mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
Add unit test setup with php_network_connect_socket test
This commit is contained in:
31
tests/unit/Makefile
Normal file
31
tests/unit/Makefile
Normal file
@@ -0,0 +1,31 @@
|
||||
CC = gcc
|
||||
CFLAGS = -g -Wall -I../../ -I../../Zend -I../../main -I../../TSRM -I. -I..
|
||||
COMMON_LDFLAGS = ../../.libs/libphp.a -lcmocka -lpthread -lm -ldl -lresolv -lutil
|
||||
|
||||
TESTS = main/test_network
|
||||
main/test_network_SRC = main/test_network.c
|
||||
main/test_network_LDFLAGS = $(COMMON_LDFLAGS) -Wl,--wrap=connect,--wrap=poll,--wrap=getsockopt,--wrap=gettimeofday
|
||||
|
||||
|
||||
# Build all tests
|
||||
all: $(TESTS)
|
||||
|
||||
# Build rule for each test
|
||||
$(TESTS):
|
||||
$(CC) $(CFLAGS) -o $@.out $($(basename $@)_SRC) $($(basename $@)_LDFLAGS)
|
||||
|
||||
# Run all tests
|
||||
.PHONY: test
|
||||
test: $(TESTS)
|
||||
@echo "Running all tests..."
|
||||
@for test in $(TESTS); do \
|
||||
echo "Running $$test..."; \
|
||||
$$test.out || exit 1; \
|
||||
done
|
||||
|
||||
# Clean tests
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@for test in $(TESTS); do \
|
||||
rm -f $$test.out; \
|
||||
done
|
||||
254
tests/unit/main/test_network.c
Normal file
254
tests/unit/main/test_network.c
Normal file
@@ -0,0 +1,254 @@
|
||||
#include "php.h"
|
||||
#include "php_network.h"
|
||||
#include <cmocka.h>
|
||||
|
||||
// Mocked poll
|
||||
int __wrap_poll(struct pollfd *ufds, nfds_t nfds, int timeout)
|
||||
{
|
||||
function_called();
|
||||
check_expected(timeout);
|
||||
|
||||
int n = mock_type(int);
|
||||
if (n > 0) {
|
||||
ufds->revents = 1;
|
||||
} else if (n < 0) {
|
||||
errno = -n;
|
||||
n = -1;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
// Mocked connect
|
||||
int __wrap_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
|
||||
{
|
||||
function_called();
|
||||
errno = mock_type(int);
|
||||
return errno != 0 ? -1 : 0;
|
||||
}
|
||||
|
||||
// Mocked getsockopt
|
||||
int __wrap_getsockopt(int fd, int level, int optname, void *optval, socklen_t *optlen)
|
||||
{
|
||||
function_called();
|
||||
int *error = (int *) optval;
|
||||
*error = mock_type(int);
|
||||
return mock_type(int);
|
||||
}
|
||||
|
||||
// Mocked gettimeofday
|
||||
int __wrap_gettimeofday(struct timeval *time_Info, struct timezone *timezone_Info)
|
||||
{
|
||||
function_called();
|
||||
struct timeval *now = mock_ptr_type(struct timeval *);
|
||||
if (now) {
|
||||
time_Info->tv_sec = now->tv_sec;
|
||||
time_Info->tv_usec = now->tv_usec;
|
||||
}
|
||||
return mock_type(int);
|
||||
}
|
||||
|
||||
// Test successful connection
|
||||
static void test_php_network_connect_socket_immediate_success(void **state) {
|
||||
struct timeval timeout = { .tv_sec = 2, .tv_usec = 500000 };
|
||||
php_socket_t sockfd = 12;
|
||||
int error_code = 0;
|
||||
|
||||
expect_function_call(__wrap_connect);
|
||||
will_return(__wrap_connect, 0);
|
||||
|
||||
int result = php_network_connect_socket(sockfd, NULL, 0, 0, &timeout, NULL, &error_code);
|
||||
|
||||
assert_int_equal(result, 0);
|
||||
assert_int_equal(error_code, 0);
|
||||
}
|
||||
|
||||
// Test successful connection in progress followed by poll
|
||||
static void test_php_network_connect_socket_progress_success(void **state) {
|
||||
struct timeval timeout_tv = { .tv_sec = 2, .tv_usec = 500000 };
|
||||
php_socket_t sockfd = 12;
|
||||
int error_code = 0;
|
||||
|
||||
// Mock connect setting EINPROGRESS errno
|
||||
expect_function_call(__wrap_connect);
|
||||
will_return(__wrap_connect, EINPROGRESS);
|
||||
|
||||
// Mock time setting - ignored
|
||||
expect_function_call(__wrap_gettimeofday);
|
||||
will_return(__wrap_gettimeofday, NULL);
|
||||
will_return(__wrap_gettimeofday, 0);
|
||||
|
||||
// Mock poll to return success
|
||||
expect_function_call(__wrap_poll);
|
||||
expect_value(__wrap_poll, timeout, 2500);
|
||||
will_return(__wrap_poll, 1);
|
||||
|
||||
// Mock no socket error
|
||||
expect_function_call(__wrap_getsockopt);
|
||||
will_return(__wrap_getsockopt, 0); // optval saved result
|
||||
will_return(__wrap_getsockopt, 0); // actual return value
|
||||
|
||||
int result = php_network_connect_socket(sockfd, NULL, 0, 0, &timeout_tv, NULL, &error_code);
|
||||
|
||||
assert_int_equal(result, 0);
|
||||
assert_int_equal(error_code, 0);
|
||||
}
|
||||
|
||||
static void test_php_network_connect_socket_eintr_t1(void **state) {
|
||||
struct timeval timeout_tv = { .tv_sec = 2, .tv_usec = 500000 };
|
||||
struct timeval start_time = { .tv_sec = 1000, .tv_usec = 0 }; // Initial time
|
||||
struct timeval retry_time = { .tv_sec = 1001, .tv_usec = 200000 }; // Time after EINTR
|
||||
php_socket_t sockfd = 12;
|
||||
int error_code = 0;
|
||||
|
||||
// Mock connect to set EINPROGRESS
|
||||
expect_function_call(__wrap_connect);
|
||||
will_return(__wrap_connect, EINPROGRESS);
|
||||
|
||||
// Mock gettimeofday for initial call
|
||||
expect_function_call(__wrap_gettimeofday);
|
||||
will_return(__wrap_gettimeofday, &start_time);
|
||||
will_return(__wrap_gettimeofday, 0);
|
||||
|
||||
// Mock poll to return EINTR first
|
||||
expect_function_call(__wrap_poll);
|
||||
expect_value(__wrap_poll, timeout, 2500);
|
||||
will_return(__wrap_poll, -EINTR);
|
||||
|
||||
// Mock gettimeofday after EINTR
|
||||
expect_function_call(__wrap_gettimeofday);
|
||||
will_return(__wrap_gettimeofday, &retry_time);
|
||||
will_return(__wrap_gettimeofday, 0);
|
||||
|
||||
// Mock poll to succeed on retry
|
||||
expect_function_call(__wrap_poll);
|
||||
expect_value(__wrap_poll, timeout, 1300);
|
||||
will_return(__wrap_poll, 1);
|
||||
|
||||
// Mock no socket error
|
||||
expect_function_call(__wrap_getsockopt);
|
||||
will_return(__wrap_getsockopt, 0);
|
||||
will_return(__wrap_getsockopt, 0);
|
||||
|
||||
int result = php_network_connect_socket(sockfd, NULL, 0, 0, &timeout_tv, NULL, &error_code);
|
||||
|
||||
// Ensure the function succeeds
|
||||
assert_int_equal(result, 0);
|
||||
assert_int_equal(error_code, 0);
|
||||
}
|
||||
|
||||
static void test_php_network_connect_socket_eintr_t2(void **state) {
|
||||
struct timeval timeout_tv = { .tv_sec = 2, .tv_usec = 1500000 };
|
||||
struct timeval start_time = { .tv_sec = 1000, .tv_usec = 300000 }; // Initial time
|
||||
struct timeval retry_time = { .tv_sec = 1001, .tv_usec = 200000 }; // Time after EINTR
|
||||
php_socket_t sockfd = 12;
|
||||
int error_code = 0;
|
||||
|
||||
// Mock connect to set EINPROGRESS
|
||||
expect_function_call(__wrap_connect);
|
||||
will_return(__wrap_connect, EINPROGRESS);
|
||||
|
||||
// Mock gettimeofday for initial call
|
||||
expect_function_call(__wrap_gettimeofday);
|
||||
will_return(__wrap_gettimeofday, &start_time);
|
||||
will_return(__wrap_gettimeofday, 0);
|
||||
|
||||
// Mock poll to return EINTR first
|
||||
expect_function_call(__wrap_poll);
|
||||
expect_value(__wrap_poll, timeout, 3500);
|
||||
will_return(__wrap_poll, -EINTR);
|
||||
|
||||
// Mock gettimeofday after EINTR
|
||||
expect_function_call(__wrap_gettimeofday);
|
||||
will_return(__wrap_gettimeofday, &retry_time);
|
||||
will_return(__wrap_gettimeofday, 0);
|
||||
|
||||
// Mock poll to succeed on retry
|
||||
expect_function_call(__wrap_poll);
|
||||
expect_value(__wrap_poll, timeout, 2600);
|
||||
will_return(__wrap_poll, 1);
|
||||
|
||||
// Mock no socket error
|
||||
expect_function_call(__wrap_getsockopt);
|
||||
will_return(__wrap_getsockopt, 0); // optval saved result
|
||||
will_return(__wrap_getsockopt, 0); // actual return value
|
||||
|
||||
int result = php_network_connect_socket(sockfd, NULL, 0, 0, &timeout_tv, NULL, &error_code);
|
||||
|
||||
// Ensure the function succeeds
|
||||
assert_int_equal(result, 0);
|
||||
assert_int_equal(error_code, 0);
|
||||
}
|
||||
|
||||
static void test_php_network_connect_socket_eintr_t3(void **state) {
|
||||
struct timeval timeout_tv = { .tv_sec = 2, .tv_usec = 500000 };
|
||||
struct timeval start_time = { .tv_sec = 1002, .tv_usec = 300000 }; // Initial time
|
||||
struct timeval retry_time = { .tv_sec = 1001, .tv_usec = 2200000 }; // Time after EINTR
|
||||
php_socket_t sockfd = 12;
|
||||
int error_code = 0;
|
||||
|
||||
// Mock connect to set EINPROGRESS
|
||||
expect_function_call(__wrap_connect);
|
||||
will_return(__wrap_connect, EINPROGRESS);
|
||||
|
||||
// Mock gettimeofday for initial call
|
||||
expect_function_call(__wrap_gettimeofday);
|
||||
will_return(__wrap_gettimeofday, &start_time);
|
||||
will_return(__wrap_gettimeofday, 0);
|
||||
|
||||
// Mock poll to return EINTR first
|
||||
expect_function_call(__wrap_poll);
|
||||
expect_value(__wrap_poll, timeout, 2500);
|
||||
will_return(__wrap_poll, -EINTR);
|
||||
|
||||
// Mock gettimeofday after EINTR
|
||||
expect_function_call(__wrap_gettimeofday);
|
||||
will_return(__wrap_gettimeofday, &retry_time);
|
||||
will_return(__wrap_gettimeofday, 0);
|
||||
|
||||
// Mock poll to succeed on retry
|
||||
expect_function_call(__wrap_poll);
|
||||
expect_value(__wrap_poll, timeout, 1600);
|
||||
will_return(__wrap_poll, 1);
|
||||
|
||||
// Mock no socket error
|
||||
expect_function_call(__wrap_getsockopt);
|
||||
will_return(__wrap_getsockopt, 0); // optval saved result
|
||||
will_return(__wrap_getsockopt, 0); // actual return value
|
||||
|
||||
int result = php_network_connect_socket(sockfd, NULL, 0, 0, &timeout_tv, NULL, &error_code);
|
||||
|
||||
// Ensure the function succeeds
|
||||
assert_int_equal(result, 0);
|
||||
assert_int_equal(error_code, 0);
|
||||
}
|
||||
|
||||
// Test connection error (ECONNREFUSED)
|
||||
static void test_php_network_connect_socket_connect_error(void **state) {
|
||||
struct timeval timeout = { .tv_sec = 2, .tv_usec = 500000 };
|
||||
php_socket_t sockfd = 12;
|
||||
int error_code = 0;
|
||||
|
||||
// Mock connect to set ECONNREFUSED
|
||||
expect_function_call(__wrap_connect);
|
||||
will_return(__wrap_connect, ECONNREFUSED);
|
||||
|
||||
int result = php_network_connect_socket(sockfd, NULL, 0, 0, &timeout, NULL, &error_code);
|
||||
|
||||
// Ensure the function returns an error
|
||||
assert_int_equal(result, -1);
|
||||
assert_int_equal(error_code, ECONNREFUSED);
|
||||
}
|
||||
|
||||
|
||||
int main(void) {
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test(test_php_network_connect_socket_immediate_success),
|
||||
cmocka_unit_test(test_php_network_connect_socket_progress_success),
|
||||
cmocka_unit_test(test_php_network_connect_socket_eintr_t1),
|
||||
cmocka_unit_test(test_php_network_connect_socket_eintr_t2),
|
||||
cmocka_unit_test(test_php_network_connect_socket_eintr_t3),
|
||||
cmocka_unit_test(test_php_network_connect_socket_connect_error),
|
||||
};
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
||||
Reference in New Issue
Block a user