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 );
111+ will_return (__wrap_gettimeofday , 0 );
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 );
121+ will_return (__wrap_gettimeofday , 0 );
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 );
131+ will_return (__wrap_getsockopt , 0 );
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 );
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 );
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 );
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 );
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