Skip to content

Commit

Permalink
nuts: try to avoid address in use for most tests
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
gdamore committed Dec 7, 2024
1 parent 32c78f7 commit 45ad63d
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 50 deletions.
56 changes: 56 additions & 0 deletions src/testing/marry.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 12 additions & 0 deletions src/testing/nuts.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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))
Expand Down
112 changes: 62 additions & 50 deletions src/testing/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -337,24 +339,26 @@ 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));
NUTS_PASS(nng_socket_set_ms(s2, NNG_OPT_SENDTIMEO, 100));
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);
Expand All @@ -366,22 +370,24 @@ 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));
NUTS_PASS(nng_socket_set_ms(s2, NNG_OPT_SENDTIMEO, 100));
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++) {
Expand All @@ -397,25 +403,27 @@ 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));
NUTS_PASS(nng_socket_set_ms(s2, NNG_OPT_SENDTIMEO, 100));
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");
Expand All @@ -438,26 +446,28 @@ 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));
NUTS_PASS(nng_socket_set_ms(s2, NNG_OPT_SENDTIMEO, 5000));
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++) {
Expand All @@ -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);
Expand All @@ -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");
Expand Down

0 comments on commit 45ad63d

Please sign in to comment.