Skip to content

Commit

Permalink
tests: inproc converted to NUTS
Browse files Browse the repository at this point in the history
This actually represents a conversion of the transport tests implemented
in Convey terms to NUTS.  As part of this, have implemented a simple
round trip performance test, using PAIR.

The rest of the transport tests will shortly be converted to this as well.
  • Loading branch information
gdamore committed Nov 30, 2024
1 parent 12307a1 commit cb8e906
Show file tree
Hide file tree
Showing 6 changed files with 341 additions and 21 deletions.
1 change: 1 addition & 0 deletions src/sp/transport/inproc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ nng_directory(inproc)

nng_sources_if(NNG_TRANSPORT_INPROC inproc.c)
nng_defines_if(NNG_TRANSPORT_INPROC NNG_TRANSPORT_INPROC)
nng_test_if(NNG_TRANSPORT_INPROC inproc_test)
17 changes: 17 additions & 0 deletions src/sp/transport/inproc/inproc_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// Copyright 2024 Staysail Systems, Inc. <[email protected]>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//

#include <nuts.h>

NUTS_DECLARE_TRAN_TESTS(inproc)

NUTS_TESTS = {
NUTS_INSERT_TRAN_TESTS(inproc),
{ NULL, NULL },
};
56 changes: 56 additions & 0 deletions src/testing/nuts.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,62 @@ extern void *nuts_stream_send_start(nng_stream *, void *, size_t);
extern void *nuts_stream_recv_start(nng_stream *, void *, size_t);
extern int nuts_stream_wait(void *);

// nuts_tran_ functions are implementation of tesets
// for transports, to improve code reuse.
extern void nuts_tran_conn_refused(const char *scheme);
extern void nuts_tran_duplicate_listen(const char *scheme);
extern void nuts_tran_listen_accept(const char *scheme);
extern void nuts_tran_exchange(const char *scheme);
extern void nuts_tran_pipe_id(const char *scheme);
extern void nuts_tran_huge_msg(const char *scheme, size_t size);
extern void nuts_tran_msg_props(const char *scheme, void (*check)(nng_msg *));
extern void nuts_tran_perf(const char *scheme);

#ifndef NUTS_TRAN_HUGE_MSG_SIZE
#define NUTS_TRAN_HUGE_MSG_SIZE (1U << 20)
#endif

