Skip to content

Commit 319fc93

Browse files
committed
Add unit test setup with php_network_connect_socket test
1 parent 34edb29 commit 319fc93

File tree

2 files changed

+285
-0
lines changed

2 files changed

+285
-0
lines changed

tests/unit/Makefile

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
CC = gcc
2+
CFLAGS = -g -Wall -I../../ -I../../Zend -I../../main -I../../TSRM -I. -I..
3+
COMMON_LDFLAGS = ../../.libs/libphp.a -lcmocka -lpthread -lm -ldl -lresolv -lutil
4+
5+
TESTS = main/test_network
6+
main/test_network_SRC = main/test_network.c
7+
main/test_network_LDFLAGS = $(COMMON_LDFLAGS) -Wl,--wrap=connect,--wrap=poll,--wrap=getsockopt,--wrap=gettimeofday
8+
9+
10+
# Build all tests
11+
all: $(TESTS)
12+
13+
# Build rule for each test
14+
$(TESTS):
15+
$(CC) $(CFLAGS) -o $@.out $($(basename $@)_SRC) $($(basename $@)_LDFLAGS)
16+
17+
# Run all tests
18+
.PHONY: test
19+
test: $(TESTS)
20+
@echo "Running all tests..."
21+
@for test in $(TESTS); do \
22+
echo "Running $$test..."; \
23+
$$test.out || exit 1; \
24+
done
25+
26+
# Clean tests
27+
.PHONY: clean
28+
clean:
29+
@for test in $(TESTS); do \
30+
rm -f $$test.out; \
31+
done

