Skip to content

Commit 8949f1a

Browse files
committed
Do not inline current time retrieval to be mockable
1 parent 561ecba commit 8949f1a

File tree

4 files changed

+30
-72
lines changed

4 files changed

+30
-72
lines changed

Zend/zend_time.h

Lines changed: 5 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -80,46 +80,15 @@ static zend_always_inline void zend_time_val2spec(struct timeval tv, struct time
8080
ts->tv_nsec = (long) (tv.tv_usec * 1000);
8181
}
8282

83-
/* Get current timestamp in seconds */
84-
static zend_always_inline time_t zend_time_real_get(void) {
85-
return time(NULL);
86-
}
87-
88-
/* wrapper around clock_gettime/timestamp_get/gettimeofday/time */
89-
static zend_always_inline void zend_time_real_spec(struct timespec *ts) {
90-
#if defined(HAVE_CLOCK_GETTIME)
91-
92-
(void) clock_gettime(CLOCK_REALTIME, ts);
93-
94-
#elif defined(HAVE_TIMESPEC_GET)
95-
96-
(void) timespec_get(ts, TIME_UTC);
97-
98-
#elif defined(HAVE_GETTIMEOFDAY)
83+
/* Current real/wall-time in seconds */
84+
ZEND_API time_t zend_time_real_get(void);
9985

100-
struct timeval tv;
101-
(void) gettimeofday(&tv, NULL);
102-
zend_time_val2spec(tv, ts);
103-
104-
#else
105-
106-
ts->tv_sec = zend_time_real_get();
107-
ts->tv_nsec = 0;
108-
109-
#endif
110-
}
86+
/* Current real/wall-time in up-to nano seconds */
87+
ZEND_API void zend_time_real_spec(struct timespec *ts);
11188

11289
/* Monotonic time in nanoseconds with a fallback to real/wall-time
11390
if no monotonic timer is available */
114-
static zend_always_inline uint64_t zend_time_mono_fallback(void) {
115-
#if ZEND_HRTIME_AVAILABLE
116-
return (uint64_t)zend_hrtime();
117-
#else
118-
struct timespec ts;
119-
zend_time_real_spec(&ts);
120-
return ((uint64_t) ts.tv_sec * ZEND_NANO_IN_SEC) + ts.tv_nsec;
121-
#endif
122-
}
91+
ZEND_API uint64_t zend_time_mono_fallback(void);
12392

12493
END_EXTERN_C()
12594