#define NUTS_DECLARE_TRAN_TESTS(scheme) \
void test_##scheme##_conn_refused(void) \
{ \
nuts_tran_conn_refused(#scheme); \
} \
void test_##scheme##_duplicate_listen(void) \
{ \
nuts_tran_duplicate_listen(#scheme); \
} \
void test_##scheme##_listen_accept(void) \
{ \
nuts_tran_listen_accept(#scheme); \
} \
void test_##scheme##_exchange(void) \
{ \
nuts_tran_exchange(#scheme); \
} \
void test_##scheme##_pipe_id(void) \
{ \
nuts_tran_pipe_id(#scheme); \
} \
void test_##scheme##_huge_msg(void) \
{ \
nuts_tran_huge_msg(#scheme, NUTS_TRAN_HUGE_MSG_SIZE); \
} \
void test_##scheme##_perf(void) \
{ \
nuts_tran_perf(#scheme); \
}

// clang-format off
#define NUTS_INSERT_TRAN_TESTS(scheme) \
{ #scheme " conn refused", test_##scheme##_conn_refused }, \
{ #scheme " duplicate listen", test_##scheme##_duplicate_listen }, \
{ #scheme " listen accept", test_##scheme##_listen_accept }, \
{ #scheme " exchange", test_##scheme##_exchange }, \
{ #scheme " pipe id", test_##scheme##_pipe_id }, \
{ #scheme " huge msg", test_##scheme##_huge_msg }, \
{ #scheme " perf", test_##scheme##_perf }
// clang-format on

// These are TLS certificates. The client and server are signed with the
// root. The server uses CN 127.0.0.1. Other details are bogus, but
// designed to prevent accidental use elsewhere.
Expand Down
267 changes: 267 additions & 0 deletions src/testing/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,3 +214,270 @@ nuts_logger(nng_log_level level, nng_log_facility fac, const char *msgid,
}
acutest_message_color_(color, "%s: %s: %s", lstr, msgid, msg);
}

void
nuts_tran_conn_refused(const char *scheme)
{
nng_socket s = NNG_SOCKET_INITIALIZER;
nng_dialer d = NNG_DIALER_INITIALIZER;
const char *addr;

NUTS_ADDR(addr, scheme);
NUTS_OPEN(s);
NUTS_FAIL(nng_dial(s, addr, &d, 0), NNG_ECONNREFUSED);
NUTS_TRUE(nng_dialer_id(d) < 0);
NUTS_CLOSE(s);
}

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;

NUTS_ADDR(addr, scheme);
NUTS_OPEN(s);
NUTS_PASS(nng_listen(s, addr, &l1, 0));
NUTS_FAIL(nng_listen(s, addr, &l2, 0), NNG_EADDRINUSE);
NUTS_TRUE(nng_listener_id(l1) > 0);
NUTS_TRUE(nng_listener_id(l2) < 0);
NUTS_CLOSE(s);
}

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;

NUTS_ADDR(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_TRUE(nng_listener_id(l1) > 0);
NUTS_TRUE(nng_dialer_id(d1) > 0);
NUTS_TRUE(nng_dialer_id(d2) > 0);
NUTS_TRUE(nng_dialer_id(d1) != nng_dialer_id(d2));
NUTS_CLOSE(s1);
NUTS_CLOSE(s2);
}

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;

NUTS_ADDR(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_TRUE(nng_listener_id(l1) > 0);
NUTS_TRUE(nng_dialer_id(d1) > 0);
for (int i = 0; i < 5; i++) {
NUTS_SEND(s1, "ping");
NUTS_RECV(s2, "ping");
NUTS_SEND(s2, "acknowledge");
NUTS_RECV(s1, "acknowledge");
}
NUTS_CLOSE(s1);
NUTS_CLOSE(s2);
}

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;

NUTS_ADDR(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_TRUE(nng_listener_id(l1) > 0);
NUTS_TRUE(nng_dialer_id(d1) > 0);
NUTS_SEND(s1, "ping");
NUTS_PASS(nng_recvmsg(s2, &msg, 0));
NUTS_MATCH(nng_msg_body(msg), "ping");
p1 = nng_msg_get_pipe(msg);
nng_msg_free(msg);
NUTS_TRUE(nng_pipe_id(p1) > 0);
NUTS_SEND(s2, "acknowledge");
NUTS_PASS(nng_recvmsg(s1, &msg, 0));
NUTS_MATCH(nng_msg_body(msg), "acknowledge");
p2 = nng_msg_get_pipe(msg);
NUTS_TRUE(nng_pipe_id(p2) > 0);
nng_msg_free(msg);
NUTS_TRUE(nng_pipe_id(p1) != nng_pipe_id(p2));
NUTS_CLOSE(s1);
NUTS_CLOSE(s2);
}

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;

buf = nng_alloc(size);

NUTS_ADDR(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_TRUE(nng_listener_id(l1) > 0);
NUTS_TRUE(nng_dialer_id(d1) > 0);
for (int i = 0; i < 5; i++) {
for (size_t j = 0; j < size; j++) {
buf[j] = nng_random() & 0xff;
}
NUTS_PASS(nng_send(s1, buf, size, 0));
NUTS_PASS(nng_recvmsg(s2, &msg, 0));
NUTS_TRUE(nng_msg_len(msg) == size);
NUTS_TRUE(memcmp(nng_msg_body(msg), buf, size) == 0);
nng_msg_free(msg);
NUTS_PASS(nng_send(s2, buf, size, 0));
NUTS_PASS(nng_recvmsg(s1, &msg, 0));
NUTS_TRUE(nng_msg_len(msg) == size);
NUTS_TRUE(memcmp(nng_msg_body(msg), buf, size) == 0);
nng_msg_free(msg);
}
NUTS_CLOSE(s1);
NUTS_CLOSE(s2);
nng_free(buf, 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;

NUTS_ADDR(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_TRUE(nng_listener_id(l1) > 0);
NUTS_TRUE(nng_dialer_id(d1) > 0);
NUTS_SEND(s1, "ping");
NUTS_PASS(nng_recvmsg(s2, &msg, 0));
NUTS_MATCH(nng_msg_body(msg), "ping");
check(msg);
nng_msg_free(msg);
NUTS_CLOSE(s1);
NUTS_CLOSE(s2);
}

void
nuts_tran_perf(const char *scheme)
{
nng_socket s1;
nng_socket s2;
const char *addr;
nng_msg *msg;

nuts_set_logger(NNG_LOG_NOTICE);
NUTS_OPEN(s1);
NUTS_OPEN(s2);
NUTS_ADDR(addr, scheme);
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_MARRY_EX(s1, s2, addr, NULL, NULL);
NUTS_PASS(nng_msg_alloc(&msg, 64));
nng_log_notice(scheme, "Exchanging 64 byte messages for 10 seconds");
nng_time now = nng_clock();
nng_time end = now + 10000; // ten seconds
nng_duration delta;
int rv;
int num = 0;

// count round trips for 10 seconds
while (nng_clock() < end) {
if ((rv = nng_sendmsg(s1, msg, 0)) != 0) {
NUTS_PASS(rv);
NUTS_MSG("nng_sendmsg failed");
break;
}
if ((rv = nng_recvmsg(s2, &msg, 0)) != 0) {
NUTS_PASS(rv);
NUTS_MSG("nng_recvmsg failed");
break;
}
num++;
}
delta = (nng_clock() - now);
nng_msg_free(msg);

// now count the cost of the time collection
now = nng_clock();
for (int i = 0; i < num; i++) {
end = nng_clock();
if (end < now) {
NUTS_ASSERT(end >= now);
}
}
NUTS_ASSERT(end - now > 0);
NUTS_ASSERT(end - now < 10000);
// remove the cost of timing
delta -= (end - now);
nng_log_notice(scheme,
"Did %u roundtrips in %0.2f seconds (%0.3f msg/sec)", num,
delta / 1000.0, (float) num / (delta / 1000.0));
nng_log_notice(scheme, "RTT %0.3f ms", (float) delta / (float) num);
nng_log_notice(
scheme, "Timing overhead %0.3f ms", (end - now) / (float) num);
NUTS_CLOSE(s1);
NUTS_CLOSE(s2);
}
1 change: 0 additions & 1 deletion tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,6 @@ endif ()
add_nng_test(files 5)
add_nng_test1(httpclient 60 NNG_SUPP_HTTP)
add_nng_test1(httpserver 30 NNG_SUPP_HTTP)
add_nng_test(inproc 5)
add_nng_test(ipcsupp 10)
add_nng_test(nonblock 60)
add_nng_test(scalability 20 ON)
Expand Down
20 changes: 0 additions & 20 deletions tests/inproc.c

This file was deleted.

0 comments on commit cb8e906

Please sign in to comment.