tests/unit/main/test_network.c

Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
#include "php.h"
2+
#include "php_network.h"
3+
#include <cmocka.h>
4+
5+
// Mocked poll
6+
int __wrap_poll(struct pollfd *ufds, nfds_t nfds, int timeout)
7+
{
8+
function_called();
9+
check_expected(timeout);
10+
11+
int n = mock_type(int);
12+
if (n > 0) {
13+
ufds->revents = 1;
14+
} else if (n < 0) {
15+
errno = -n;
16+
n = -1;
17+
}
18+
19+
return n;
20+
}
21+
22+
// Mocked connect
23+
int __wrap_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
24+
{
25+
function_called();
26+
errno = mock_type(int);
27+
return errno != 0 ? -1 : 0;
28+
}
29+
30+
// Mocked getsockopt
31+
int __wrap_getsockopt(int fd, int level, int optname, void *optval, socklen_t *optlen)
32+
{
33+
function_called();
34+
int *error = (int *) optval;
35+
*error = mock_type(int);
36+
return mock_type(int);
37+
}
38+
39+
// Mocked gettimeofday
40+
int __wrap_gettimeofday(struct timeval *time_Info, struct timezone *timezone_Info)
41+
{
42+
function_called();
43+
struct timeval *now = mock_ptr_type(struct timeval *);
44+
if (now) {
45+
time_Info->tv_sec = now->tv_sec;
46+
time_Info->tv_usec = now->tv_usec;
47+
}
48+
return mock_type(int);
49+
}
50+
51+
// Test successful connection
52+
static void test_php_network_connect_socket_immediate_success(void **state) {
53+
struct timeval timeout = { .tv_sec = 2, .tv_usec = 500000 };
54+
php_socket_t sockfd = 12;
55+
int error_code = 0;
56+
57+
expect_function_call(__wrap_connect);
58+
will_return(__wrap_connect, 0);
59+
60+
int result = php_network_connect_socket(sockfd, NULL, 0, 0, &timeout, NULL, &error_code);
61+
62+
assert_int_equal(result, 0);
63+
assert_int_equal(error_code, 0);
64+
}
65+
66+
// Test successful connection in progress followed by poll
67+
static void test_php_network_connect_socket_progress_success(void **state) {
68+
struct timeval timeout_tv = { .tv_sec = 2, .tv_usec = 500000 };
69+
php_socket_t sockfd = 12;
70+
int error_code = 0;
71+
72+
// Mock connect setting EINPROGRESS errno
73+
expect_function_call(__wrap_connect);
74+
will_return(__wrap_connect, EINPROGRESS);
75+
76+
// Mock time setting - ignored
77+
expect_function_call(__wrap_gettimeofday);
78+
will_return(__wrap_gettimeofday, NULL);
79+
will_return(__wrap_gettimeofday, 0);
80+
81+
// Mock poll to return success
82+
expect_function_call(__wrap_poll);
83+
expect_value(__wrap_poll, timeout, 2500);
84+
will_return(__wrap_poll, 1);
85+
86+
// Mock no socket error
87+
expect_function_call(__wrap_getsockopt);
88+
will_return(__wrap_getsockopt, 0); // optval saved result
89+
will_return(__wrap_getsockopt, 0); // actual return value
90+
91+
int result = php_network_connect_socket(sockfd, NULL, 0, 0, &timeout_tv, NULL, &error_code);
92+
93+
assert_int_equal(result, 0);
94+
assert_int_equal(error_code, 0);
95+
}
96+
97+
static void test_php_network_connect_socket_eintr_t1(void **state) {
98+
struct timeval timeout_tv = { .tv_sec = 2, .tv_usec = 500000 };
99+
struct timeval start_time = { .tv_sec = 1000, .tv_usec = 0 }; // Initial time
100+
struct timeval retry_time = { .tv_sec = 1001, .tv_usec = 200000 }; // Time after EINTR
101+
php_socket_t sockfd = 12;
102+
int error_code = 0;
103+
104+
// Mock connect to set EINPROGRESS
105+
expect_function_call(__wrap_connect);
106+
will_return(__wrap_connect, EINPROGRESS);
107+
108+
// Mock gettimeofday for initial call
109+
expect_function_call(__wrap_gettimeofday);
110+
will_return(__wrap_gettimeofday, &start_time); // time to set
111+
will_return(__wrap_gettimeofday, 0); // actual return value
112+
113+
// Mock poll to return EINTR first
114+
expect_function_call(__wrap_poll);
115+
expect_value(__wrap_poll, timeout, 2500);
116+
will_return(__wrap_poll, -EINTR);
117+
118+
// Mock gettimeofday after EINTR
119+
expect_function_call(__wrap_gettimeofday);
120+
will_return(__wrap_gettimeofday, &retry_time); // time to set
121+
will_return(__wrap_gettimeofday, 0); // actual return value
122+
123+
// Mock poll to succeed on retry
124+
expect_function_call(__wrap_poll);
125+
expect_value(__wrap_poll, timeout, 1300);
126+
will_return(__wrap_poll, 1);
127+
128+
// Mock no socket error
129+
expect_function_call(__wrap_getsockopt);
130+
will_return(__wrap_getsockopt, 0); // optval saved result
131+
will_return(__wrap_getsockopt, 0); // actual return value
132+
133+
int result = php_network_connect_socket(sockfd, NULL, 0, 0, &timeout_tv, NULL, &error_code);
134+
135+
// Ensure the function succeeds
136+
assert_int_equal(result, 0);
137+
assert_int_equal(error_code, 0);
138+
}
139+
140+
static void test_php_network_connect_socket_eintr_t2(void **state) {
141+
struct timeval timeout_tv = { .tv_sec = 2, .tv_usec = 1500000 };
142+
struct timeval start_time = { .tv_sec = 1000, .tv_usec = 300000 }; // Initial time
143+
struct timeval retry_time = { .tv_sec = 1001, .tv_usec = 200000 }; // Time after EINTR
144+
php_socket_t sockfd = 12;
145+
int error_code = 0;
146+
147+
// Mock connect to set EINPROGRESS
148+
expect_function_call(__wrap_connect);
149+
will_return(__wrap_connect, EINPROGRESS);
150+
151+
// Mock gettimeofday for initial call
152+
expect_function_call(__wrap_gettimeofday);
153+
will_return(__wrap_gettimeofday, &start_time);
154+
will_return(__wrap_gettimeofday, 0); // Return 0 (success)
155+
156+
// Mock poll to return EINTR first
157+
expect_function_call(__wrap_poll);
158+
expect_value(__wrap_poll, timeout, 3500);
159+
will_return(__wrap_poll, -EINTR);
160+
161+
// Mock gettimeofday after EINTR
162+
expect_function_call(__wrap_gettimeofday);
163+
will_return(__wrap_gettimeofday, &retry_time);
164+
will_return(__wrap_gettimeofday, 0); // Return 0 (success)
165+
166+
// Mock poll to succeed on retry
167+
expect_function_call(__wrap_poll);
168+
expect_value(__wrap_poll, timeout, 2600);
169+
will_return(__wrap_poll, 1);
170+
171+
// Mock no socket error
172+
expect_function_call(__wrap_getsockopt);
173+
will_return(__wrap_getsockopt, 0); // optval saved result
174+
will_return(__wrap_getsockopt, 0); // actual return value
175+
176+
int result = php_network_connect_socket(sockfd, NULL, 0, 0, &timeout_tv, NULL, &error_code);
177+
178+
// Ensure the function succeeds
179+
assert_int_equal(result, 0);
180+
assert_int_equal(error_code, 0);
181+
}
182+
183+
static void test_php_network_connect_socket_eintr_t3(void **state) {
184+
struct timeval timeout_tv = { .tv_sec = 2, .tv_usec = 500000 };
185+
struct timeval start_time = { .tv_sec = 1002, .tv_usec = 300000 }; // Initial time
186+
struct timeval retry_time = { .tv_sec = 1001, .tv_usec = 2200000 }; // Time after EINTR
187+
php_socket_t sockfd = 12;
188+
int error_code = 0;
189+
190+
// Mock connect to set EINPROGRESS
191+
expect_function_call(__wrap_connect);
192+
will_return(__wrap_connect, EINPROGRESS);
193+
194+
// Mock gettimeofday for initial call
195+
expect_function_call(__wrap_gettimeofday);
196+
will_return(__wrap_gettimeofday, &start_time);
197+
will_return(__wrap_gettimeofday, 0); // Return 0 (success)
198+
199+
// Mock poll to return EINTR first
200+
expect_function_call(__wrap_poll);
201+
expect_value(__wrap_poll, timeout, 2500);
202+
will_return(__wrap_poll, -EINTR);
203+
204+
// Mock gettimeofday after EINTR
205+
expect_function_call(__wrap_gettimeofday);
206+
will_return(__wrap_gettimeofday, &retry_time);
207+
will_return(__wrap_gettimeofday, 0); // Return 0 (success)
208+
209+
// Mock poll to succeed on retry
210+
expect_function_call(__wrap_poll);
211+
expect_value(__wrap_poll, timeout, 1600);
212+
will_return(__wrap_poll, 1);
213+
214+
// Mock no socket error
215+
expect_function_call(__wrap_getsockopt);
216+
will_return(__wrap_getsockopt, 0); // optval saved result
217+
will_return(__wrap_getsockopt, 0); // actual return value
218+
219+
int result = php_network_connect_socket(sockfd, NULL, 0, 0, &timeout_tv, NULL, &error_code);
220+
221+
// Ensure the function succeeds
222+
assert_int_equal(result, 0);
223+
assert_int_equal(error_code, 0);
224+
}
225+
226+
// Test connection error (ECONNREFUSED)
227+
static void test_php_network_connect_socket_connect_error(void **state) {
228+
struct timeval timeout = { .tv_sec = 2, .tv_usec = 500000 };
229+
php_socket_t sockfd = 12;
230+
int error_code = 0;
231+
232+
// Mock connect to set ECONNREFUSED
233+
expect_function_call(__wrap_connect);
234+
will_return(__wrap_connect, ECONNREFUSED);
235+
236+
int result = php_network_connect_socket(sockfd, NULL, 0, 0, &timeout, NULL, &error_code);
237+
238+
// Ensure the function returns an error
239+
assert_int_equal(result, -1);
240+
assert_int_equal(error_code, ECONNREFUSED);
241+
}
242+
243+
244+
int main(void) {
245+
const struct CMUnitTest tests[] = {
246+
cmocka_unit_test(test_php_network_connect_socket_immediate_success),
247+
cmocka_unit_test(test_php_network_connect_socket_progress_success),
248+
cmocka_unit_test(test_php_network_connect_socket_eintr_t1),
249+
cmocka_unit_test(test_php_network_connect_socket_eintr_t2),
250+
cmocka_unit_test(test_php_network_connect_socket_eintr_t3),
251+
cmocka_unit_test(test_php_network_connect_socket_connect_error),
252+
};
253+
return cmocka_run_group_tests(tests, NULL, NULL);
254+
}

0 commit comments

Comments
 (0)