configure.ac

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1761,6 +1761,7 @@ PHP_ADD_SOURCES([Zend], m4_normalize([
17611761
zend_generators.c
17621762
zend_hash.c
17631763
zend_highlight.c
1764+
zend_time.c
17641765
zend_hrtime.c
17651766
zend_inheritance.c
17661767
zend_ini_parser.c

tests/unit/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ COMMON_LDFLAGS = ../../.libs/libphp.a -lcmocka -lpthread -lm -ldl -lresolv -luti
55
# Update paths in .github/workflows/unit-tests.yml when adding new test to make it run in PR when such file changes
66
TESTS = main/test_network
77
main/test_network_SRC = main/test_network.c
8-
main/test_network_LDFLAGS = $(COMMON_LDFLAGS) -Wl,--wrap=connect,--wrap=poll,--wrap=getsockopt,--wrap=gettimeofday
8+
main/test_network_LDFLAGS = $(COMMON_LDFLAGS) -Wl,--wrap=connect,--wrap=poll,--wrap=getsockopt,--wrap=zend_time_mono_fallback
99

1010

1111
# Build all tests

tests/unit/main/test_network.c

Lines changed: 23 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,11 @@ int __wrap_getsockopt(int fd, int level, int optname, void *optval, socklen_t *o
3636
return mock_type(int);
3737
}
3838

39-
// Mocked gettimeofday
40-
int __wrap_gettimeofday(struct timeval *time_Info, struct timezone *timezone_Info)
39+
// Mocked zend_time_mono_fallback
40+
uint64_t __wrap_zend_time_mono_fallback(void)
4141
{
4242
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);
43+
return mock_type(uint64_t);
4944
}
5045

5146
// Test successful connection
@@ -74,9 +69,8 @@ static void test_php_network_connect_socket_progress_success(void **state) {
7469
will_return(__wrap_connect, EINPROGRESS);
7570

7671
// Mock time setting - ignored
77-
expect_function_call(__wrap_gettimeofday);
78-
will_return(__wrap_gettimeofday, NULL);
79-
will_return(__wrap_gettimeofday, 0);
72+
expect_function_call(__wrap_zend_time_mono_fallback);
73+
will_return(__wrap_zend_time_mono_fallback, 0);
8074

8175
// Mock poll to return success
8276
expect_function_call(__wrap_poll);
@@ -96,8 +90,8 @@ static void test_php_network_connect_socket_progress_success(void **state) {
9690

9791
static void test_php_network_connect_socket_eintr_t1(void **state) {
9892
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
93+
uint64_t start_time = 1000000000000; // Initial time
94+
uint64_t retry_time = 1001200000000; // Time after EINTR
10195
php_socket_t sockfd = 12;
10296
int error_code = 0;
10397

@@ -106,19 +100,17 @@ static void test_php_network_connect_socket_eintr_t1(void **state) {
106100
will_return(__wrap_connect, EINPROGRESS);
107101

108102
// Mock gettimeofday for initial call
109-
expect_function_call(__wrap_gettimeofday);
110-
will_return(__wrap_gettimeofday, &start_time);
111-
will_return(__wrap_gettimeofday, 0);
103+
expect_function_call(__wrap_zend_time_mono_fallback);
104+
will_return(__wrap_zend_time_mono_fallback, start_time);
112105

113106
// Mock poll to return EINTR first
114107
expect_function_call(__wrap_poll);
115108
expect_value(__wrap_poll, timeout, 2500);
116109
will_return(__wrap_poll, -EINTR);
117110

118111
// Mock gettimeofday after EINTR
119-
expect_function_call(__wrap_gettimeofday);
120-
will_return(__wrap_gettimeofday, &retry_time);
121-
will_return(__wrap_gettimeofday, 0);
112+
expect_function_call(__wrap_zend_time_mono_fallback);
113+
will_return(__wrap_zend_time_mono_fallback, retry_time);
122114

123115
// Mock poll to succeed on retry
124116
expect_function_call(__wrap_poll);
@@ -139,8 +131,8 @@ static void test_php_network_connect_socket_eintr_t1(void **state) {
139131

140132
static void test_php_network_connect_socket_eintr_t2(void **state) {
141133
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
134+
uint64_t start_time = 1000300000000; // Initial time
135+
uint64_t retry_time = 1001200000000; // Time after EINTR
144136
php_socket_t sockfd = 12;
145137
int error_code = 0;
146138

@@ -149,19 +141,17 @@ static void test_php_network_connect_socket_eintr_t2(void **state) {
149141
will_return(__wrap_connect, EINPROGRESS);
150142

151143
// Mock gettimeofday for initial call
152-
expect_function_call(__wrap_gettimeofday);
153-
will_return(__wrap_gettimeofday, &start_time);
154-
will_return(__wrap_gettimeofday, 0);
144+
expect_function_call(__wrap_zend_time_mono_fallback);
145+
will_return(__wrap_zend_time_mono_fallback, start_time);
155146

156147
// Mock poll to return EINTR first
157148
expect_function_call(__wrap_poll);
158149
expect_value(__wrap_poll, timeout, 3500);
159150
will_return(__wrap_poll, -EINTR);
160151

161152
// Mock gettimeofday after EINTR
162-
expect_function_call(__wrap_gettimeofday);
163-
will_return(__wrap_gettimeofday, &retry_time);
164-
will_return(__wrap_gettimeofday, 0);
153+
expect_function_call(__wrap_zend_time_mono_fallback);
154+
will_return(__wrap_zend_time_mono_fallback, retry_time);
165155

166156
// Mock poll to succeed on retry
167157
expect_function_call(__wrap_poll);
@@ -182,8 +172,8 @@ static void test_php_network_connect_socket_eintr_t2(void **state) {
182172

183173
static void test_php_network_connect_socket_eintr_t3(void **state) {
184174
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
175+
uint64_t start_time = 1002300000000; // Initial time
176+
uint64_t retry_time = 1003200000000; // Time after EINTR
187177
php_socket_t sockfd = 12;
188178
int error_code = 0;
189179

@@ -192,19 +182,17 @@ static void test_php_network_connect_socket_eintr_t3(void **state) {
192182
will_return(__wrap_connect, EINPROGRESS);
193183

194184
// Mock gettimeofday for initial call
195-
expect_function_call(__wrap_gettimeofday);
196-
will_return(__wrap_gettimeofday, &start_time);
197-
will_return(__wrap_gettimeofday, 0);
185+
expect_function_call(__wrap_zend_time_mono_fallback);
186+
will_return(__wrap_zend_time_mono_fallback, start_time);
198187

199188
// Mock poll to return EINTR first
200189
expect_function_call(__wrap_poll);
201190
expect_value(__wrap_poll, timeout, 2500);
202191
will_return(__wrap_poll, -EINTR);
203192

204193
// Mock gettimeofday after EINTR
205-
expect_function_call(__wrap_gettimeofday);
206-
will_return(__wrap_gettimeofday, &retry_time);
207-
will_return(__wrap_gettimeofday, 0);
194+
expect_function_call(__wrap_zend_time_mono_fallback);
195+
will_return(__wrap_zend_time_mono_fallback, retry_time);
208196

209197
// Mock poll to succeed on retry
210198
expect_function_call(__wrap_poll);

0 commit comments

Comments
 (0)