|
1 | | -#include <assert.h> |
2 | 1 | #include <sys/socket.h> |
3 | 2 | #include <unistd.h> |
| 3 | + |
| 4 | +#include "test_harness.h" |
4 | 5 | #include "../../src/dns_poller.c" |
5 | | -int main(void) { |
6 | | - dns_poller_t d = {0}; |
7 | | - struct ev_loop *loop = ev_loop_new(0); |
8 | | - assert(loop); |
9 | | - dns_poller_init(&d, loop, "127.0.0.1,127.0.0.2", 60, NULL, |
| 6 | + |
| 7 | +enum { |
| 8 | + TEST_SOCKET_COUNT = 40, |
| 9 | + TEST_FD_CAPACITY = 48 |
| 10 | +}; |
| 11 | + |
| 12 | +static dns_poller_t poller; |
| 13 | +static struct ev_loop *loop; |
| 14 | +static int poller_initialized; |
| 15 | +static int tracked_fds[TEST_FD_CAPACITY]; |
| 16 | +static unsigned tracked_fd_count; |
| 17 | + |
| 18 | +static void setUp(void) { |
| 19 | + poller_initialized = 0; |
| 20 | + tracked_fd_count = 0; |
| 21 | + loop = NULL; |
| 22 | + memset(&poller, 0, sizeof(poller)); |
| 23 | + loop = ev_loop_new(0); |
| 24 | + if (!loop) { |
| 25 | + test_fail(__FILE__, __LINE__, "ev_loop_new(0)"); |
| 26 | + return; |
| 27 | + } |
| 28 | + dns_poller_init(&poller, loop, "127.0.0.1,127.0.0.2", 60, NULL, |
10 | 29 | "example.com", AF_INET, NULL, NULL); |
11 | | - ev_timer_stop(loop, &d.timer); |
12 | | - int fds[40]; |
13 | | - ev_io *first = NULL; |
14 | | - for (int i = 0; i < 40; i++) { |
15 | | - fds[i] = socket(AF_INET, SOCK_DGRAM, 0); |
16 | | - assert(fds[i] >= 0); |
17 | | - sock_state_cb(&d, fds[i], 1, 0); |
18 | | - assert(get_io_event(&d, fds[i])); |
19 | | - if (!i) first = get_io_event(&d, fds[i]); |
20 | | - assert(get_io_event(&d, fds[0]) == first); |
| 30 | + poller_initialized = 1; |
| 31 | + ev_timer_stop(loop, &poller.timer); |
| 32 | +} |
| 33 | + |
| 34 | +static void tearDown(void) { |
| 35 | + if (poller_initialized) { |
| 36 | + dns_poller_cleanup(&poller); |
| 37 | + poller_initialized = 0; |
| 38 | + } |
| 39 | + for (unsigned i = 0; i < tracked_fd_count; i++) { |
| 40 | + close(tracked_fds[i]); |
21 | 41 | } |
22 | | - ev_io *reused = get_io_event(&d, fds[10]); |
23 | | - sock_state_cb(&d, fds[10], 0, 0); |
24 | | - assert(!get_io_event(&d, fds[10])); |
25 | | - sock_state_cb(&d, fds[10], 1, 1); |
26 | | - assert(get_io_event(&d, fds[10]) == reused); |
27 | | - for (int i = 0; i < 40; i++) { |
28 | | - sock_state_cb(&d, fds[i], 0, 0); |
29 | | - close(fds[i]); |
| 42 | + if (loop) { |
| 43 | + ev_loop_destroy(loop); |
| 44 | + loop = NULL; |
30 | 45 | } |
31 | | - // Also exercise cleanup with a registered watcher still active. |
32 | | - int remaining = socket(AF_INET, SOCK_DGRAM, 0); |
33 | | - assert(remaining >= 0); |
34 | | - sock_state_cb(&d, remaining, 1, 0); |
35 | | - dns_poller_cleanup(&d); |
36 | | - close(remaining); |
37 | | - ev_run(loop, EVRUN_NOWAIT); |
38 | | - ev_loop_destroy(loop); |
39 | | - puts("PASS: 40 sockets / 2 servers; stable addresses; update/reuse/cleanup"); |
40 | | - return 0; |
| 46 | +} |
| 47 | + |
| 48 | +static int open_test_socket(void) { |
| 49 | + int fd = socket(AF_INET, SOCK_DGRAM, 0); |
| 50 | + if (fd < 0) { |
| 51 | + return fd; |
| 52 | + } |
| 53 | + if (tracked_fd_count >= TEST_FD_CAPACITY) { |
| 54 | + close(fd); |
| 55 | + return -1; |
| 56 | + } |
| 57 | + tracked_fds[tracked_fd_count++] = fd; |
| 58 | + return fd; |
| 59 | +} |
| 60 | + |
| 61 | +static int watcher_matches(ev_io *watcher, int fd, int events) { |
| 62 | + return watcher && ev_is_active(watcher) && !ev_is_pending(watcher) && |
| 63 | + watcher->fd == fd && watcher->events == events && |
| 64 | + watcher->data == &poller; |
| 65 | +} |
| 66 | + |
| 67 | +static void test_allocates_watchers_beyond_nameserver_count(void) { |
| 68 | + ev_io *first = NULL; |
| 69 | + int first_fd = ARES_SOCKET_BAD; |
| 70 | + |
| 71 | + for (int i = 0; i < TEST_SOCKET_COUNT; i++) { |
| 72 | + int fd = open_test_socket(); |
| 73 | + TEST_ASSERT(fd >= 0); |
| 74 | + sock_state_cb(&poller, fd, 1, 0); |
| 75 | + TEST_ASSERT(watcher_matches(get_io_event(&poller, fd), fd, EV_READ)); |
| 76 | + if (i == 0) { |
| 77 | + first = get_io_event(&poller, fd); |
| 78 | + first_fd = fd; |
| 79 | + } |
| 80 | + TEST_ASSERT_EQUAL_PTR(first, get_io_event(&poller, first_fd)); |
| 81 | + } |
| 82 | +} |
| 83 | + |
| 84 | +static void test_reuses_released_watcher(void) { |
| 85 | + int fd = open_test_socket(); |
| 86 | + TEST_ASSERT(fd >= 0); |
| 87 | + sock_state_cb(&poller, fd, 1, 0); |
| 88 | + ev_io *watcher = get_io_event(&poller, fd); |
| 89 | + TEST_ASSERT(watcher_matches(watcher, fd, EV_READ)); |
| 90 | + |
| 91 | + sock_state_cb(&poller, fd, 0, 0); |
| 92 | + TEST_ASSERT(!get_io_event(&poller, fd)); |
| 93 | + TEST_ASSERT(!ev_is_active(watcher)); |
| 94 | + TEST_ASSERT(!ev_is_pending(watcher)); |
| 95 | + TEST_ASSERT(watcher->fd == ARES_SOCKET_BAD); |
| 96 | + sock_state_cb(&poller, fd, 1, 1); |
| 97 | + TEST_ASSERT_EQUAL_PTR(watcher, get_io_event(&poller, fd)); |
| 98 | + TEST_ASSERT(watcher_matches(watcher, fd, EV_READ | EV_WRITE)); |
| 99 | +} |
| 100 | + |
| 101 | +static void test_fd_zero_does_not_alias_free_watcher(void) { |
| 102 | + sock_state_cb(&poller, 0, 1, 0); |
| 103 | + ev_io *fd_zero_watcher = get_io_event(&poller, 0); |
| 104 | + TEST_ASSERT(watcher_matches(fd_zero_watcher, 0, EV_READ)); |
| 105 | + |
| 106 | + int fd = open_test_socket(); |
| 107 | + TEST_ASSERT(fd > 0); |
| 108 | + sock_state_cb(&poller, fd, 1, 0); |
| 109 | + TEST_ASSERT(watcher_matches(get_io_event(&poller, fd), fd, EV_READ)); |
| 110 | + TEST_ASSERT_EQUAL_PTR(fd_zero_watcher, get_io_event(&poller, 0)); |
| 111 | + TEST_ASSERT(get_io_event(&poller, fd) != fd_zero_watcher); |
| 112 | +} |
| 113 | + |
| 114 | +static void test_cleanup_stops_active_watchers(void) { |
| 115 | + int fd = open_test_socket(); |
| 116 | + TEST_ASSERT(fd >= 0); |
| 117 | + sock_state_cb(&poller, fd, 1, 0); |
| 118 | + ev_io *watcher = get_io_event(&poller, fd); |
| 119 | + TEST_ASSERT(watcher_matches(watcher, fd, EV_READ)); |
| 120 | + ev_feed_event(loop, watcher, EV_READ); |
| 121 | + TEST_ASSERT(ev_is_pending(watcher)); |
| 122 | + |
| 123 | + dns_poller_cleanup(&poller); |
| 124 | + poller_initialized = 0; |
| 125 | + TEST_ASSERT(!poller.io_events); |
| 126 | + TEST_ASSERT(ev_run(loop, EVRUN_NOWAIT) == 0); |
| 127 | +} |
| 128 | + |
| 129 | +int main(void) { |
| 130 | + TEST_RUN(test_allocates_watchers_beyond_nameserver_count); |
| 131 | + TEST_RUN(test_reuses_released_watcher); |
| 132 | + TEST_RUN(test_fd_zero_does_not_alias_free_watcher); |
| 133 | + TEST_RUN(test_cleanup_stops_active_watchers); |
| 134 | + return test_summary(); |
41 | 135 | } |
0 commit comments