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