From 45ad63d265261203155c882ec93b80a604e9ab3b Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sat, 7 Dec 2024 15:45:15 -0800 Subject: [PATCH] nuts: try to avoid address in use for most tests We get test failures somewhat frequently due to port conflicts. This attempts to make more of the tests use the trick of binding to port 0, and letting us use the random port instead. --- src/testing/marry.c | 56 ++++++++++++++++++++++ src/testing/nuts.h | 12 +++++ src/testing/util.c | 112 ++++++++++++++++++++++++-------------------- 3 files changed, 130 insertions(+), 50 deletions(-) diff --git a/src/testing/marry.c b/src/testing/marry.c index 8cc944733..36b879c7b 100644 --- a/src/testing/marry.c +++ b/src/testing/marry.c @@ -92,6 +92,62 @@ nuts_scratch_addr(const char *scheme, size_t sz, char *addr) abort(); } +void +nuts_scratch_addr_zero(const char *scheme, size_t sz, char *addr) +{ + if ((strcmp(scheme, "inproc") == 0) || + (strcmp(scheme, "abstract") == 0)) { + (void) snprintf(addr, sz, "%s://nuts%04x%04x%04x%04x", scheme, + nng_random(), nng_random(), nng_random(), nng_random()); + return; + } + + if ((strncmp(scheme, "tcp", 3) == 0) || + (strncmp(scheme, "tls", 3) == 0) || + (strncmp(scheme, "udp", 3) == 0)) { + const char *ip = + strchr(scheme, '6') != NULL ? "[::1]" : "127.0.0.1"; + (void) snprintf(addr, sz, "%s://%s:%u", scheme, ip, 0); + return; + } + + if (strncmp(scheme, "ws", 2) == 0) { + const char *ip = + strchr(scheme, '6') != NULL ? "[::1]" : "127.0.0.1"; + (void) snprintf(addr, sz, "%s://%s:%u/nuts%04x%04x%04x%04x", + scheme, ip, 0, nng_random(), nng_random(), nng_random(), + nng_random()); + return; + } + + if ((strncmp(scheme, "ipc", 3) == 0) || + (strncmp(scheme, "unix", 4) == 0)) { +#ifdef _WIN32 + // Windows doesn't place IPC names in the filesystem. + (void) snprintf(addr, sz, "%s://nuts%04x%04x%04x%04x", scheme, + nng_random(), nng_random(), nng_random(), nng_random()); + return; +#else + char *tmpdir; + + if (((tmpdir = getenv("TMPDIR")) == NULL) && + ((tmpdir = getenv("TEMP")) == NULL) && + ((tmpdir = getenv("TMP")) == NULL)) { + tmpdir = "/tmp"; + } + + (void) snprintf(addr, sz, "%s://%s/nuts%04x%04x%04x%04x", + scheme, tmpdir, nng_random(), nng_random(), nng_random(), + nng_random()); + return; +#endif + } + + // We should not be here. + nng_log_err("NUTS", "Unknown scheme"); + abort(); +} + // nuts_next_port returns a "next" allocation port. // Ports are chosen by starting from a random point within a // range (normally 38000-40000, but other good places to choose diff --git a/src/testing/nuts.h b/src/testing/nuts.h index 5fe193db1..f2e50c2c8 100644 --- a/src/testing/nuts.h +++ b/src/testing/nuts.h @@ -85,6 +85,10 @@ extern uint16_t nuts_next_port(void); // 64 bytes to ensure no truncation occurs. extern void nuts_scratch_addr(const char *, size_t, char *); +// like nuts_scratch_addr, but attempts to use an autobind (0 port) +// address instead. +extern void nuts_scratch_addr_zero(const char *, size_t, char *); + // nuts_marry connects two sockets using inproc. It uses socket // pipe hooks to ensure that it does not return before both sockets // are fully connected. @@ -264,6 +268,14 @@ extern const char *nuts_ecdsa_client_crt; (var) = nuts_addr_; \ } while (0) +#define NUTS_ADDR_ZERO(var, scheme) \ + do { \ + static char nuts_addr_[64]; \ + nuts_scratch_addr_zero( \ + scheme, sizeof(nuts_addr_), nuts_addr_); \ + (var) = nuts_addr_; \ + } while (0) + #define NUTS_OPEN(sock) NUTS_PASS(nng_pair1_open(&(sock))) #define NUTS_CLOSE(sock) NUTS_PASS(nng_close(sock)) diff --git a/src/testing/util.c b/src/testing/util.c index d569bf5f4..2bb882b7a 100644 --- a/src/testing/util.c +++ b/src/testing/util.c @@ -286,16 +286,18 @@ nuts_tran_dialer_closed(const char *scheme) void nuts_tran_duplicate_listen(const char *scheme) { - nng_socket s = NNG_SOCKET_INITIALIZER; - nng_listener l1 = NNG_LISTENER_INITIALIZER; - nng_listener l2 = NNG_LISTENER_INITIALIZER; - const char *addr; + nng_socket s = NNG_SOCKET_INITIALIZER; + nng_listener l1 = NNG_LISTENER_INITIALIZER; + nng_listener l2 = NNG_LISTENER_INITIALIZER; + const char *addr; + const nng_url *url; NUTS_SKIP_IF_IPV6_NEEDED_AND_ABSENT(scheme); - NUTS_ADDR(addr, scheme); + NUTS_ADDR_ZERO(addr, scheme); NUTS_OPEN(s); NUTS_PASS(nng_listen(s, addr, &l1, 0)); - NUTS_FAIL(nng_listen(s, addr, &l2, 0), NNG_EADDRINUSE); + NUTS_PASS(nng_listener_get_url(l1, &url)); + NUTS_FAIL(nng_listen_url(s, url, &l2, 0), NNG_EADDRINUSE); NUTS_TRUE(nng_listener_id(l1) > 0); NUTS_TRUE(nng_listener_id(l2) < 0); NUTS_CLOSE(s); @@ -309,7 +311,7 @@ nuts_tran_listener_cancel(const char *scheme) const char *addr; NUTS_SKIP_IF_IPV6_NEEDED_AND_ABSENT(scheme); - NUTS_ADDR(addr, scheme); + NUTS_ADDR_ZERO(addr, scheme); NUTS_OPEN(s); NUTS_PASS(nng_listen(s, addr, &l, 0)); NUTS_TRUE(nng_listener_id(l) > 0); @@ -325,7 +327,7 @@ nuts_tran_listener_closed(const char *scheme) const char *addr; NUTS_SKIP_IF_IPV6_NEEDED_AND_ABSENT(scheme); - NUTS_ADDR(addr, scheme); + NUTS_ADDR_ZERO(addr, scheme); NUTS_OPEN(s); NUTS_PASS(nng_listener_create(&l, s, addr)); NUTS_TRUE(nng_listener_id(l) > 0); @@ -337,15 +339,16 @@ nuts_tran_listener_closed(const char *scheme) void nuts_tran_listen_accept(const char *scheme) { - nng_socket s1 = NNG_SOCKET_INITIALIZER; - nng_socket s2 = NNG_SOCKET_INITIALIZER; - nng_listener l1 = NNG_LISTENER_INITIALIZER; - nng_dialer d1 = NNG_LISTENER_INITIALIZER; - nng_dialer d2 = NNG_LISTENER_INITIALIZER; - const char *addr; + nng_socket s1 = NNG_SOCKET_INITIALIZER; + nng_socket s2 = NNG_SOCKET_INITIALIZER; + nng_listener l1 = NNG_LISTENER_INITIALIZER; + nng_dialer d1 = NNG_LISTENER_INITIALIZER; + nng_dialer d2 = NNG_LISTENER_INITIALIZER; + const char *addr; + const nng_url *url; NUTS_SKIP_IF_IPV6_NEEDED_AND_ABSENT(scheme); - NUTS_ADDR(addr, scheme); + NUTS_ADDR_ZERO(addr, scheme); NUTS_OPEN(s1); NUTS_OPEN(s2); NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_SENDTIMEO, 100)); @@ -353,8 +356,9 @@ nuts_tran_listen_accept(const char *scheme) NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_RECVTIMEO, 100)); NUTS_PASS(nng_socket_set_ms(s2, NNG_OPT_RECVTIMEO, 100)); NUTS_PASS(nng_listen(s1, addr, &l1, 0)); - NUTS_PASS(nng_dial(s2, addr, &d1, 0)); - NUTS_PASS(nng_dial(s2, addr, &d2, 0)); + NUTS_PASS(nng_listener_get_url(l1, &url)); + NUTS_PASS(nng_dial_url(s2, url, &d1, 0)); + NUTS_PASS(nng_dial_url(s2, url, &d2, 0)); NUTS_TRUE(nng_listener_id(l1) > 0); NUTS_TRUE(nng_dialer_id(d1) > 0); NUTS_TRUE(nng_dialer_id(d2) > 0); @@ -366,14 +370,15 @@ nuts_tran_listen_accept(const char *scheme) void nuts_tran_exchange(const char *scheme) { - nng_socket s1 = NNG_SOCKET_INITIALIZER; - nng_socket s2 = NNG_SOCKET_INITIALIZER; - nng_listener l1 = NNG_LISTENER_INITIALIZER; - nng_dialer d1 = NNG_LISTENER_INITIALIZER; - const char *addr; + nng_socket s1 = NNG_SOCKET_INITIALIZER; + nng_socket s2 = NNG_SOCKET_INITIALIZER; + nng_listener l1 = NNG_LISTENER_INITIALIZER; + nng_dialer d1 = NNG_LISTENER_INITIALIZER; + const char *addr; + const nng_url *url; NUTS_SKIP_IF_IPV6_NEEDED_AND_ABSENT(scheme); - NUTS_ADDR(addr, scheme); + NUTS_ADDR_ZERO(addr, scheme); NUTS_OPEN(s1); NUTS_OPEN(s2); NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_SENDTIMEO, 100)); @@ -381,7 +386,8 @@ nuts_tran_exchange(const char *scheme) NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_RECVTIMEO, 100)); NUTS_PASS(nng_socket_set_ms(s2, NNG_OPT_RECVTIMEO, 100)); NUTS_PASS(nng_listen(s1, addr, &l1, 0)); - NUTS_PASS(nng_dial(s2, addr, &d1, 0)); + NUTS_PASS(nng_listener_get_url(l1, &url)); + NUTS_PASS(nng_dial_url(s2, url, &d1, 0)); NUTS_TRUE(nng_listener_id(l1) > 0); NUTS_TRUE(nng_dialer_id(d1) > 0); for (int i = 0; i < 5; i++) { @@ -397,17 +403,18 @@ nuts_tran_exchange(const char *scheme) void nuts_tran_pipe_id(const char *scheme) { - nng_socket s1 = NNG_SOCKET_INITIALIZER; - nng_socket s2 = NNG_SOCKET_INITIALIZER; - nng_listener l1 = NNG_LISTENER_INITIALIZER; - nng_dialer d1 = NNG_LISTENER_INITIALIZER; - const char *addr; - nng_msg *msg; - nng_pipe p1; - nng_pipe p2; + nng_socket s1 = NNG_SOCKET_INITIALIZER; + nng_socket s2 = NNG_SOCKET_INITIALIZER; + nng_listener l1 = NNG_LISTENER_INITIALIZER; + nng_dialer d1 = NNG_LISTENER_INITIALIZER; + const char *addr; + nng_msg *msg; + nng_pipe p1; + nng_pipe p2; + const nng_url *url; NUTS_SKIP_IF_IPV6_NEEDED_AND_ABSENT(scheme); - NUTS_ADDR(addr, scheme); + NUTS_ADDR_ZERO(addr, scheme); NUTS_OPEN(s1); NUTS_OPEN(s2); NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_SENDTIMEO, 100)); @@ -415,7 +422,8 @@ nuts_tran_pipe_id(const char *scheme) NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_RECVTIMEO, 100)); NUTS_PASS(nng_socket_set_ms(s2, NNG_OPT_RECVTIMEO, 100)); NUTS_PASS(nng_listen(s1, addr, &l1, 0)); - NUTS_PASS(nng_dial(s2, addr, &d1, 0)); + NUTS_PASS(nng_listener_get_url(l1, &url)); + NUTS_PASS(nng_dial_url(s2, url, &d1, 0)); NUTS_TRUE(nng_listener_id(l1) > 0); NUTS_TRUE(nng_dialer_id(d1) > 0); NUTS_SEND(s1, "ping"); @@ -438,18 +446,19 @@ nuts_tran_pipe_id(const char *scheme) void nuts_tran_huge_msg(const char *scheme, size_t size) { - nng_socket s1 = NNG_SOCKET_INITIALIZER; - nng_socket s2 = NNG_SOCKET_INITIALIZER; - nng_listener l1 = NNG_LISTENER_INITIALIZER; - nng_dialer d1 = NNG_LISTENER_INITIALIZER; - const char *addr; - char *buf; - nng_msg *msg; + nng_socket s1 = NNG_SOCKET_INITIALIZER; + nng_socket s2 = NNG_SOCKET_INITIALIZER; + nng_listener l1 = NNG_LISTENER_INITIALIZER; + nng_dialer d1 = NNG_LISTENER_INITIALIZER; + const char *addr; + char *buf; + nng_msg *msg; + const nng_url *url; buf = nng_alloc(size); NUTS_SKIP_IF_IPV6_NEEDED_AND_ABSENT(scheme); - NUTS_ADDR(addr, scheme); + NUTS_ADDR_ZERO(addr, scheme); NUTS_OPEN(s1); NUTS_OPEN(s2); NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_SENDTIMEO, 5000)); @@ -457,7 +466,8 @@ nuts_tran_huge_msg(const char *scheme, size_t size) NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_RECVTIMEO, 5000)); NUTS_PASS(nng_socket_set_ms(s2, NNG_OPT_RECVTIMEO, 5000)); NUTS_PASS(nng_listen(s1, addr, &l1, 0)); - NUTS_PASS(nng_dial(s2, addr, &d1, 0)); + NUTS_PASS(nng_listener_get_url(l1, &url)); + NUTS_PASS(nng_dial_url(s2, url, &d1, 0)); NUTS_TRUE(nng_listener_id(l1) > 0); NUTS_TRUE(nng_dialer_id(d1) > 0); for (int i = 0; i < 5; i++) { @@ -483,12 +493,13 @@ nuts_tran_huge_msg(const char *scheme, size_t size) void nuts_tran_msg_props(const char *scheme, void (*check)(nng_msg *)) { - nng_socket s1 = NNG_SOCKET_INITIALIZER; - nng_socket s2 = NNG_SOCKET_INITIALIZER; - nng_listener l1 = NNG_LISTENER_INITIALIZER; - nng_dialer d1 = NNG_LISTENER_INITIALIZER; - const char *addr; - nng_msg *msg; + nng_socket s1 = NNG_SOCKET_INITIALIZER; + nng_socket s2 = NNG_SOCKET_INITIALIZER; + nng_listener l1 = NNG_LISTENER_INITIALIZER; + nng_dialer d1 = NNG_LISTENER_INITIALIZER; + const char *addr; + nng_msg *msg; + const nng_url *url; NUTS_SKIP_IF_IPV6_NEEDED_AND_ABSENT(scheme); NUTS_ADDR(addr, scheme); @@ -499,7 +510,8 @@ nuts_tran_msg_props(const char *scheme, void (*check)(nng_msg *)) NUTS_PASS(nng_socket_set_ms(s1, NNG_OPT_RECVTIMEO, 100)); NUTS_PASS(nng_socket_set_ms(s2, NNG_OPT_RECVTIMEO, 100)); NUTS_PASS(nng_listen(s1, addr, &l1, 0)); - NUTS_PASS(nng_dial(s2, addr, &d1, 0)); + NUTS_PASS(nng_listener_get_url(l1, &url)); + NUTS_PASS(nng_dial_url(s2, url, &d1, 0)); NUTS_TRUE(nng_listener_id(l1) > 0); NUTS_TRUE(nng_dialer_id(d1) > 0); NUTS_SEND(s1, "ping");