diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 90ef40239..b8aa1e634 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -88,5 +88,6 @@ nng_test(message_test) nng_test(reconnect_test) nng_test(sock_test) nng_test(sockaddr_test) +nng_test(synch_test) nng_test(stats_test) nng_test(url_test) diff --git a/src/core/synch_test.c b/src/core/synch_test.c new file mode 100644 index 000000000..87745cbe1 --- /dev/null +++ b/src/core/synch_test.c @@ -0,0 +1,216 @@ +// +// Copyright 2024 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// +// 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 + +#include + +// Notify tests for verifying condvars. +struct notifyarg { + int did; + nng_duration when; + nng_mtx *mx; + nng_cv *cv; + bool wake; + bool fini; +}; + +void +notifyafter(void *a) +{ + struct notifyarg *na = a; + + nng_msleep(na->when); + nng_mtx_lock(na->mx); + na->did = 1; + nng_cv_wake(na->cv); + nng_mtx_unlock(na->mx); +} + +static void +test_mutex_lock_unlock(void) +{ + nng_mtx *mtx; + NUTS_PASS(nng_mtx_alloc(&mtx)); + for (int i = 1; i < 100; i++) { + nng_mtx_lock(mtx); + nng_mtx_unlock(mtx); + } + nng_mtx_free(mtx); +} + +static void +test_mutex_block(void) +{ + nng_thread *thr; + struct notifyarg arg = { 0 }; + + NUTS_PASS(nng_mtx_alloc(&arg.mx)); + NUTS_PASS(nng_cv_alloc(&arg.cv, arg.mx)); + arg.did = 0; + arg.when = 0; + nng_mtx_lock(arg.mx); + NUTS_PASS(nng_thread_create(&thr, notifyafter, &arg)); + nng_thread_set_name(thr, "notify thread"); + nng_msleep(10); + NUTS_TRUE(arg.did == 0); + nng_mtx_unlock(arg.mx); + nng_msleep(10); + nng_mtx_lock(arg.mx); + while (!arg.did) { + nng_cv_wait(arg.cv); + } + NUTS_TRUE(arg.did != 0); + nng_mtx_unlock(arg.mx); + nng_thread_destroy(thr); + nng_cv_free(arg.cv); + nng_mtx_free(arg.mx); +} + +static void +test_cv_wake(void) +{ + nng_thread *thr; + struct notifyarg arg = { 0 }; + + NUTS_PASS(nng_mtx_alloc(&arg.mx)); + NUTS_PASS(nng_cv_alloc(&arg.cv, arg.mx)); + arg.did = 0; + arg.when = 10; + NUTS_PASS(nng_thread_create(&thr, notifyafter, &arg)); + nng_thread_set_name(thr, "notify thread"); + + nng_mtx_lock(arg.mx); + if (!arg.did) { + nng_cv_wait(arg.cv); + } + nng_mtx_unlock(arg.mx); + nng_thread_destroy(thr); + NUTS_TRUE(arg.did == 1); + nng_cv_free(arg.cv); + nng_mtx_free(arg.mx); +} + +static void +waiter(void *arg) +{ + struct notifyarg *na = arg; + nng_mtx_lock(na->mx); + while (!na->wake && !na->fini) { + nng_cv_wait(na->cv); + } + if ((!na->fini) && na->wake) { + na->did++; + } + nng_mtx_unlock(na->mx); +} + +static void +test_cv_wake_only_one(void) +{ + nng_thread *thr1; + nng_thread *thr2; + struct notifyarg arg = { 0 }; + + NUTS_PASS(nng_mtx_alloc(&arg.mx)); + NUTS_PASS(nng_cv_alloc(&arg.cv, arg.mx)); + arg.did = 0; + arg.when = 10; + NUTS_PASS(nng_thread_create(&thr1, waiter, &arg)); + nng_thread_set_name(thr1, "one"); + NUTS_PASS(nng_thread_create(&thr2, waiter, &arg)); + nng_thread_set_name(thr2, "two"); + nng_msleep(200); + + nng_mtx_lock(arg.mx); + arg.wake = true; + nng_cv_wake1(arg.cv); + nng_mtx_unlock(arg.mx); + nng_msleep(200); + + nng_mtx_lock(arg.mx); + NUTS_TRUE(arg.did == 1); + NUTS_MSG("arg.did was %d", arg.did); + arg.fini = true; + nng_cv_wake(arg.cv); + nng_mtx_unlock(arg.mx); + + nng_thread_destroy(thr1); + nng_thread_destroy(thr2); + nng_cv_free(arg.cv); + nng_mtx_free(arg.mx); +} + +static void +test_cv_timeout(void) +{ + nng_thread *thr; + struct notifyarg arg = { 0 }; + + NUTS_PASS(nng_mtx_alloc(&arg.mx)); + NUTS_PASS(nng_cv_alloc(&arg.cv, arg.mx)); + arg.did = 0; + arg.when = 200; + NUTS_PASS(nng_thread_create(&thr, notifyafter, &arg)); + nng_thread_set_name(thr, "notify thread"); + nng_mtx_lock(arg.mx); + if (!arg.did) { + nng_cv_until(arg.cv, nng_clock() + 10); + } + NUTS_TRUE(arg.did == 0); + nng_mtx_unlock(arg.mx); + nng_thread_destroy(thr); + nng_cv_free(arg.cv); + nng_mtx_free(arg.mx); +} + +static void +test_cv_poll(void) +{ + struct notifyarg arg = { 0 }; + + NUTS_PASS(nng_mtx_alloc(&arg.mx)); + NUTS_PASS(nng_cv_alloc(&arg.cv, arg.mx)); + nng_mtx_lock(arg.mx); + NUTS_FAIL(nng_cv_until(arg.cv, 0), NNG_EAGAIN); + nng_mtx_unlock(arg.mx); + nng_cv_free(arg.cv); + nng_mtx_free(arg.mx); +} + +static void +test_cv_timeout_no_thread(void) +{ + struct notifyarg arg = { 0 }; + + NUTS_PASS(nng_mtx_alloc(&arg.mx)); + NUTS_PASS(nng_cv_alloc(&arg.cv, arg.mx)); + arg.did = 0; + arg.when = 1; + nng_mtx_lock(arg.mx); + if (!arg.did) { + nng_cv_until(arg.cv, nng_clock() + 10); + } + NUTS_TRUE(arg.did == 0); + nng_mtx_unlock(arg.mx); + nng_cv_free(arg.cv); + nng_mtx_free(arg.mx); +} + +NUTS_TESTS = { + { "mutex lock unlock", test_mutex_lock_unlock }, + { "mutex lock block", test_mutex_block }, + { "cv wake", test_cv_wake }, + { "cv timeout", test_cv_timeout }, + { "cv poll", test_cv_poll }, + { "cv timeout no thread", test_cv_timeout_no_thread }, + { "cv wake only one", test_cv_wake_only_one }, + { NULL, NULL }, +}; diff --git a/src/platform/CMakeLists.txt b/src/platform/CMakeLists.txt index 6a49d1fe4..d6189c11c 100644 --- a/src/platform/CMakeLists.txt +++ b/src/platform/CMakeLists.txt @@ -13,6 +13,9 @@ nng_directory(platform) add_subdirectory(posix) add_subdirectory(windows) +nng_test(files_test) +nng_test(ipc_stream_test) nng_test(platform_test) nng_test(resolver_test) +nng_test(tcp_stream_test) nng_test(udp_test) diff --git a/src/platform/files_test.c b/src/platform/files_test.c new file mode 100644 index 000000000..903bc28bf --- /dev/null +++ b/src/platform/files_test.c @@ -0,0 +1,279 @@ +// +// Copyright 2024 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// +// 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 "core/nng_impl.h" +#include + +#include +#include + +#ifdef NNG_PLATFORM_POSIX +#include +#include +#endif + +static void +test_permissions(void) +{ +#ifdef NNG_PLATFORM_POSIX + char *temp; + char *file; + void *data; + size_t n; + temp = nni_plat_temp_dir(); + NUTS_TRUE(temp != NULL); + file = nni_file_join(temp, "nng_files_perms_test"); + if (geteuid() == 0) { + NUTS_SKIP("Cannot test permissions as root"); + return; + } + NUTS_PASS(nni_file_put(file, "abc", 4)); + chmod(file, 0); + NUTS_FAIL(nni_file_get(file, &data, &n), NNG_EPERM); + NUTS_FAIL(nni_file_put(file, "def", 4), NNG_EPERM); + nni_file_delete(file); + nni_strfree(file); + nni_strfree(temp); +#else + NUTS_SKIP("Not a POSIX platform"); +#endif +} + +struct walkarg { + int a; + int b; + int c; + int d; + int seen; +}; + +static int +walker(const char *name, void *arg) +{ + struct walkarg *wa = arg; + const char *bn; + + bn = nni_file_basename(name); + if (wa != NULL) { + wa->seen++; + if (strcmp(bn, "a") == 0) { + wa->a++; + } else if (strcmp(bn, "b") == 0) { + wa->b++; + } else if (strcmp(bn, "c") == 0) { + wa->c++; + } else if (strcmp(bn, "d") == 0) { + wa->d++; + } + } + if (strcmp(bn, "stop") == 0) { + return (NNI_FILE_WALK_STOP); + } + if (strcmp(bn, "prunechild") == 0) { + return (NNI_FILE_WALK_PRUNE_CHILD); + } + if (strcmp(bn, "prunesib") == 0) { + return (NNI_FILE_WALK_PRUNE_SIB); + } + return (NNI_FILE_WALK_CONTINUE); +} + +static void +test_directory_names(void) +{ + char *d; + + NUTS_TRUE((d = nni_plat_temp_dir()) != NULL); + nni_strfree(d); + + NUTS_TRUE((d = nni_file_join("a", "b")) != NULL); + NUTS_TRUE(d[0] == 'a'); + NUTS_TRUE(d[2] == 'b'); + NUTS_TRUE(d[3] == '\0'); + NUTS_TRUE((d[1] == '/') || (d[1] == '\\')); + nni_strfree(d); +} + +static void +test_create_file_in_absent_dir(void) +{ + int rv; + char *tmp; + char *d1; + char *d2; + NUTS_TRUE((tmp = nni_plat_temp_dir()) != NULL); + NUTS_TRUE((d1 = nni_file_join(tmp, "bogusdir")) != NULL); + NUTS_TRUE((d2 = nni_file_join(d1, "a")) != NULL); + NUTS_TRUE((rv = nni_plat_file_put(d2, "", 0)) == 0); + NUTS_PASS(nni_file_delete(d2)); + NUTS_PASS(nni_file_delete(d1)); + nni_strfree(d2); + nni_strfree(d1); + nni_strfree(tmp); +} + +static void +test_cannot_read_missing_file(void) +{ + void *data; + size_t n; + NUTS_FAIL(nni_file_get("/bogus/dir/a", &data, &n), NNG_ENOENT); +} + +static void +test_delete_missing_file(void) +{ + NUTS_PASS(nni_file_delete("/bogus/dir/a")); +} + +static void +test_walk_missing_dir(void) +{ + NUTS_FAIL(nni_file_walk("/bogus/dir/a", walker, NULL, 0), NNG_ENOENT); +} + +struct scratch { + char *temp; + char *mydir; + char *a; + char *b; + char *c; + char *d; +}; + +static void +make_scratch(struct scratch *s) +{ + s->temp = nni_plat_temp_dir(); + NUTS_TRUE(s->temp != NULL); + s->mydir = nni_file_join(s->temp, "nng_files_test"); + NUTS_TRUE(s->mydir != NULL); + s->a = nni_file_join(s->mydir, "a"); + NUTS_TRUE(s->a != NULL); + s->b = nni_file_join(s->mydir, "b"); + NUTS_TRUE(s->b != NULL); + s->c = nni_file_join(s->mydir, "c"); + NUTS_TRUE(s->c != NULL); + s->d = nni_file_join(s->c, "d"); + NUTS_TRUE(s->d != NULL); + + NUTS_PASS(nni_file_put(s->a, "alpha", 6)); + NUTS_PASS(nni_file_put(s->b, "bravo", 6)); + NUTS_PASS(nni_file_put(s->d, "delta", 6)); +} + +static void +clean_scratch(struct scratch *s) +{ + nni_strfree(s->temp); + nni_file_delete(s->a); + nni_file_delete(s->b); + nni_file_delete(s->d); + nni_file_delete(s->c); + nni_file_delete(s->mydir); + nni_strfree(s->a); + nni_strfree(s->b); + nni_strfree(s->c); + nni_strfree(s->d); + nni_strfree(s->mydir); +} + +static void +test_directory_walk(void) +{ + struct scratch s = { 0 }; + struct walkarg wa = { 0 }; + + make_scratch(&s); + memset(&wa, 0, sizeof(wa)); + NUTS_PASS(nni_file_walk(s.mydir, walker, &wa, 0)); + NUTS_TRUE(wa.a == 1); + NUTS_TRUE(wa.b == 1); + NUTS_TRUE(wa.c == 1); + NUTS_TRUE(wa.d == 1); + NUTS_TRUE(wa.seen == 4); + + memset(&wa, 0, sizeof(wa)); + NUTS_PASS( + nni_file_walk(s.mydir, walker, &wa, NNI_FILE_WALK_FILES_ONLY)); + NUTS_TRUE(wa.a == 1); + NUTS_TRUE(wa.b == 1); + NUTS_TRUE(wa.c == 0); + NUTS_TRUE(wa.d == 1); + NUTS_TRUE(wa.seen == 3); + + memset(&wa, 0, sizeof(wa)); + NUTS_PASS(nni_file_walk(s.mydir, walker, &wa, NNI_FILE_WALK_SHALLOW)); + NUTS_TRUE(wa.a == 1); + NUTS_TRUE(wa.b == 1); + NUTS_TRUE(wa.c == 1); + NUTS_TRUE(wa.d == 0); + NUTS_TRUE(wa.seen == 3); + + memset(&wa, 0, sizeof(wa)); + NUTS_PASS(nni_file_walk(s.mydir, walker, &wa, + NNI_FILE_WALK_SHALLOW | NNI_FILE_WALK_FILES_ONLY)); + NUTS_TRUE(wa.a == 1); + NUTS_TRUE(wa.b == 1); + NUTS_TRUE(wa.c == 0); + NUTS_TRUE(wa.d == 0); + NUTS_TRUE(wa.seen == 2); + + clean_scratch(&s); +} + +static void +test_file_contents(void) +{ + void *data; + size_t len; + struct scratch s = { 0 }; + + make_scratch(&s); + + NUTS_PASS(nni_file_get(s.a, &data, &len)); + NUTS_TRUE(len == 6); + NUTS_MATCH(data, "alpha"); + nni_free(data, len); + clean_scratch(&s); +} + +static void +test_empty_files(void) +{ + char *temp; + char *empty; + void *data; + size_t n; + temp = nni_plat_temp_dir(); + NUTS_TRUE(temp != NULL); + empty = nni_file_join(temp, "nng_files_test1"); + NUTS_TRUE(empty != NULL); + NUTS_PASS(nni_file_put(empty, "", 0)); + NUTS_PASS(nni_file_get(empty, &data, &n)); + nni_free(data, n); + NUTS_TRUE(n == 0); + nni_file_delete(empty); + nni_strfree(empty); + nni_strfree(temp); +} + +NUTS_TESTS = { + { "permissions", test_permissions }, + { "directory names", test_directory_names }, + { "create file absent dir", test_create_file_in_absent_dir }, + { "cannot read missing file", test_cannot_read_missing_file }, + { "delete missing file", test_delete_missing_file }, + { "walk missing dir", test_walk_missing_dir }, + { "walk directory", test_directory_walk }, + { "file contents", test_file_contents }, + { "empty files", test_empty_files }, + { NULL, NULL }, +}; diff --git a/src/platform/ipc_stream_test.c b/src/platform/ipc_stream_test.c new file mode 100644 index 000000000..caf7861ac --- /dev/null +++ b/src/platform/ipc_stream_test.c @@ -0,0 +1,111 @@ +// +// Copyright 2024 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// Copyright 2018 Devolutions +// +// 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 + +#include + +#include + +void +test_ipc_stream(void) +{ + nng_stream_dialer *d = NULL; + nng_stream_listener *l = NULL; + char *url; + nng_aio *daio = NULL; + nng_aio *laio = NULL; + nng_aio *maio = NULL; + nng_stream *c1 = NULL; + nng_stream *c2 = NULL; + nng_aio *aio1; + nng_aio *aio2; + nng_iov iov; + nng_sockaddr sa2; + char buf1[5]; + char buf2[5]; + + NUTS_ADDR(url, "ipc"); + NUTS_PASS(nng_aio_alloc(&daio, NULL, NULL)); + NUTS_PASS(nng_aio_alloc(&laio, NULL, NULL)); + NUTS_PASS(nng_aio_alloc(&maio, NULL, NULL)); + NUTS_PASS(nng_aio_alloc(&aio1, NULL, NULL)); + NUTS_PASS(nng_aio_alloc(&aio2, NULL, NULL)); + + NUTS_PASS(nng_stream_listener_alloc(&l, url)); + NUTS_PASS(nng_stream_listener_listen(l)); + + NUTS_PASS(nng_stream_dialer_alloc(&d, url)); + nng_stream_dialer_dial(d, daio); + nng_stream_listener_accept(l, laio); + + nng_aio_wait(daio); + NUTS_PASS(nng_aio_result(daio)); + nng_aio_wait(laio); + NUTS_PASS(nng_aio_result(laio)); + + c1 = nng_aio_get_output(daio, 0); + c2 = nng_aio_get_output(laio, 0); + NUTS_TRUE(c1 != NULL); + NUTS_TRUE(c2 != NULL); + + // This relies on send completing for + // for just 5 bytes, and on recv doing + // the same. Technically this isn't + // guaranteed, but it would be weird + // to split such a small payload. + memcpy(buf1, "TEST", 5); + memset(buf2, 0, 5); + iov.iov_buf = buf1; + iov.iov_len = 5; + + nng_aio_set_iov(aio1, 1, &iov); + + iov.iov_buf = buf2; + iov.iov_len = 5; + nng_aio_set_iov(aio2, 1, &iov); + nng_stream_send(c1, aio1); + nng_stream_recv(c2, aio2); + nng_aio_wait(aio1); + nng_aio_wait(aio2); + + NUTS_PASS(nng_aio_result(aio1)); + NUTS_TRUE(nng_aio_count(aio1) == 5); + + NUTS_PASS(nng_aio_result(aio2)); + NUTS_TRUE(nng_aio_count(aio2) == 5); + + NUTS_TRUE(memcmp(buf1, buf2, 5) == 0); + + NUTS_PASS(nng_stream_get_addr(c2, NNG_OPT_LOCADDR, &sa2)); + NUTS_TRUE(sa2.s_ipc.sa_family == NNG_AF_IPC); + NUTS_MATCH(sa2.s_ipc.sa_path, url + strlen("ipc://")); + + nng_aio_free(aio1); + nng_aio_free(aio2); + nng_aio_free(daio); + nng_aio_free(laio); + nng_aio_free(maio); + + nng_stream_listener_close(l); + nng_stream_dialer_close(d); + nng_stream_listener_free(l); + nng_stream_dialer_free(d); + nng_stream_close(c1); + nng_stream_free(c1); + nng_stream_close(c2); + nng_stream_free(c2); +} + +NUTS_TESTS = { + { "ipc stream", test_ipc_stream }, + { NULL, NULL }, +}; diff --git a/src/platform/tcp_stream_test.c b/src/platform/tcp_stream_test.c new file mode 100644 index 000000000..c1353e8a9 --- /dev/null +++ b/src/platform/tcp_stream_test.c @@ -0,0 +1,136 @@ +// +// Copyright 2024 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// +// 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 + +#include + +#include + +void +test_tcp_stream(void) +{ + nng_stream_dialer *d = NULL; + nng_stream_listener *l = NULL; + nng_sockaddr sa; + uint8_t ip[4]; + nng_aio *daio = NULL; + nng_aio *laio = NULL; + nng_aio *maio = NULL; + nng_stream *c1 = NULL; + nng_stream *c2 = NULL; + nng_aio *aio1; + nng_aio *aio2; + nng_iov iov; + nng_sockaddr sa2; + char buf1[5]; + char buf2[5]; + bool on; + + NUTS_PASS(nng_aio_alloc(&daio, NULL, NULL)); + NUTS_PASS(nng_aio_alloc(&laio, NULL, NULL)); + NUTS_PASS(nng_aio_alloc(&maio, NULL, NULL)); + NUTS_PASS(nng_aio_alloc(&aio1, NULL, NULL)); + NUTS_PASS(nng_aio_alloc(&aio2, NULL, NULL)); + + NUTS_PASS(nng_stream_listener_alloc(&l, "tcp://127.0.0.1")); + NUTS_PASS(nng_stream_listener_listen(l)); + + ip[0] = 127; + ip[1] = 0; + ip[2] = 0; + ip[3] = 1; + NUTS_PASS(nng_stream_listener_get_addr(l, NNG_OPT_LOCADDR, &sa)); + NUTS_TRUE(sa.s_in.sa_port != 0); + NUTS_TRUE(memcmp(&sa.s_in.sa_addr, ip, 4) == 0); + + char uri[64]; + snprintf(uri, sizeof(uri), "tcp://127.0.0.1:%d", + nuts_be16(sa.s_in.sa_port)); + + NUTS_PASS(nng_stream_dialer_alloc(&d, uri)); + nng_stream_dialer_dial(d, daio); + nng_stream_listener_accept(l, laio); + + nng_aio_wait(daio); + NUTS_PASS(nng_aio_result(daio)); + nng_aio_wait(laio); + NUTS_PASS(nng_aio_result(laio)); + + c1 = nng_aio_get_output(daio, 0); + c2 = nng_aio_get_output(laio, 0); + NUTS_TRUE(c1 != NULL); + NUTS_TRUE(c2 != NULL); + + on = false; + NUTS_PASS(nng_stream_get_bool(c1, NNG_OPT_TCP_NODELAY, &on)); + NUTS_TRUE(on); + + on = false; + NUTS_PASS(nng_stream_get_bool(c1, NNG_OPT_TCP_KEEPALIVE, &on)); + + // This relies on send completing for + // for just 5 bytes, and on recv doing + // the same. Technically this isn't + // guaranteed, but it would be weird + // to split such a small payload. + memcpy(buf1, "TEST", 5); + memset(buf2, 0, 5); + iov.iov_buf = buf1; + iov.iov_len = 5; + + nng_aio_set_iov(aio1, 1, &iov); + + iov.iov_buf = buf2; + iov.iov_len = 5; + nng_aio_set_iov(aio2, 1, &iov); + nng_stream_send(c1, aio1); + nng_stream_recv(c2, aio2); + nng_aio_wait(aio1); + nng_aio_wait(aio2); + + NUTS_PASS(nng_aio_result(aio1)); + NUTS_TRUE(nng_aio_count(aio1) == 5); + + NUTS_PASS(nng_aio_result(aio2)); + NUTS_TRUE(nng_aio_count(aio2) == 5); + + NUTS_TRUE(memcmp(buf1, buf2, 5) == 0); + + NUTS_PASS(nng_stream_get_addr(c2, NNG_OPT_LOCADDR, &sa2)); + NUTS_TRUE(sa2.s_in.sa_family == NNG_AF_INET); + + NUTS_TRUE(sa2.s_in.sa_addr == sa.s_in.sa_addr); + NUTS_TRUE(sa2.s_in.sa_port == sa.s_in.sa_port); + + NUTS_PASS(nng_stream_get_addr(c1, NNG_OPT_REMADDR, &sa2)); + NUTS_TRUE(sa2.s_in.sa_family == NNG_AF_INET); + NUTS_TRUE(sa2.s_in.sa_addr == sa.s_in.sa_addr); + NUTS_TRUE(sa2.s_in.sa_port == sa.s_in.sa_port); + + nng_stream_listener_close(l); + nng_stream_listener_free(l); + nng_stream_dialer_close(d); + nng_stream_dialer_free(d); + nng_aio_free(aio1); + nng_aio_free(aio2); + nng_aio_free(daio); + nng_aio_free(laio); + nng_aio_free(maio); + nng_stream_close(c1); + nng_stream_free(c1); + nng_stream_close(c2); + nng_stream_free(c2); +} + +NUTS_TESTS = { + { "tcp stream", test_tcp_stream }, + { NULL, NULL }, +}; diff --git a/src/sp/CMakeLists.txt b/src/sp/CMakeLists.txt index 4704f8021..ef79e674d 100644 --- a/src/sp/CMakeLists.txt +++ b/src/sp/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2021 Staysail Systems, Inc. +# Copyright 2024 Staysail Systems, Inc. # # This software is supplied under the terms of the MIT License, a # copy of which should be located in the distribution where this @@ -17,3 +17,9 @@ nng_sources( transport.c transport.h ) + +nng_test(pipe_test) +nng_test(device_test) +nng_test(multistress_test) +nng_test(nonblock_test) +nng_test(scalability_test) diff --git a/src/sp/device_test.c b/src/sp/device_test.c new file mode 100644 index 000000000..6d2ff1fba --- /dev/null +++ b/src/sp/device_test.c @@ -0,0 +1,170 @@ +// +// Copyright 2024 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// +// 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 + +#include +#include +#include + +#include + +struct dev_data { + nng_socket s1; + nng_socket s2; +}; + +void +dodev(void *arg) +{ + struct dev_data *d = arg; + + nng_device(d->s1, d->s2); +} + +#define SECOND(x) ((x) *1000) + +void +test_device_not_cooked(void) +{ + nng_socket cooked; + nng_socket raw; + NUTS_PASS(nng_pair1_open(&cooked)); + NUTS_PASS(nng_pair1_open_raw(&raw)); + NUTS_FAIL(nng_device(cooked, cooked), NNG_EINVAL); + NUTS_FAIL(nng_device(raw, cooked), NNG_EINVAL); + NUTS_FAIL(nng_device(cooked, raw), NNG_EINVAL); + NUTS_CLOSE(cooked); + NUTS_CLOSE(raw); +} + +void +test_device_incompatible(void) +{ + nng_socket s1; + nng_socket s2; + NUTS_PASS(nng_pair0_open_raw(&s1)); + NUTS_PASS(nng_pair1_open_raw(&s2)); + NUTS_FAIL(nng_device(s1, s2), NNG_EINVAL); + NUTS_CLOSE(s1); + NUTS_CLOSE(s2); +} +void +test_device_forward(void) +{ + nng_thread *thr; + struct dev_data d; + nng_duration tmo = SECOND(1); + nng_socket e1, e2; + + // will be a pair variant + NUTS_PASS(nng_pair1_open_raw(&d.s1)); + NUTS_PASS(nng_pair1_open_raw(&d.s2)); + NUTS_PASS(nng_pair1_open(&e1)); + NUTS_PASS(nng_pair1_open(&e2)); + NUTS_PASS(nng_socket_set_ms(e1, NNG_OPT_RECVTIMEO, tmo)); + NUTS_PASS(nng_socket_set_ms(e2, NNG_OPT_RECVTIMEO, tmo)); + NUTS_PASS(nng_socket_set_ms(e1, NNG_OPT_SENDTIMEO, tmo)); + NUTS_PASS(nng_socket_set_ms(e2, NNG_OPT_SENDTIMEO, tmo)); + + NUTS_MARRY(e1, d.s1); + NUTS_MARRY(e2, d.s2); + NUTS_PASS(nng_thread_create(&thr, dodev, &d)); + nng_thread_set_name(thr, "device thread"); + + NUTS_SEND(e1, "ping"); + NUTS_RECV(e2, "ping"); + NUTS_SEND(e2, "pong"); + NUTS_RECV(e1, "pong"); + + NUTS_CLOSE(e1); + NUTS_CLOSE(e2); + NUTS_CLOSE(d.s1); + NUTS_CLOSE(d.s2); + nng_thread_destroy(thr); +} + +void +test_device_reflect(void) +{ + nng_thread *thr; + struct dev_data d; + nng_duration tmo = SECOND(1); + nng_socket e1; + + // will be a pair variant + NUTS_PASS(nng_pair1_open_raw(&d.s1)); + d.s2 = d.s1; + NUTS_PASS(nng_pair1_open(&e1)); + NUTS_PASS(nng_socket_set_ms(e1, NNG_OPT_RECVTIMEO, tmo)); + NUTS_PASS(nng_socket_set_ms(e1, NNG_OPT_SENDTIMEO, tmo)); + + NUTS_MARRY(e1, d.s1); + NUTS_PASS(nng_thread_create(&thr, dodev, &d)); + nng_thread_set_name(thr, "device thread"); + + NUTS_SEND(e1, "ping"); + NUTS_RECV(e1, "ping"); + NUTS_SEND(e1, "pong"); + NUTS_RECV(e1, "pong"); + + NUTS_CLOSE(e1); + NUTS_CLOSE(d.s1); + nng_thread_destroy(thr); +} + +void +test_device_aio(void) +{ + struct dev_data d; + nng_duration tmo = SECOND(1); + nng_socket e1, e2; + nng_aio *aio; + + // will be a pair variant + NUTS_PASS(nng_pair1_open_raw(&d.s1)); + NUTS_PASS(nng_pair1_open_raw(&d.s2)); + NUTS_PASS(nng_pair1_open(&e1)); + NUTS_PASS(nng_pair1_open(&e2)); + NUTS_PASS(nng_socket_set_ms(e1, NNG_OPT_RECVTIMEO, tmo)); + NUTS_PASS(nng_socket_set_ms(e2, NNG_OPT_RECVTIMEO, tmo)); + NUTS_PASS(nng_socket_set_ms(e1, NNG_OPT_SENDTIMEO, tmo)); + NUTS_PASS(nng_socket_set_ms(e2, NNG_OPT_SENDTIMEO, tmo)); + + NUTS_MARRY(e1, d.s1); + NUTS_MARRY(e2, d.s2); + // cancellation of this aio is how we stop it + NUTS_PASS(nng_aio_alloc(&aio, NULL, NULL)); + nng_device_aio(aio, d.s1, d.s2); + + NUTS_SEND(e1, "ping"); + NUTS_RECV(e2, "ping"); + NUTS_SEND(e2, "pong"); + NUTS_RECV(e1, "pong"); + + nng_aio_cancel(aio); + nng_aio_wait(aio); + NUTS_FAIL(nng_aio_result(aio), NNG_ECANCELED); + nng_aio_free(aio); + + NUTS_CLOSE(e1); + NUTS_CLOSE(e2); + NUTS_CLOSE(d.s1); + NUTS_CLOSE(d.s2); +} + +NUTS_TESTS = { + { "device not cooked", test_device_not_cooked }, + { "device incompatible", test_device_incompatible }, + { "device forward", test_device_forward }, + { "device reflect", test_device_reflect }, + { "device aio", test_device_aio }, + { NULL, NULL }, +}; diff --git a/tests/multistress.c b/src/sp/multistress_test.c similarity index 95% rename from tests/multistress.c rename to src/sp/multistress_test.c index b9e480149..1e336205d 100644 --- a/tests/multistress.c +++ b/src/sp/multistress_test.c @@ -25,8 +25,7 @@ #include #include -#include "convey.h" -#include "stubs.h" +#include #ifdef NDEBUG #define dprintf(...) @@ -761,7 +760,9 @@ pipeline0_test(int ntests) nng_sleep_aio(1, srv->woke); } -Main({ +void +test_multi_stress(void) +{ int i; char *str; int tmo; @@ -769,13 +770,13 @@ Main({ // Each run should truly be random. srand((int) time(NULL)); - if (((str = ConveyGetEnv("STRESSTIME")) == NULL) || + if (((str = getenv("STRESSTIME")) == NULL) || ((tmo = atoi(str)) < 1)) { tmo = 30; } // We have to keep this relatively low by default because some // platforms have limited resources. - if (((str = ConveyGetEnv("STRESSPRESSURE")) == NULL) || + if (((str = getenv("STRESSPRESSURE")) == NULL) || ((ncases = atoi(str)) < 1)) { ncases = 32; } @@ -822,31 +823,32 @@ Main({ nng_aio_stop(cases[i].woke); } - Test("MultiProtocol/Transport Stress", { - Convey("All tests worked", { - for (i = 0; i < ncases; i++) { - test_case *c = &cases[i]; - if (c->name == NULL) { - break; - } - nng_aio_stop(c->sent); - nng_aio_stop(c->recd); - nng_aio_stop(c->woke); - nng_aio_free(c->sent); - nng_aio_free(c->recd); - nng_aio_free(c->woke); - - dprintf("RESULT socket %u (%s) sent %d " - "recd %d fail %d\n", - c->sock.id, c->name, c->nsend, c->nrecv, - c->nfail); - So(c->nfail == 0); - So((c->sent == NULL) || (c->nsend > 0)); - So((c->recd == NULL) || (c->nrecv > 0)); - } - }); - }); + for (i = 0; i < ncases; i++) { + test_case *c = &cases[i]; + if (c->name == NULL) { + break; + } + nng_aio_stop(c->sent); + nng_aio_stop(c->recd); + nng_aio_stop(c->woke); + nng_aio_free(c->sent); + nng_aio_free(c->recd); + nng_aio_free(c->woke); + + dprintf("RESULT socket %u (%s) sent %d " + "recd %d fail %d\n", + c->sock.id, c->name, c->nsend, c->nrecv, c->nfail); + NUTS_TRUE(c->nfail == 0); + NUTS_TRUE((c->sent == NULL) || (c->nsend > 0)); + NUTS_TRUE((c->recd == NULL) || (c->nrecv > 0)); + + NUTS_CLOSE(c->sock); + } free(cases); - nng_fini(); -}) +} + +NUTS_TESTS = { + { "multi stress", test_multi_stress }, + { NULL, NULL }, +}; diff --git a/tests/nonblock.c b/src/sp/nonblock_test.c similarity index 71% rename from tests/nonblock.c rename to src/sp/nonblock_test.c index 624c92331..0f9be0348 100644 --- a/tests/nonblock.c +++ b/src/sp/nonblock_test.c @@ -14,14 +14,19 @@ #ifndef _WIN32 #include #include +#define PLATFD int +#else +#include +// order counts +#include +#define PLATFD SOCKET #endif #include #include #include -#include "convey.h" -#include "stubs.h" +#include const char *addr = "inproc://bug346"; @@ -92,27 +97,32 @@ reqthr(void *arg) nng_socket reqs[NCLIENTS]; nng_socket rep; -TestMain("Nonblocking Works", { - Convey("Running for 15 sec", { - nng_thread *server; - nng_thread *clients[NCLIENTS]; +static void +test_nonblocking(void) +{ + nng_thread *server; + nng_thread *clients[NCLIENTS]; - So(nng_rep0_open(&rep) == 0); - for (int i = 0; i < NCLIENTS; i++) { - So(nng_req0_open(&reqs[i]) == 0); - } + NUTS_PASS(nng_rep0_open(&rep)); + for (int i = 0; i < NCLIENTS; i++) { + NUTS_PASS(nng_req0_open(&reqs[i])); + } - nng_thread_create(&server, repthr, &rep); - for (int i = 0; i < NCLIENTS; i++) { - nng_thread_create(&clients[i], reqthr, &reqs[i]); - } + NUTS_PASS(nng_thread_create(&server, repthr, &rep)); + for (int i = 0; i < NCLIENTS; i++) { + NUTS_PASS(nng_thread_create(&clients[i], reqthr, &reqs[i])); + } - nng_msleep(15000); - nng_close(rep); - nng_thread_destroy(server); - for (int i = 0; i < NCLIENTS; i++) { - nng_close(reqs[i]); - nng_thread_destroy(clients[i]); - } - }); -}) + nng_msleep(15000); + nng_close(rep); + nng_thread_destroy(server); + for (int i = 0; i < NCLIENTS; i++) { + nng_close(reqs[i]); + nng_thread_destroy(clients[i]); + } +} + +NUTS_TESTS = { + { "nonblocking", test_nonblocking }, + { NULL, NULL }, +}; diff --git a/src/sp/pipe_test.c b/src/sp/pipe_test.c new file mode 100644 index 000000000..787eac694 --- /dev/null +++ b/src/sp/pipe_test.c @@ -0,0 +1,276 @@ +// +// Copyright 2024 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// +// 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 +#include + +#include +#include +#include + +#include + +struct testcase { + nng_socket s; + nng_dialer d; + nng_listener l; + nng_pipe p; + int add_pre; + int add_post; + int rem; + int err; + int rej; + nng_mtx *lk; + nng_cv *cv; +}; + +static bool +expect(struct testcase *t, int *vp, int v) +{ + bool ok; + nng_time when = nng_clock() + 5000; // five seconds + + nng_mtx_lock(t->lk); + while (*vp != v) { + if (nng_cv_until(t->cv, when) == NNG_ETIMEDOUT) { + break; + } + } + ok = (*vp == v) ? true : false; + if (!ok) { + NUTS_MSG("Expected %d but got %d\n", v, *vp); + } + nng_mtx_unlock(t->lk); + return (ok); +} + +void +notify(nng_pipe p, nng_pipe_ev act, void *arg) +{ + struct testcase *t = arg; + + nng_mtx_lock(t->lk); + if ((nng_socket_id(nng_pipe_socket(p)) != nng_socket_id(t->s)) || + (nng_listener_id(nng_pipe_listener(p)) != nng_listener_id(t->l)) || + (nng_dialer_id(nng_pipe_dialer(p)) != nng_dialer_id(t->d))) { + t->err++; + nng_cv_wake(t->cv); + nng_mtx_unlock(t->lk); + return; + } + if (t->add_post > t->add_pre) { + t->err++; + } + switch (act) { + case NNG_PIPE_EV_ADD_PRE: + t->add_pre++; + break; + case NNG_PIPE_EV_ADD_POST: + t->add_post++; + break; + case NNG_PIPE_EV_REM_POST: + t->rem++; + break; + default: + t->err++; + nng_cv_wake(t->cv); + nng_mtx_unlock(t->lk); + return; + } + t->p = p; + nng_cv_wake(t->cv); + nng_mtx_unlock(t->lk); +} + +void +reject(nng_pipe p, nng_pipe_ev act, void *arg) +{ + struct testcase *t = arg; + notify(p, act, arg); + + nng_mtx_lock(t->lk); + if (!t->rej) { + nng_pipe_close(p); + t->rej++; + } + nng_mtx_unlock(t->lk); +} + +static void +init_cases(char *addr, struct testcase *push, struct testcase *pull) +{ + memset(push, 0, sizeof(*push)); + memset(pull, 0, sizeof(*pull)); + NUTS_PASS(nng_mtx_alloc(&push->lk)); + NUTS_PASS(nng_cv_alloc(&push->cv, push->lk)); + NUTS_PASS(nng_mtx_alloc(&pull->lk)); + NUTS_PASS(nng_cv_alloc(&pull->cv, pull->lk)); + + NUTS_PASS(nng_push_open(&push->s)); + NUTS_PASS(nng_pull_open(&pull->s)); + + NUTS_PASS(nng_socket_set_ms(push->s, NNG_OPT_RECONNMINT, 10)); + NUTS_PASS(nng_socket_set_ms(push->s, NNG_OPT_RECONNMAXT, 10)); + NUTS_PASS(nng_socket_set_ms(pull->s, NNG_OPT_RECONNMINT, 10)); + NUTS_PASS(nng_socket_set_ms(pull->s, NNG_OPT_RECONNMAXT, 10)); + + NUTS_PASS(nng_listener_create(&pull->l, pull->s, addr)); + NUTS_PASS(nng_dialer_create(&push->d, push->s, addr)); + NUTS_TRUE(nng_listener_id(pull->l) > 0); + NUTS_TRUE(nng_dialer_id(push->d) > 0); + NUTS_PASS(nng_dialer_set_ms(push->d, NNG_OPT_RECONNMINT, 10)); + NUTS_PASS(nng_dialer_set_ms(push->d, NNG_OPT_RECONNMAXT, 10)); + + NUTS_PASS(nng_pipe_notify(push->s, NNG_PIPE_EV_ADD_PRE, notify, push)); + NUTS_PASS( + nng_pipe_notify(push->s, NNG_PIPE_EV_ADD_POST, notify, push)); + NUTS_PASS( + nng_pipe_notify(push->s, NNG_PIPE_EV_REM_POST, notify, push)); + NUTS_PASS(nng_pipe_notify(pull->s, NNG_PIPE_EV_ADD_PRE, notify, pull)); + NUTS_PASS( + nng_pipe_notify(pull->s, NNG_PIPE_EV_ADD_POST, notify, pull)); + NUTS_PASS( + nng_pipe_notify(pull->s, NNG_PIPE_EV_REM_POST, notify, pull)); +} + +static void +fini_cases(struct testcase *push, struct testcase *pull) +{ + nng_close(push->s); + nng_close(pull->s); + nng_cv_free(push->cv); + nng_cv_free(pull->cv); + nng_mtx_free(push->lk); + nng_mtx_free(pull->lk); +} + +static void +test_pipe_msg_id(void) +{ + static struct testcase push = { 0 }; + static struct testcase pull = { 0 }; + char *addr; + nng_msg *msg; + + NUTS_ADDR(addr, "inproc"); + + init_cases(addr, &push, &pull); + + NUTS_PASS(nng_listener_start(pull.l, 0)); + NUTS_PASS(nng_dialer_start(push.d, 0)); + NUTS_TRUE(expect(&pull, &pull.add_pre, 1)); + NUTS_TRUE(expect(&pull, &pull.add_post, 1)); + NUTS_TRUE(expect(&pull, &pull.add_pre, 1)); + NUTS_TRUE(expect(&pull, &pull.add_post, 1)); + NUTS_TRUE(expect(&pull, &pull.rem, 0)); + NUTS_TRUE(expect(&pull, &pull.err, 0)); + NUTS_TRUE(expect(&push, &push.add_pre, 1)); + NUTS_TRUE(expect(&push, &push.add_post, 1)); + NUTS_TRUE(expect(&push, &push.rem, 0)); + NUTS_TRUE(expect(&push, &push.err, 0)); + + NUTS_PASS(nng_msg_alloc(&msg, 0)); + NUTS_PASS(nng_msg_append(msg, "hello", strlen("hello") + 1)); + NUTS_PASS(nng_sendmsg(push.s, msg, 0)); + msg = NULL; + NUTS_PASS(nng_recvmsg(pull.s, &msg, 0)); + NUTS_TRUE(msg != NULL); + NUTS_TRUE(nng_msg_len(msg) == strlen("hello") + 1); + NUTS_MATCH(nng_msg_body(msg), "hello"); + NUTS_TRUE(nng_pipe_id(nng_msg_get_pipe(msg)) == nng_pipe_id(pull.p)); + nng_msg_free(msg); + fini_cases(&push, &pull); +} + +static void +test_pipe_reconnect(void) +{ + struct testcase push = { 0 }; + struct testcase pull = { 0 }; + char *addr; + nng_msg *msg; + + NUTS_ADDR(addr, "inproc"); + + init_cases(addr, &push, &pull); + + NUTS_PASS(nng_listener_start(pull.l, 0)); + NUTS_PASS(nng_dialer_start(push.d, 0)); + NUTS_TRUE(expect(&pull, &pull.add_pre, 1)); + NUTS_TRUE(expect(&pull, &pull.add_post, 1)); + NUTS_TRUE(expect(&pull, &pull.add_pre, 1)); + NUTS_TRUE(expect(&pull, &pull.add_post, 1)); + NUTS_TRUE(expect(&pull, &pull.rem, 0)); + NUTS_TRUE(expect(&pull, &pull.err, 0)); + NUTS_TRUE(expect(&push, &push.add_pre, 1)); + NUTS_TRUE(expect(&push, &push.add_post, 1)); + NUTS_TRUE(expect(&push, &push.rem, 0)); + NUTS_TRUE(expect(&push, &push.err, 0)); + + NUTS_TRUE(expect(&pull, &pull.add_pre, 1)); + NUTS_TRUE(expect(&pull, &pull.add_post, 1)); + nng_pipe_close(pull.p); + + NUTS_TRUE(expect(&pull, &pull.rem, 1)); + NUTS_TRUE(expect(&pull, &pull.err, 0)); + NUTS_TRUE(expect(&pull, &pull.add_pre, 2)); + NUTS_TRUE(expect(&pull, &pull.add_post, 2)); + + NUTS_TRUE(expect(&push, &push.rem, 1)); + NUTS_TRUE(expect(&push, &push.err, 0)); + NUTS_TRUE(expect(&push, &push.add_pre, 2)); + NUTS_TRUE(expect(&push, &push.add_post, 2)); + + nng_msleep(200); + NUTS_PASS(nng_msg_alloc(&msg, 0)); + NUTS_PASS(nng_msg_append(msg, "hello", strlen("hello") + 1)); + NUTS_PASS(nng_sendmsg(push.s, msg, 0)); + msg = NULL; + NUTS_PASS(nng_recvmsg(pull.s, &msg, 0)); + NUTS_TRUE(msg != NULL); + NUTS_MATCH(nng_msg_body(msg), "hello"); + nng_pipe p1 = nng_msg_get_pipe(msg); + nng_msg_free(msg); + NUTS_TRUE(nng_pipe_id(p1) == nng_pipe_id(pull.p)); + fini_cases(&push, &pull); +} + +static void +test_pipe_reject(void) +{ + struct testcase push = { 0 }; + struct testcase pull = { 0 }; + char *addr; + + NUTS_ADDR(addr, "inproc"); + + init_cases(addr, &push, &pull); + NUTS_PASS(nng_pipe_notify(pull.s, NNG_PIPE_EV_ADD_PRE, reject, &pull)); + NUTS_PASS(nng_listener_start(pull.l, 0)); + nng_msleep(100); + NUTS_PASS(nng_dialer_start(push.d, 0)); + NUTS_TRUE(expect(&pull, &pull.add_pre, 2)); + NUTS_TRUE(expect(&pull, &pull.add_post, 1)); + NUTS_TRUE(expect(&pull, &pull.rem, 1)); + NUTS_TRUE(expect(&pull, &pull.err, 0)); + NUTS_TRUE(expect(&push, &push.add_pre, 2)); + NUTS_TRUE(expect(&push, &push.add_post, 2)); + NUTS_TRUE(expect(&push, &push.rem, 1) == 1); + NUTS_TRUE(expect(&push, &push.err, 0)); + + fini_cases(&push, &pull); +} + +NUTS_TESTS = { + { "pipe msg id", test_pipe_msg_id }, + { "pipe reconnect", test_pipe_reconnect }, + { "pipe reject", test_pipe_reject }, + { NULL, NULL }, +}; diff --git a/src/sp/protocol/reqrep0/CMakeLists.txt b/src/sp/protocol/reqrep0/CMakeLists.txt index a3cecfd03..b5d447593 100644 --- a/src/sp/protocol/reqrep0/CMakeLists.txt +++ b/src/sp/protocol/reqrep0/CMakeLists.txt @@ -23,3 +23,4 @@ nng_test(req_test) nng_test(rep_test) nng_test(xrep_test) nng_test(xreq_test) +nng_test(reqstress_test) diff --git a/src/sp/protocol/reqrep0/rep_test.c b/src/sp/protocol/reqrep0/rep_test.c index 6ca8fbca0..579f795c1 100644 --- a/src/sp/protocol/reqrep0/rep_test.c +++ b/src/sp/protocol/reqrep0/rep_test.c @@ -164,6 +164,7 @@ test_rep_double_recv(void) nng_aio_wait(aio2); NUTS_FAIL(nng_aio_result(aio2), NNG_ESTATE); NUTS_CLOSE(s1); + nng_aio_wait(aio1); NUTS_FAIL(nng_aio_result(aio1), NNG_ECLOSED); nng_aio_free(aio1); nng_aio_free(aio2); diff --git a/src/sp/protocol/reqrep0/req_test.c b/src/sp/protocol/reqrep0/req_test.c index 71e088771..d1c615d1b 100644 --- a/src/sp/protocol/reqrep0/req_test.c +++ b/src/sp/protocol/reqrep0/req_test.c @@ -934,6 +934,7 @@ test_req_ctx_recv_close_socket(void) nng_ctx_recv(ctx, aio); nng_close(req); + nng_aio_wait(aio); NUTS_FAIL(nng_aio_result(aio), NNG_ECLOSED); nng_aio_free(aio); NUTS_CLOSE(rep); diff --git a/tests/reqstress.c b/src/sp/protocol/reqrep0/reqstress_test.c similarity index 89% rename from tests/reqstress.c rename to src/sp/protocol/reqrep0/reqstress_test.c index de31e9877..cd0004a09 100644 --- a/tests/reqstress.c +++ b/src/sp/protocol/reqrep0/reqstress_test.c @@ -17,8 +17,7 @@ #include #include -#include "convey.h" -#include "stubs.h" +#include #ifdef NDEBUG #define dprintf(...) @@ -261,19 +260,21 @@ reqrep_test(int ntests) } } -Main({ +static void +test_req_stress(void) +{ int i; int tmo; char *str; - if (((str = ConveyGetEnv("STRESSTIME")) == NULL) || + if (((str = getenv("STRESSTIME")) == NULL) || ((tmo = atoi(str)) < 1)) { tmo = 30; } // We have to keep this relatively low by default because some // platforms don't support large numbers of sockets. (On macOS // laptop I can run this with 500 though.) - if (((str = ConveyGetEnv("STRESSPRESSURE")) == NULL) || + if (((str = getenv("STRESSPRESSURE")) == NULL) || ((ncases = atoi(str)) < 1)) { ncases = 32; } @@ -307,30 +308,29 @@ Main({ } nng_msleep(100); - Test("Req/Rep Stress", { - Convey("All tests worked", { - for (i = 0; i < ncases; i++) { - nng_aio_stop(cases[i].recv_aio); - nng_aio_stop(cases[i].send_aio); - nng_aio_stop(cases[i].time_aio); - nng_aio_free(cases[i].recv_aio); - nng_aio_free(cases[i].send_aio); - nng_aio_free(cases[i].time_aio); - if (cases[i].name != NULL) { - dprintf( - "RESULT socket %u (%s) sent %d " - "recd %d fail %d\n", - cases[i].socket.id, cases[i].name, - cases[i].nsend, cases[i].nrecv, - cases[i].nfail); - So(cases[i].nfail == 0); - So(cases[i].nsend > 0 || - cases[i].nrecv > 0); - } - } - }); - }); + for (i = 0; i < ncases; i++) { + nng_aio_stop(cases[i].recv_aio); + nng_aio_stop(cases[i].send_aio); + nng_aio_stop(cases[i].time_aio); + nng_aio_free(cases[i].recv_aio); + nng_aio_free(cases[i].send_aio); + nng_aio_free(cases[i].time_aio); + if (cases[i].name != NULL) { + dprintf("RESULT socket %u (%s) sent %d " + "recd %d fail %d\n", + cases[i].socket.id, cases[i].name, cases[i].nsend, + cases[i].nrecv, cases[i].nfail); + NUTS_TRUE(cases[i].nfail == 0); + NUTS_TRUE(cases[i].nsend > 0 || cases[i].nrecv > 0); + NUTS_CLOSE(cases[i].socket); + } + } free(cases); nng_fini(); -}) +} + +NUTS_TESTS = { + { "req stress", test_req_stress }, + { NULL, NULL }, +}; diff --git a/src/sp/protocol/survey0/respond_test.c b/src/sp/protocol/survey0/respond_test.c index 15061cc2e..0260dc30a 100644 --- a/src/sp/protocol/survey0/respond_test.c +++ b/src/sp/protocol/survey0/respond_test.c @@ -164,6 +164,7 @@ test_resp_double_recv(void) nng_aio_wait(aio2); NUTS_FAIL(nng_aio_result(aio2), NNG_ESTATE); NUTS_CLOSE(s1); + nng_aio_wait(aio1); NUTS_FAIL(nng_aio_result(aio1), NNG_ECLOSED); nng_aio_free(aio1); nng_aio_free(aio2); diff --git a/src/sp/protocol/survey0/survey_test.c b/src/sp/protocol/survey0/survey_test.c index 6a5574c06..3f122abbe 100644 --- a/src/sp/protocol/survey0/survey_test.c +++ b/src/sp/protocol/survey0/survey_test.c @@ -504,6 +504,7 @@ test_surv_ctx_recv_close_socket(void) nng_ctx_recv(ctx, aio); nng_close(surv); + nng_aio_wait(aio); NUTS_FAIL(nng_aio_result(aio), NNG_ECLOSED); nng_aio_free(aio); NUTS_CLOSE(resp); diff --git a/tests/scalability.c b/src/sp/scalability_test.c similarity index 65% rename from tests/scalability.c rename to src/sp/scalability_test.c index 0b4b17993..6e9047a1a 100644 --- a/tests/scalability.c +++ b/src/sp/scalability_test.c @@ -14,8 +14,7 @@ #include #include -#include "convey.h" -#include "stubs.h" +#include static int nclients = 200; @@ -45,18 +44,15 @@ serve(void *arg) int openclients(nng_socket *clients, int num) { - int rv; int i; nng_duration t; for (i = 0; i < num; i++) { t = 100; // 100ms nng_socket c; - if (((rv = nng_req_open(&c)) != 0) || - ((rv = nng_socket_set_ms(c, NNG_OPT_RECVTIMEO, t)) != 0) || - ((rv = nng_socket_set_ms(c, NNG_OPT_SENDTIMEO, t)) != 0) || - ((rv = nng_dial(c, addr, NULL, 0)) != 0)) { - return (rv); - } + NUTS_PASS(nng_req_open(&c)); + NUTS_PASS(nng_socket_set_ms(c, NNG_OPT_RECVTIMEO, t)); + NUTS_PASS(nng_socket_set_ms(c, NNG_OPT_SENDTIMEO, t)); + NUTS_PASS(nng_dial(c, addr, NULL, 0)); clients[i] = c; } return (0); @@ -84,36 +80,35 @@ transact(nng_socket *clients, int num) return (rv); } -Main({ +void +test_scalability(void) +{ nng_socket *clients; int *results; clients = calloc(nclients, sizeof(nng_socket)); results = calloc(nclients, sizeof(int)); - if ((nng_rep_open(&rep) != 0) || - (nng_socket_set_int(rep, NNG_OPT_RECVBUF, 256) != 0) || - (nng_socket_set_int(rep, NNG_OPT_SENDBUF, 256) != 0) || - (nng_listen(rep, addr, NULL, 0) != 0) || - (nng_thread_create(&server, serve, NULL) != 0)) { - fprintf(stderr, "Unable to set up server!\n"); - exit(1); + NUTS_PASS(nng_rep_open(&rep)); + NUTS_PASS(nng_socket_set_int(rep, NNG_OPT_RECVBUF, 256)); + NUTS_PASS(nng_socket_set_int(rep, NNG_OPT_SENDBUF, 256)); + NUTS_PASS(nng_listen(rep, addr, NULL, 0)); + NUTS_PASS(nng_thread_create(&server, serve, NULL)); + + int i; + NUTS_TRUE(openclients(clients, nclients) == 0); + NUTS_TRUE(transact(clients, nclients) == 0); + for (i = 0; i < nclients; i++) { + NUTS_CLOSE(clients[i]); } - - Test("Scalability", { - Convey("We can handle many many clients", { - int i; - So(openclients(clients, nclients) == 0); - So(transact(clients, nclients) == 0); - for (i = 0; i < nclients; i++) { - So(nng_close(clients[i]) == 0); - } - }); - }); - - nng_close(rep); + NUTS_CLOSE(rep); nng_thread_destroy(server); free(clients); free(results); -}) +} + +NUTS_TESTS = { + { "scalability", test_scalability }, + { NULL, NULL }, +}; diff --git a/src/sp/transport/inproc/CMakeLists.txt b/src/sp/transport/inproc/CMakeLists.txt index b84ab01e3..2132e8d7e 100644 --- a/src/sp/transport/inproc/CMakeLists.txt +++ b/src/sp/transport/inproc/CMakeLists.txt @@ -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) diff --git a/src/sp/transport/inproc/inproc_test.c b/src/sp/transport/inproc/inproc_test.c new file mode 100644 index 000000000..2683b1e40 --- /dev/null +++ b/src/sp/transport/inproc/inproc_test.c @@ -0,0 +1,17 @@ +// +// Copyright 2024 Staysail Systems, Inc. +// +// 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_DECLARE_TRAN_TESTS(inproc) + +NUTS_TESTS = { + NUTS_INSERT_TRAN_TESTS(inproc), + { NULL, NULL }, +}; diff --git a/src/sp/transport/tcp/tcp_test.c b/src/sp/transport/tcp/tcp_test.c index 82abcae1b..2b6eb834e 100644 --- a/src/sp/transport/tcp/tcp_test.c +++ b/src/sp/transport/tcp/tcp_test.c @@ -127,42 +127,6 @@ test_tcp_no_delay_option(void) NUTS_CLOSE(s); } -static bool -has_v6(void) -{ - nng_sockaddr sa; - nng_udp *u; - int rv; - - sa.s_in6.sa_family = NNG_AF_INET6; - sa.s_in6.sa_port = 0; - memset(sa.s_in6.sa_addr, 0, 16); - sa.s_in6.sa_addr[15] = 1; - - rv = nng_udp_open(&u, &sa); - if (rv == 0) { - nng_udp_close(u); - } - return (rv == 0 ? 1 : 0); -} - -void -test_tcp_ipv6(void) -{ - if (!has_v6()) { - NUTS_SKIP("No IPv6 support"); - return; - } - nng_socket s; - NUTS_OPEN(s); - // this should have a [::1] bracket - NUTS_FAIL(nng_dial(s, "tcp://::1", NULL, 0), NNG_EINVAL); - NUTS_FAIL(nng_dial(s, "tcp://::1:5055", NULL, 0), NNG_EINVAL); - // this requires a port, but otherwise its ok, so address is invalid - NUTS_FAIL(nng_dial(s, "tcp://[::1]", NULL, 0), NNG_EADDRINVAL); - NUTS_CLOSE(s); -} - void test_tcp_keep_alive_option(void) { @@ -238,8 +202,86 @@ test_tcp_recv_max(void) NUTS_CLOSE(s1); } -NUTS_TESTS = { +static void +check_props_v4(nng_msg *msg) +{ + nng_pipe p; + size_t z; + nng_sockaddr la; + nng_sockaddr ra; + bool b; + + p = nng_msg_get_pipe(msg); + NUTS_TRUE(nng_pipe_id(p) > 0); + NUTS_PASS(nng_pipe_get_addr(p, NNG_OPT_LOCADDR, &la)); + NUTS_FAIL(nng_pipe_get_size(p, NNG_OPT_LOCADDR, &z), NNG_EBADTYPE); + NUTS_TRUE(la.s_family == NNG_AF_INET); + NUTS_TRUE(la.s_in.sa_port != 0); + NUTS_TRUE(la.s_in.sa_addr == nuts_be32(0x7f000001)); + + NUTS_PASS(nng_pipe_get_addr(p, NNG_OPT_REMADDR, &ra)); + NUTS_TRUE(ra.s_family == NNG_AF_INET); + NUTS_TRUE(ra.s_in.sa_port != 0); + NUTS_TRUE(ra.s_in.sa_addr == nuts_be32(0x7f000001)); + NUTS_TRUE(ra.s_in.sa_port != la.s_in.sa_port); + NUTS_FAIL(nng_pipe_get_size(p, NNG_OPT_REMADDR, &z), NNG_EBADTYPE); + + NUTS_PASS(nng_pipe_get_bool(p, NNG_OPT_TCP_KEEPALIVE, &b)); + NUTS_TRUE(b == false); // default + + NUTS_PASS(nng_pipe_get_bool(p, NNG_OPT_TCP_NODELAY, &b)); + NUTS_TRUE(b); // default +} +void +check_props_v6(nng_msg *msg) +{ + nng_pipe p; + size_t z; + nng_sockaddr la; + nng_sockaddr ra; + bool b; + uint8_t self[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; + + p = nng_msg_get_pipe(msg); + NUTS_TRUE(nng_pipe_id(p) > 0); + NUTS_PASS(nng_pipe_get_addr(p, NNG_OPT_LOCADDR, &la)); + NUTS_FAIL(nng_pipe_get_size(p, NNG_OPT_LOCADDR, &z), NNG_EBADTYPE); + NUTS_TRUE(la.s_family == NNG_AF_INET6); + NUTS_TRUE(la.s_in6.sa_port != 0); + NUTS_TRUE(memcmp(la.s_in6.sa_addr, self, 16) == 0); + + NUTS_PASS(nng_pipe_get_addr(p, NNG_OPT_REMADDR, &ra)); + NUTS_TRUE(ra.s_family == NNG_AF_INET6); + NUTS_TRUE(ra.s_in6.sa_port != 0); + NUTS_TRUE(memcmp(ra.s_in6.sa_addr, self, 16) == 0); + NUTS_TRUE(ra.s_in6.sa_port != la.s_in6.sa_port); + NUTS_FAIL(nng_pipe_get_size(p, NNG_OPT_REMADDR, &z), NNG_EBADTYPE); + + NUTS_PASS(nng_pipe_get_bool(p, NNG_OPT_TCP_KEEPALIVE, &b)); + NUTS_TRUE(b == false); // default + + NUTS_PASS(nng_pipe_get_bool(p, NNG_OPT_TCP_NODELAY, &b)); + NUTS_TRUE(b); // default +} + +void +test_tcp_props_v4(void) +{ + nuts_tran_msg_props("tcp4", check_props_v4); +} + +void +test_tcp_props_v6(void) +{ + nuts_tran_msg_props("tcp6", check_props_v6); +} + +NUTS_DECLARE_TRAN_TESTS(tcp) +NUTS_DECLARE_TRAN_TESTS(tcp6) + +NUTS_TESTS = { + NUTS_INSERT_TRAN_TESTS(tcp), { "tcp wild card connect fail", test_tcp_wild_card_connect_fail }, { "tcp wild card bind", test_tcp_wild_card_bind }, { "tcp port zero bind", test_tcp_port_zero_bind }, @@ -248,6 +290,8 @@ NUTS_TESTS = { { "tcp no delay option", test_tcp_no_delay_option }, { "tcp keep alive option", test_tcp_keep_alive_option }, { "tcp recv max", test_tcp_recv_max }, - { "tcp ipv6", test_tcp_ipv6 }, + { "tcp props v4", test_tcp_props_v4 }, + NUTS_INSERT_TRAN_TESTS(tcp6), + { "tcp props v6", test_tcp_props_v6 }, { NULL, NULL }, }; diff --git a/src/sp/transport/ws/ws_test.c b/src/sp/transport/ws/ws_test.c index 514a2d3f3..a05fc18ce 100644 --- a/src/sp/transport/ws/ws_test.c +++ b/src/sp/transport/ws/ws_test.c @@ -195,6 +195,57 @@ test_ws_no_tls(void) NUTS_CLOSE(s0); } +static void +check_props_v4(nng_msg *msg) +{ + nng_pipe p; + size_t z; + nng_sockaddr la; + nng_sockaddr ra; + bool b; + + p = nng_msg_get_pipe(msg); + NUTS_TRUE(nng_pipe_id(p) > 0); + NUTS_PASS(nng_pipe_get_addr(p, NNG_OPT_LOCADDR, &la)); + NUTS_FAIL(nng_pipe_get_size(p, NNG_OPT_LOCADDR, &z), NNG_EBADTYPE); + NUTS_TRUE(la.s_family == NNG_AF_INET); + NUTS_TRUE(la.s_in.sa_port != 0); + NUTS_TRUE(la.s_in.sa_addr == nuts_be32(0x7f000001)); + + NUTS_PASS(nng_pipe_get_addr(p, NNG_OPT_REMADDR, &ra)); + NUTS_TRUE(ra.s_family == NNG_AF_INET); + NUTS_TRUE(ra.s_in.sa_port != 0); + NUTS_TRUE(ra.s_in.sa_addr == nuts_be32(0x7f000001)); + NUTS_TRUE(ra.s_in.sa_port != la.s_in.sa_port); + NUTS_FAIL(nng_pipe_get_size(p, NNG_OPT_REMADDR, &z), NNG_EBADTYPE); + + NUTS_PASS(nng_pipe_get_bool(p, NNG_OPT_TCP_KEEPALIVE, &b)); + NUTS_TRUE(b == false); // default + + NUTS_PASS(nng_pipe_get_bool(p, NNG_OPT_TCP_NODELAY, &b)); + NUTS_TRUE(b); // default + + // Request Header + char *buf = NULL; + NUTS_PASS(nng_pipe_get_string(p, NNG_OPT_WS_REQUEST_HEADERS, &buf)); + NUTS_TRUE(strstr(buf, "Sec-WebSocket-Key") != NULL); + nng_strfree(buf); + + // Response Header + NUTS_PASS(nng_pipe_get_string(p, NNG_OPT_WS_RESPONSE_HEADERS, &buf)); + NUTS_TRUE(strstr(buf, "Sec-WebSocket-Accept") != NULL); + nng_strfree(buf); +} + +void +test_ws_props_v4(void) +{ + nuts_tran_msg_props("ws", check_props_v4); +} + +NUTS_DECLARE_TRAN_TESTS(ws) +NUTS_DECLARE_TRAN_TESTS(ws6) + TEST_LIST = { { "ws url path filters", test_ws_url_path_filters }, { "ws wild card port", test_wild_card_port }, @@ -202,5 +253,8 @@ TEST_LIST = { { "ws empty host", test_empty_host }, { "ws recv max", test_ws_recv_max }, { "ws no tls", test_ws_no_tls }, + NUTS_INSERT_TRAN_TESTS(ws), + { "ws msg props", test_ws_props_v4 }, + NUTS_INSERT_TRAN_TESTS(ws6), { NULL, NULL }, }; diff --git a/src/testing/acutest.h b/src/testing/acutest.h index b64f2f1db..e6efb120e 100644 --- a/src/testing/acutest.h +++ b/src/testing/acutest.h @@ -332,6 +332,8 @@ void acutest_message_(const char* fmt, ...); void acutest_message_color_(int color, const char* fmt, ...); void acutest_dump_(const char* title, const void* addr, size_t size); void acutest_abort_(void) ACUTEST_ATTRIBUTE_(noreturn); +void ACUTEST_ATTRIBUTE_(format (printf, 3, 4)) +acutest_skip_(const char* file, int line, const char* fmt, ...); #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/src/testing/marry.c b/src/testing/marry.c index 7441468ff..8cc944733 100644 --- a/src/testing/marry.c +++ b/src/testing/marry.c @@ -48,16 +48,19 @@ nuts_scratch_addr(const char *scheme, size_t sz, char *addr) 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://127.0.0.1:%u", scheme, nuts_next_port()); + addr, sz, "%s://%s:%u", scheme, ip, nuts_next_port()); return; } if (strncmp(scheme, "ws", 2) == 0) { - (void) snprintf(addr, sz, - "%s://127.0.0.1:%u/nuts%04x%04x%04x%04x", scheme, - nuts_next_port(), nng_random(), nng_random(), nng_random(), - nng_random()); + 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, nuts_next_port(), nng_random(), nng_random(), + nng_random(), nng_random()); return; } diff --git a/src/testing/nuts.h b/src/testing/nuts.h index a61968b8d..5fe193db1 100644 --- a/src/testing/nuts.h +++ b/src/testing/nuts.h @@ -106,6 +106,94 @@ 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_dialer_cancel(const char *scheme); +extern void nuts_tran_dialer_closed(const char *scheme); +extern void nuts_tran_duplicate_listen(const char *scheme); +extern void nuts_tran_listener_cancel(const char *scheme); +extern void nuts_tran_listener_closed(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); + +#define NUTS_SKIP_IF_IPV6_NEEDED_AND_ABSENT(scheme) \ + do { \ + if ((strchr(scheme, '6') != NULL) && (!nuts_has_ipv6())) { \ + NUTS_SKIP("No IPv6 support present"); \ + return; \ + } \ + } while (0) + +#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##_dialer_cancel(void) \ + { \ + nuts_tran_dialer_cancel(#scheme); \ + } \ + void test_##scheme##_dialer_closed(void) \ + { \ + nuts_tran_dialer_closed(#scheme); \ + } \ + void test_##scheme##_duplicate_listen(void) \ + { \ + nuts_tran_duplicate_listen(#scheme); \ + } \ + void test_##scheme##_listener_cancel(void) \ + { \ + nuts_tran_listener_cancel(#scheme); \ + } \ + void test_##scheme##_listener_closed(void) \ + { \ + nuts_tran_listener_closed(#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 " dialer cancel", test_##scheme##_dialer_cancel }, \ + { #scheme " dialer closed", test_##scheme##_dialer_closed }, \ + { #scheme " duplicate listen", test_##scheme##_duplicate_listen }, \ + { #scheme " listener cancel", test_##scheme##_listener_cancel }, \ + { #scheme " listener closed", test_##scheme##_listener_closed }, \ + { #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. diff --git a/src/testing/util.c b/src/testing/util.c index 497598edf..d569bf5f4 100644 --- a/src/testing/util.c +++ b/src/testing/util.c @@ -9,6 +9,7 @@ // #include "nng/nng.h" +#include #define TEST_NO_MAIN #ifdef _WIN32 @@ -41,7 +42,7 @@ #include #endif -#include "nuts.h" +#include uint64_t nuts_clock(void) @@ -171,6 +172,25 @@ nuts_sleep(int msec) #define NUTS_COLOR_GREEN_INTENSIVE_ 4 #define NUTS_COLOR_RED_INTENSIVE_ 5 +bool +nuts_has_ipv6(void) +{ + nng_sockaddr sa = { 0 }; + nng_udp *u; + int rv; + + sa.s_in6.sa_family = NNG_AF_INET6; + sa.s_in6.sa_port = 0; + memset(sa.s_in6.sa_addr, 0, 16); + sa.s_in6.sa_addr[15] = 1; + + rv = nng_udp_open(&u, &sa); + if (rv == 0) { + nng_udp_close(u); + } + return (rv == 0 ? 1 : 0); +} + void nuts_set_logger(int level) { @@ -214,3 +234,344 @@ 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_SKIP_IF_IPV6_NEEDED_AND_ABSENT(scheme); + 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_dialer_cancel(const char *scheme) +{ + nng_socket s = NNG_SOCKET_INITIALIZER; + nng_dialer d = NNG_DIALER_INITIALIZER; + const char *addr; + + NUTS_SKIP_IF_IPV6_NEEDED_AND_ABSENT(scheme); + NUTS_ADDR(addr, scheme); + NUTS_OPEN(s); + NUTS_PASS(nng_dial(s, addr, &d, NNG_FLAG_NONBLOCK)); + NUTS_TRUE(nng_dialer_id(d) > 0); + NUTS_PASS(nng_dialer_close(d)); + NUTS_CLOSE(s); +} + +void +nuts_tran_dialer_closed(const char *scheme) +{ + nng_socket s = NNG_SOCKET_INITIALIZER; + nng_dialer d = NNG_DIALER_INITIALIZER; + const char *addr; + + NUTS_SKIP_IF_IPV6_NEEDED_AND_ABSENT(scheme); + NUTS_ADDR(addr, scheme); + NUTS_OPEN(s); + NUTS_PASS(nng_dialer_create(&d, s, addr)); + NUTS_TRUE(nng_dialer_id(d) > 0); + NUTS_PASS(nng_dialer_close(d)); + NUTS_FAIL(nng_dialer_start(d, 0), NNG_ENOENT); + 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_SKIP_IF_IPV6_NEEDED_AND_ABSENT(scheme); + 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_listener_cancel(const char *scheme) +{ + nng_socket s = NNG_SOCKET_INITIALIZER; + nng_listener l = NNG_LISTENER_INITIALIZER; + const char *addr; + + NUTS_SKIP_IF_IPV6_NEEDED_AND_ABSENT(scheme); + NUTS_ADDR(addr, scheme); + NUTS_OPEN(s); + NUTS_PASS(nng_listen(s, addr, &l, 0)); + NUTS_TRUE(nng_listener_id(l) > 0); + NUTS_PASS(nng_listener_close(l)); + NUTS_CLOSE(s); +} + +void +nuts_tran_listener_closed(const char *scheme) +{ + nng_socket s = NNG_SOCKET_INITIALIZER; + nng_listener l = NNG_LISTENER_INITIALIZER; + const char *addr; + + NUTS_SKIP_IF_IPV6_NEEDED_AND_ABSENT(scheme); + NUTS_ADDR(addr, scheme); + NUTS_OPEN(s); + NUTS_PASS(nng_listener_create(&l, s, addr)); + NUTS_TRUE(nng_listener_id(l) > 0); + NUTS_PASS(nng_listener_close(l)); + NUTS_FAIL(nng_listener_start(l, 0), NNG_ENOENT); + 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_SKIP_IF_IPV6_NEEDED_AND_ABSENT(scheme); + 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_SKIP_IF_IPV6_NEEDED_AND_ABSENT(scheme); + 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_SKIP_IF_IPV6_NEEDED_AND_ABSENT(scheme); + 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_SKIP_IF_IPV6_NEEDED_AND_ABSENT(scheme); + NUTS_ADDR(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_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_SKIP_IF_IPV6_NEEDED_AND_ABSENT(scheme); + 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_SKIP_IF_IPV6_NEEDED_AND_ABSENT(scheme); + 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); + 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, %0.3f us/msg", + (float) (end - now), (end - now) * 1000.0 / (float) num); + NUTS_CLOSE(s1); + NUTS_CLOSE(s2); +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d4e008bd3..268b0808e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -124,25 +124,10 @@ else () endmacro(add_nng_test3) endif () -add_nng_test(device 5) -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(multistress 60) -add_nng_test(nonblock 60) -add_nng_test(pipe 5) -add_nng_test(scalability 20 ON) -add_nng_test(synch 5) -add_nng_test(tcpsupp 10) -add_nng_test(tcp 180) -add_nng_test(tcp6 60) -add_nng_test(ws 30) add_nng_test(wss 30) add_nng_test1(zt 60 NNG_TRANSPORT_ZEROTIER) -add_nng_test(reqstress 60) - # c++ tests add_nng_cpp_test(cplusplus_pair 5) diff --git a/tests/device.c b/tests/device.c deleted file mode 100644 index 53f51ba38..000000000 --- a/tests/device.c +++ /dev/null @@ -1,108 +0,0 @@ -// -// Copyright 2024 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// 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 - -#include -#include - -#include "convey.h" -#include "stubs.h" - -#define APPENDSTR(m, s) nng_msg_append(m, s, strlen(s)) -#define CHECKSTR(m, s) \ - So(nng_msg_len(m) == strlen(s)); \ - So(memcmp(nng_msg_body(m), s, strlen(s)) == 0) - -struct dev_data { - nng_socket s1; - nng_socket s2; -}; - -void -dodev(void *arg) -{ - struct dev_data *d = arg; - - nng_device(d->s1, d->s2); -} - -#define SECOND(x) ((x) *1000) - -Main({ - Test("PAIRv1 device", { - const char *addr1 = "inproc://dev1"; - const char *addr2 = "inproc://dev2"; - - Convey("We cannot create cooked mode device", { - nng_socket s1; - So(nng_pair1_open(&s1) == 0); - Reset({ nng_close(s1); }); - So(nng_device(s1, s1) == NNG_EINVAL); - }); - Convey("We can create a PAIRv1 device", { - nng_socket dev1; - nng_socket dev2; - nng_socket end1; - nng_socket end2; - nng_duration tmo; - nng_msg *msg; - nng_thread *thr; - - So(nng_pair1_open_raw(&dev1) == 0); - So(nng_pair1_open_raw(&dev2) == 0); - - struct dev_data ddata; - ddata.s1 = dev1; - ddata.s2 = dev2; - - So(nng_thread_create(&thr, dodev, &ddata) == 0); - Reset({ - nng_close(dev1); - nng_close(dev2); - nng_thread_destroy(thr); - }); - - So(nng_listen(dev1, addr1, NULL, 0) == 0); - So(nng_listen(dev2, addr2, NULL, 0) == 0); - - So(nng_pair1_open(&end1) == 0); - So(nng_pair1_open(&end2) == 0); - - So(nng_dial(end1, addr1, NULL, 0) == 0); - So(nng_dial(end2, addr2, NULL, 0) == 0); - - tmo = SECOND(1); - So(nng_socket_set_ms(end1, NNG_OPT_RECVTIMEO, tmo) == - 0); - So(nng_socket_set_ms(end2, NNG_OPT_RECVTIMEO, tmo) == - 0); - - nng_msleep(100); - Convey("Device can send and receive", { - So(nng_msg_alloc(&msg, 0) == 0); - APPENDSTR(msg, "ALPHA"); - So(nng_sendmsg(end1, msg, 0) == 0); - So(nng_recvmsg(end2, &msg, 0) == 0); - CHECKSTR(msg, "ALPHA"); - nng_msg_free(msg); - - So(nng_msg_alloc(&msg, 0) == 0); - APPENDSTR(msg, "OMEGA"); - - So(nng_sendmsg(end2, msg, 0) == 0); - So(nng_recvmsg(end1, &msg, 0) == 0); - - CHECKSTR(msg, "OMEGA"); - nng_msg_free(msg); - }); - }); - }); -}) diff --git a/tests/files.c b/tests/files.c deleted file mode 100644 index bf6f704ab..000000000 --- a/tests/files.c +++ /dev/null @@ -1,255 +0,0 @@ -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// 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 "convey.h" -#include "core/nng_impl.h" -#include "stubs.h" - -#include -#include - -#ifdef NNG_PLATFORM_POSIX -#include -#include -#endif - -void -test_permissions(void) -{ -#ifdef NNG_PLATFORM_POSIX - Convey("Permissions work", { - int rv; - char * temp; - char * file; - void * data; - size_t n; - temp = nni_plat_temp_dir(); - So(temp != NULL); - file = nni_file_join(temp, "nng_files_perms_test"); - if (geteuid() == 0) { - ConveySkip("Cannot test permissions as root"); - } - So(nni_file_put(file, "abc", 4) == 0); - Reset({ - nni_file_delete(file); - nni_strfree(file); - nni_strfree(temp); - }); - chmod(file, 0); - So((rv = nni_file_get(file, &data, &n)) != 0); - So(rv == NNG_EPERM); - So(nni_file_put(file, "def", 4) == NNG_EPERM); - }); -#endif -} - -struct walkarg { - int a; - int b; - int c; - int d; - int seen; -}; - -static int -walker(const char *name, void *arg) -{ - struct walkarg *wa = arg; - const char * bn; - - bn = nni_file_basename(name); - if (wa != NULL) { - wa->seen++; - if (strcmp(bn, "a") == 0) { - wa->a++; - } else if (strcmp(bn, "b") == 0) { - wa->b++; - } else if (strcmp(bn, "c") == 0) { - wa->c++; - } else if (strcmp(bn, "d") == 0) { - wa->d++; - } - } - if (strcmp(bn, "stop") == 0) { - return (NNI_FILE_WALK_STOP); - } - if (strcmp(bn, "prunechild") == 0) { - return (NNI_FILE_WALK_PRUNE_CHILD); - } - if (strcmp(bn, "prunesib") == 0) { - return (NNI_FILE_WALK_PRUNE_SIB); - } - return (NNI_FILE_WALK_CONTINUE); -} - -TestMain("Platform File Support", { - Convey("Directory names work", { - char *d; - - So((d = nni_plat_temp_dir()) != NULL); - nni_strfree(d); - - So((d = nni_file_join("a", "b")) != NULL); - So(d[0] == 'a'); - So(d[2] == 'b'); - So(d[3] == '\0'); - So((d[1] == '/') || (d[1] == '\\')); - nni_strfree(d); - }); - - Convey("Can create file in non-existent directory", { - int rv; - char *tmp; - char *d1; - char *d2; - So((tmp = nni_plat_temp_dir()) != NULL); - So((d1 = nni_file_join(tmp, "bogusdir")) != NULL); - So((d2 = nni_file_join(d1, "a")) != NULL); - So((rv = nni_plat_file_put(d2, "", 0)) == 0); - So(nni_file_delete(d2) == 0); - So(nni_file_delete(d1) == 0); - nni_strfree(d2); - nni_strfree(d1); - nni_strfree(tmp); - }); - Convey("Cannot read missing file", { - int rv; - void * data; - size_t n; - So((rv = nni_file_get("/bogus/dir/a", &data, &n)) != 0); - So(rv == NNG_ENOENT); - }); - - Convey("Delete of missing file passes", - { So(nni_file_delete("/bogus/dir/a") == 0); }); - - Convey("Walk of missing directory fails", { - int rv = nni_file_walk("/bogus/dir/a", walker, NULL, 0); - So(rv == NNG_ENOENT); - }); - - Convey("Remove missing directory works", - { So(nni_file_delete("/bogus/nng_does_not_exist") == 0); }); - - Convey("We can create a pair of files", { - char *temp; - char *mydir; - char *a; - char *b; - char *c; - char *d; - temp = nni_plat_temp_dir(); - So(temp != NULL); - mydir = nni_file_join(temp, "nng_files_test"); - So(mydir != NULL); - a = nni_file_join(mydir, "a"); - So(a != NULL); - b = nni_file_join(mydir, "b"); - So(b != NULL); - c = nni_file_join(mydir, "c"); - So(c != NULL); - d = nni_file_join(c, "d"); - So(d != NULL); - - So(nni_file_put(a, "alpha", 6) == 0); - So(nni_file_put(b, "bravo", 6) == 0); - So(nni_file_put(d, "delta", 6) == 0); - - Reset({ - nni_strfree(temp); - nni_file_delete(a); - nni_file_delete(b); - nni_file_delete(d); - nni_file_delete(c); - nni_file_delete(mydir); - nni_strfree(a); - nni_strfree(b); - nni_strfree(c); - nni_strfree(d); - nni_strfree(mydir); - }); - - Convey("Directory walk works", { - struct walkarg wa; - int rv; - - memset(&wa, 0, sizeof(wa)); - rv = nni_file_walk(mydir, walker, &wa, 0); - So(rv == 0); - So(wa.a == 1); - So(wa.b == 1); - So(wa.c == 1); - So(wa.d == 1); - So(wa.seen == 4); - - memset(&wa, 0, sizeof(wa)); - rv = nni_file_walk( - mydir, walker, &wa, NNI_FILE_WALK_FILES_ONLY); - So(rv == 0); - So(wa.a == 1); - So(wa.b == 1); - So(wa.c == 0); - So(wa.d == 1); - So(wa.seen == 3); - - memset(&wa, 0, sizeof(wa)); - rv = nni_file_walk( - mydir, walker, &wa, NNI_FILE_WALK_SHALLOW); - So(rv == 0); - So(wa.a == 1); - So(wa.b == 1); - So(wa.c == 1); - So(wa.d == 0); - So(wa.seen == 3); - - memset(&wa, 0, sizeof(wa)); - rv = nni_file_walk(mydir, walker, &wa, - NNI_FILE_WALK_SHALLOW | NNI_FILE_WALK_FILES_ONLY); - So(rv == 0); - So(wa.a == 1); - So(wa.b == 1); - So(wa.c == 0); - So(wa.d == 0); - So(wa.seen == 2); - }); - - Convey("Contents work", { - void * data; - size_t len; - - So(nni_file_get(a, &data, &len) == 0); - So(len == 6); - So(strcmp(data, "alpha") == 0); - nni_free(data, len); - }); - }); - - Convey("Zero length files work", { - char * temp; - char * empty; - void * data; - size_t n; - temp = nni_plat_temp_dir(); - So(temp != NULL); - empty = nni_file_join(temp, "nng_files_test1"); - So(empty != NULL); - So(nni_file_put(empty, "", 0) == 0); - Reset({ - nni_file_delete(empty); - nni_strfree(empty); - nni_strfree(temp); - }); - So(nni_file_get(empty, &data, &n) == 0); - nni_free(data, n); - So(n == 0); - }); - - test_permissions(); -}) diff --git a/tests/inproc.c b/tests/inproc.c deleted file mode 100644 index 11a6f118d..000000000 --- a/tests/inproc.c +++ /dev/null @@ -1,20 +0,0 @@ -// -// Copyright 2021 Staysail Systems, Inc. -// Copyright 2017 Capitar IT Group BV -// -// 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 "convey.h" -#include "trantest.h" - -#include "core/nng_impl.h" - -// Inproc tests. - -TestMain("Inproc Transport", { - trantest_test_all("inproc://TEST_%u"); -}) diff --git a/tests/ipcsupp.c b/tests/ipcsupp.c deleted file mode 100644 index bd7518852..000000000 --- a/tests/ipcsupp.c +++ /dev/null @@ -1,140 +0,0 @@ -// -// Copyright 2021 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// Copyright 2018 Devolutions -// -// 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 - -#include - -#include "convey.h" -#include "stubs.h" - -static int num = 0; - -TestMain("Supplemental IPC", { - Convey("We can create a dialer and listener", { - nng_stream_dialer * d; - nng_stream_listener *l; - char url[64]; - - snprintf(url, sizeof(url), "ipc:///tmp/ipcsupp_test%d", num); - num++; - So(nng_stream_dialer_alloc(&d, url) == 0); - So(nng_stream_listener_alloc(&l, url) == 0); - Reset({ - nng_stream_listener_close(l); - nng_stream_dialer_close(d); - nng_stream_listener_free(l); - nng_stream_dialer_free(d); - }); - Convey("Listener listens", { - So(nng_stream_listener_listen(l) == 0); - - Convey("We can dial it", { - nng_aio * daio = NULL; - nng_aio * laio = NULL; - nng_aio * maio = NULL; - nng_stream *c1 = NULL; - nng_stream *c2 = NULL; - - So(nng_aio_alloc(&daio, NULL, NULL) == 0); - So(nng_aio_alloc(&laio, NULL, NULL) == 0); - So(nng_aio_alloc(&maio, NULL, NULL) == 0); - - Reset({ - nng_aio_free(daio); - nng_aio_free(laio); - nng_aio_free(maio); - if (c1 != NULL) { - nng_stream_close(c1); - nng_stream_free(c1); - } - if (c2 != NULL) { - nng_stream_close(c2); - nng_stream_free(c2); - } - }); - - nng_stream_dialer_dial(d, daio); - nng_stream_listener_accept(l, laio); - - nng_aio_wait(daio); - nng_aio_wait(laio); - - So(nng_aio_result(daio) == 0); - So(nng_aio_result(laio) == 0); - - c1 = nng_aio_get_output(daio, 0); - c2 = nng_aio_get_output(laio, 0); - So(c1 != NULL); - So(c2 != NULL); - - Convey("They exchange messages", { - nng_aio * aio1; - nng_aio * aio2; - nng_iov iov; - nng_sockaddr sa2; - char buf1[5]; - char buf2[5]; - - So(nng_aio_alloc(&aio1, NULL, NULL) == - 0); - So(nng_aio_alloc(&aio2, NULL, NULL) == - 0); - - Reset({ - nng_aio_free(aio1); - nng_aio_free(aio2); - }); - - // This relies on send completing for - // for just 5 bytes, and on recv doing - // the same. Technically this isn't - // guaranteed, but it would be weird - // to split such a small payload. - memcpy(buf1, "TEST", 5); - memset(buf2, 0, 5); - iov.iov_buf = buf1; - iov.iov_len = 5; - - nng_aio_set_iov(aio1, 1, &iov); - - iov.iov_buf = buf2; - iov.iov_len = 5; - nng_aio_set_iov(aio2, 1, &iov); - nng_stream_send(c1, aio1); - nng_stream_recv(c2, aio2); - nng_aio_wait(aio1); - nng_aio_wait(aio2); - - So(nng_aio_result(aio1) == 0); - So(nng_aio_count(aio1) == 5); - - So(nng_aio_result(aio2) == 0); - So(nng_aio_count(aio2) == 5); - - So(memcmp(buf1, buf2, 5) == 0); - - Convey("Socket name matches", { - So(nng_stream_get_addr(c2, - NNG_OPT_LOCADDR, - &sa2) == 0); - So(sa2.s_ipc.sa_family == - NNG_AF_IPC); - So(strcmp(sa2.s_ipc.sa_path, - url + - strlen("ipc://")) == - 0); - }); - }); - }); - }); - }); -}) diff --git a/tests/pipe.c b/tests/pipe.c deleted file mode 100644 index 665018b0d..000000000 --- a/tests/pipe.c +++ /dev/null @@ -1,248 +0,0 @@ -// -// Copyright 2024 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// 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 -#include - -#include -#include -#include - -#include "convey.h" -#include "stubs.h" - -#define APPENDSTR(m, s) nng_msg_append(m, s, strlen(s)) -#define CHECKSTR(m, s) \ - So(nng_msg_len(m) == strlen(s)); \ - So(memcmp(nng_msg_body(m), s, strlen(s)) == 0) - -struct testcase { - nng_socket s; - nng_dialer d; - nng_listener l; - nng_pipe p; - int add_pre; - int add_post; - int rem; - int err; - int rej; - nng_mtx *lk; - nng_cv *cv; -}; - -static bool -expect(struct testcase *t, int *vp, int v) -{ - bool ok; - nng_time when = nng_clock() + 5000; // five seconds - - nng_mtx_lock(t->lk); - while (*vp != v) { - if (nng_cv_until(t->cv, when) == NNG_ETIMEDOUT) { - break; - } - } - ok = (*vp == v) ? true : false; - if (!ok) { - printf("Expected %d but got %d\n", v, *vp); - } - nng_mtx_unlock(t->lk); - return (ok); -} - -void -notify(nng_pipe p, nng_pipe_ev act, void *arg) -{ - struct testcase *t = arg; - - nng_mtx_lock(t->lk); - if ((nng_socket_id(nng_pipe_socket(p)) != nng_socket_id(t->s)) || - (nng_listener_id(nng_pipe_listener(p)) != nng_listener_id(t->l)) || - (nng_dialer_id(nng_pipe_dialer(p)) != nng_dialer_id(t->d))) { - t->err++; - nng_cv_wake(t->cv); - nng_mtx_unlock(t->lk); - return; - } - if (t->add_post > t->add_pre) { - t->err++; - } - switch (act) { - case NNG_PIPE_EV_ADD_PRE: - t->add_pre++; - break; - case NNG_PIPE_EV_ADD_POST: - t->add_post++; - break; - case NNG_PIPE_EV_REM_POST: - t->rem++; - break; - default: - t->err++; - nng_cv_wake(t->cv); - nng_mtx_unlock(t->lk); - return; - } - t->p = p; - nng_cv_wake(t->cv); - nng_mtx_unlock(t->lk); -} - -void -reject(nng_pipe p, nng_pipe_ev act, void *arg) -{ - struct testcase *t = arg; - notify(p, act, arg); - - nng_mtx_lock(t->lk); - if (!t->rej) { - nng_pipe_close(p); - t->rej++; - } - nng_mtx_unlock(t->lk); -} - -char addr[64]; -static int cnt; - -TestMain("Pipe notify works", { - Convey("We can create a pipeline", { - struct testcase push; - struct testcase pull; - sprintf(addr, "inproc://test%d", cnt++); - - memset(&pull, 0, sizeof(pull)); - memset(&push, 0, sizeof(push)); - So(nng_mtx_alloc(&push.lk) == 0); - So(nng_cv_alloc(&push.cv, push.lk) == 0); - So(nng_mtx_alloc(&pull.lk) == 0); - So(nng_cv_alloc(&pull.cv, pull.lk) == 0); - So(nng_push_open(&push.s) == 0); - So(nng_pull_open(&pull.s) == 0); - - Reset({ - nng_close(push.s); - nng_close(pull.s); - nng_cv_free(push.cv); - nng_cv_free(pull.cv); - nng_mtx_free(push.lk); - nng_mtx_free(pull.lk); - }); - - So(nng_socket_set_ms(push.s, NNG_OPT_RECONNMINT, 10) == 0); - So(nng_socket_set_ms(push.s, NNG_OPT_RECONNMAXT, 10) == 0); - So(nng_socket_set_ms(pull.s, NNG_OPT_RECONNMINT, 10) == 0); - So(nng_socket_set_ms(pull.s, NNG_OPT_RECONNMAXT, 10) == 0); - - So(nng_pipe_notify( - push.s, NNG_PIPE_EV_ADD_PRE, notify, &push) == 0); - So(nng_pipe_notify( - push.s, NNG_PIPE_EV_ADD_POST, notify, &push) == 0); - So(nng_pipe_notify( - push.s, NNG_PIPE_EV_REM_POST, notify, &push) == 0); - So(nng_pipe_notify( - pull.s, NNG_PIPE_EV_ADD_PRE, notify, &pull) == 0); - So(nng_pipe_notify( - pull.s, NNG_PIPE_EV_ADD_POST, notify, &pull) == 0); - So(nng_pipe_notify( - pull.s, NNG_PIPE_EV_REM_POST, notify, &pull) == 0); - - Convey("Dialing works", { - So(nng_listener_create(&pull.l, pull.s, addr) == 0); - So(nng_dialer_create(&push.d, push.s, addr) == 0); - So(nng_listener_id(pull.l) > 0); - So(nng_dialer_id(push.d) > 0); - So(nng_dialer_set_ms(push.d, NNG_OPT_RECONNMINT, 10) == - 0); - So(nng_dialer_set_ms(push.d, NNG_OPT_RECONNMAXT, 10) == - 0); - So(nng_listener_start(pull.l, 0) == 0); - So(nng_dialer_start(push.d, 0) == 0); - So(expect(&pull, &pull.add_pre, 1)); - So(expect(&pull, &pull.add_post, 1)); - So(expect(&pull, &pull.add_pre, 1)); - So(expect(&pull, &pull.add_post, 1)); - So(expect(&pull, &pull.rem, 0)); - So(expect(&pull, &pull.err, 0)); - So(expect(&push, &push.add_pre, 1)); - So(expect(&push, &push.add_post, 1)); - So(expect(&push, &push.rem, 0)); - So(expect(&push, &push.err, 0)); - Convey("We can send a frame", { - nng_msg *msg; - - So(nng_msg_alloc(&msg, 0) == 0); - APPENDSTR(msg, "hello"); - So(nng_sendmsg(push.s, msg, 0) == 0); - msg = NULL; - So(nng_recvmsg(pull.s, &msg, 0) == 0); - So(msg != NULL); - CHECKSTR(msg, "hello"); - So(nng_pipe_id(nng_msg_get_pipe(msg)) == - nng_pipe_id(pull.p)); - nng_msg_free(msg); - }); - - Convey("Reconnection works", { - So(expect(&pull, &pull.add_pre, 1)); - So(expect(&pull, &pull.add_post, 1)); - nng_pipe_close(pull.p); - - So(expect(&pull, &pull.rem, 1)); - So(expect(&pull, &pull.err, 0)); - So(expect(&pull, &pull.add_pre, 2)); - So(expect(&pull, &pull.add_post, 2)); - - So(expect(&push, &push.rem, 1)); - So(expect(&push, &push.err, 0)); - So(expect(&push, &push.add_pre, 2)); - So(expect(&push, &push.add_post, 2)); - - Convey("They still exchange frames", { - nng_msg *msg; - nng_pipe p1; - - nng_msleep(200); - So(nng_msg_alloc(&msg, 0) == 0); - APPENDSTR(msg, "hello"); - So(nng_sendmsg(push.s, msg, 0) == 0); - msg = NULL; - So(nng_recvmsg(pull.s, &msg, 0) == 0); - So(msg != NULL); - CHECKSTR(msg, "hello"); - p1 = nng_msg_get_pipe(msg); - nng_msg_free(msg); - So(nng_pipe_id(p1) == - nng_pipe_id(pull.p)); - }); - }); - }); - - Convey("Reject works", { - So(nng_pipe_notify(pull.s, NNG_PIPE_EV_ADD_PRE, reject, - &pull) == 0); - So(nng_listener_create(&pull.l, pull.s, addr) == 0); - So(nng_dialer_create(&push.d, push.s, addr) == 0); - So(nng_listener_id(pull.l) > 0); - So(nng_dialer_id(push.d) > 0); - So(nng_listener_start(pull.l, 0) == 0); - nng_msleep(100); - So(nng_dialer_start(push.d, 0) == 0); - So(expect(&pull, &pull.add_pre, 2)); - So(expect(&pull, &pull.add_post, 1)); - So(expect(&pull, &pull.rem, 1)); - So(expect(&pull, &pull.err, 0)); - So(expect(&push, &push.add_pre, 2)); - So(expect(&push, &push.add_post, 2)); - So(expect(&push, &push.rem, 1) == 1); - So(expect(&push, &push.err, 0)); - }); - }); -}) diff --git a/tests/synch.c b/tests/synch.c deleted file mode 100644 index c0bf18c97..000000000 --- a/tests/synch.c +++ /dev/null @@ -1,138 +0,0 @@ -// -// Copyright 2022 Staysail Systems, Inc. -// Copyright 2024 Capitar IT Group BV -// -// 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 - -#include "convey.h" - -// Notify tests for verifying condvars. -struct notifyarg { - int did; - nng_duration when; - nng_mtx *mx; - nng_cv *cv; -}; - -void -notifyafter(void *a) -{ - struct notifyarg *na = a; - - nng_msleep(na->when); - nng_mtx_lock(na->mx); - na->did = 1; - nng_cv_wake(na->cv); - nng_mtx_unlock(na->mx); -} - -struct notifyarg arg; -nng_thread *thr; - -static void -test_sync(void) -{ - Convey("Mutexes work", { - nng_mtx *mx; - - So(nng_mtx_alloc(&mx) == 0); - Reset({ nng_mtx_free(mx); }); - - Convey("We can lock and unlock a mutex", { - nng_mtx_lock(mx); - So(1); - nng_mtx_unlock(mx); - So(1); - Convey("And then lock it again", { - nng_mtx_lock(mx); - So(1); - nng_mtx_unlock(mx); - So(1); - }); - }); - Convey("Things block properly", { - So(nng_mtx_alloc(&arg.mx) == 0); - So(nng_cv_alloc(&arg.cv, arg.mx) == 0); - arg.did = 0; - arg.when = 0; - nng_mtx_lock(arg.mx); - So(nng_thread_create(&thr, notifyafter, &arg) == 0); - nng_msleep(10); - So(arg.did == 0); - nng_mtx_unlock(arg.mx); - nng_msleep(10); - nng_mtx_lock(arg.mx); - while (!arg.did) { - nng_cv_wait(arg.cv); - } - So(arg.did != 0); - nng_mtx_unlock(arg.mx); - nng_thread_destroy(thr); - nng_cv_free(arg.cv); - nng_mtx_free(arg.mx); - }) - }); - - Convey("Condition variables work", { - So(nng_mtx_alloc(&arg.mx) == 0); - So(nng_cv_alloc(&arg.cv, arg.mx) == 0); - - Reset({ - nng_cv_free(arg.cv); - nng_mtx_free(arg.mx); - }); - - Convey("Notification works", { - arg.did = 0; - arg.when = 10; - So(nng_thread_create(&thr, notifyafter, &arg) == 0); - - nng_mtx_lock(arg.mx); - if (!arg.did) { - nng_cv_wait(arg.cv); - } - nng_mtx_unlock(arg.mx); - nng_thread_destroy(thr); - So(arg.did == 1); - }); - - Convey("Timeout works", { - arg.did = 0; - arg.when = 200; - So(nng_thread_create(&thr, notifyafter, &arg) == 0); - nng_mtx_lock(arg.mx); - if (!arg.did) { - nng_cv_until(arg.cv, nng_clock() + 10); - } - So(arg.did == 0); - nng_mtx_unlock(arg.mx); - nng_thread_destroy(thr); - }); - - Convey("Empty timeout is EAGAIN", { - nng_mtx_lock(arg.mx); - So(nng_cv_until(arg.cv, 0) == NNG_EAGAIN); - nng_mtx_unlock(arg.mx); - }); - - Convey("Not running works", { - arg.did = 0; - arg.when = 1; - nng_mtx_lock(arg.mx); - if (!arg.did) { - nng_cv_until(arg.cv, nng_clock() + 10); - } - So(arg.did == 0); - nng_mtx_unlock(arg.mx); - }); - }); -} - -TestMain( - "Synchronization", { Convey("Synchronization works", { test_sync(); }); }) diff --git a/tests/tcp.c b/tests/tcp.c deleted file mode 100644 index 2c80035cd..000000000 --- a/tests/tcp.c +++ /dev/null @@ -1,60 +0,0 @@ -// -// Copyright 2022 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// Copyright 2018 Devolutions -// -// 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. -// - -#ifndef _WIN32 -#include -#endif - -#include -#include - -#include "convey.h" -#include "stubs.h" -#include "trantest.h" - -// TCP tests. - -static int -check_props_v4(nng_msg *msg) -{ - nng_pipe p; - size_t z; - nng_sockaddr la; - nng_sockaddr ra; - bool b; - - p = nng_msg_get_pipe(msg); - So(nng_pipe_id(p) > 0); - So(nng_pipe_get_addr(p, NNG_OPT_LOCADDR, &la) == 0); - So(la.s_family == NNG_AF_INET); - So(la.s_in.sa_port == htons(trantest_port - 1)); - So(la.s_in.sa_port != 0); - So(la.s_in.sa_addr == htonl(0x7f000001)); - - // untyped - So(nng_pipe_get_addr(p, NNG_OPT_REMADDR, &ra) == 0); - So(ra.s_family == NNG_AF_INET); - So(ra.s_in.sa_port != 0); - So(ra.s_in.sa_addr == htonl(0x7f000001)); - - So(nng_pipe_get_size(p, NNG_OPT_REMADDR, &z) == NNG_EBADTYPE); - - So(nng_pipe_get_bool(p, NNG_OPT_TCP_KEEPALIVE, &b) == 0); - So(b == false); // default - - So(nng_pipe_get_bool(p, NNG_OPT_TCP_NODELAY, &b) == 0); - So(b == true); // default - - return (0); -} - -TestMain("TCP Transport", - { trantest_test_extended("tcp://127.0.0.1:", check_props_v4); }) diff --git a/tests/tcp6.c b/tests/tcp6.c deleted file mode 100644 index a3ce919ba..000000000 --- a/tests/tcp6.c +++ /dev/null @@ -1,78 +0,0 @@ -// -// Copyright 2022 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// 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. -// - -// TCP tests for IPv6. - -#include -#include - -#include "convey.h" -#include "core/nng_impl.h" -#include "trantest.h" - -#include "stubs.h" - -static int -has_v6(void) -{ - nng_sockaddr sa; - nni_plat_udp *u; - int rv; - - sa.s_in6.sa_family = NNG_AF_INET6; - sa.s_in6.sa_port = 0; - memset(sa.s_in6.sa_addr, 0, 16); - sa.s_in6.sa_addr[15] = 1; - - rv = nni_plat_udp_open(&u, &sa); - if (rv == 0) { - nni_plat_udp_close(u); - } - return (rv == 0 ? 1 : 0); -} - -static int -check_props_v6(nng_msg *msg) -{ - nng_pipe p; - uint8_t loopback[16]; - - memset(loopback, 0, sizeof(loopback)); - loopback[15] = 1; - - // IPv6 Local address property works - nng_sockaddr la; - p = nng_msg_get_pipe(msg); - So(nng_pipe_id(p) > 0); - So(nng_pipe_get_addr(p, NNG_OPT_LOCADDR, &la) == 0); - So(la.s_family == NNG_AF_INET6); - // So(la.s_in.sa_port == (trantest_port - 1)); - So(la.s_in6.sa_port != 0); - So(memcmp(la.s_in6.sa_addr, loopback, 16) == 0); - - // IPv6 Remote address property works - nng_sockaddr ra; - p = nng_msg_get_pipe(msg); - So(nng_pipe_id(p) > 0); - So(nng_pipe_get_addr(p, NNG_OPT_REMADDR, &ra) == 0); - So(ra.s_family == NNG_AF_INET6); - So(ra.s_in6.sa_port != 0); - So(memcmp(ra.s_in6.sa_addr, loopback, 16) == 0); - - return (0); -} - -TestMain("TCP (IPv6) Transport", { - if (has_v6()) { - trantest_test_extended("tcp://[::1]:", check_props_v6); - } else { - SkipSo("IPv6 not available"); - } -}) diff --git a/tests/tcpsupp.c b/tests/tcpsupp.c deleted file mode 100644 index d7d5c38d5..000000000 --- a/tests/tcpsupp.c +++ /dev/null @@ -1,177 +0,0 @@ -// -// Copyright 2024 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// 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 - -#include - -#include "convey.h" -#include "stubs.h" - -TestMain("Supplemental TCP", { - Convey("We can create a dialer and listener", { - nng_stream_dialer *d = NULL; - nng_stream_listener *l = NULL; - Reset({ - nng_stream_listener_free(l); - nng_stream_dialer_free(d); - l = NULL; - d = NULL; - }); - Convey("Listener listens (wildcard)", { - nng_sockaddr sa; - uint8_t ip[4]; - - So(nng_stream_listener_alloc(&l, "tcp://127.0.0.1") == - 0); - So(nng_stream_listener_listen(l) == 0); - - ip[0] = 127; - ip[1] = 0; - ip[2] = 0; - ip[3] = 1; - So(nng_stream_listener_get_addr( - l, NNG_OPT_LOCADDR, &sa) == 0); - So(sa.s_in.sa_port != 0); - So(memcmp(&sa.s_in.sa_addr, ip, 4) == 0); - - Convey("We can dial it", { - nng_aio *daio = NULL; - nng_aio *laio = NULL; - nng_aio *maio = NULL; - nng_stream *c1 = NULL; - nng_stream *c2 = NULL; - - char uri[64]; - snprintf(uri, sizeof(uri), - "tcp://127.0.0.1:%d", - test_htons(sa.s_in.sa_port)); - - So(nng_stream_dialer_alloc(&d, uri) == 0); - So(nng_aio_alloc(&daio, NULL, NULL) == 0); - So(nng_aio_alloc(&laio, NULL, NULL) == 0); - So(nng_aio_alloc(&maio, NULL, NULL) == 0); - - Reset({ - nng_aio_free(daio); - nng_aio_free(laio); - nng_aio_free(maio); - if (c1 != NULL) { - nng_stream_close(c1); - nng_stream_free(c1); - } - if (c2 != NULL) { - nng_stream_close(c2); - nng_stream_free(c2); - } - }); - - nng_stream_dialer_dial(d, daio); - nng_stream_listener_accept(l, laio); - - nng_aio_wait(daio); - So(nng_aio_result(daio) == 0); - nng_aio_wait(laio); - So(nng_aio_result(laio) == 0); - - So(nng_aio_result(daio) == 0); - So(nng_aio_result(laio) == 0); - - c1 = nng_aio_get_output(daio, 0); - c2 = nng_aio_get_output(laio, 0); - So(c1 != NULL); - So(c2 != NULL); - - Convey("They exchange messages", { - nng_aio *aio1; - nng_aio *aio2; - nng_iov iov; - nng_sockaddr sa2; - char buf1[5]; - char buf2[5]; - bool on; - - So(nng_aio_alloc(&aio1, NULL, NULL) == - 0); - So(nng_aio_alloc(&aio2, NULL, NULL) == - 0); - - Reset({ - nng_aio_free(aio1); - nng_aio_free(aio2); - }); - - on = false; - So(nng_stream_get_bool(c1, - NNG_OPT_TCP_NODELAY, &on) == 0); - So(on == true); - - on = false; - So(nng_stream_get_bool(c1, - NNG_OPT_TCP_KEEPALIVE, - &on) == 0); - - // This relies on send completing for - // for just 5 bytes, and on recv doing - // the same. Technically this isn't - // guaranteed, but it would be weird - // to split such a small payload. - memcpy(buf1, "TEST", 5); - memset(buf2, 0, 5); - iov.iov_buf = buf1; - iov.iov_len = 5; - - nng_aio_set_iov(aio1, 1, &iov); - - iov.iov_buf = buf2; - iov.iov_len = 5; - nng_aio_set_iov(aio2, 1, &iov); - nng_stream_send(c1, aio1); - nng_stream_recv(c2, aio2); - nng_aio_wait(aio1); - nng_aio_wait(aio2); - - So(nng_aio_result(aio1) == 0); - So(nng_aio_count(aio1) == 5); - - So(nng_aio_result(aio2) == 0); - So(nng_aio_count(aio2) == 5); - - So(memcmp(buf1, buf2, 5) == 0); - - Convey("Socket name matches", { - So(nng_stream_get_addr(c2, - NNG_OPT_LOCADDR, - &sa2) == 0); - So(sa2.s_in.sa_family == - NNG_AF_INET); - - So(sa2.s_in.sa_addr == - sa.s_in.sa_addr); - So(sa2.s_in.sa_port == - sa.s_in.sa_port); - }); - - Convey("Peer name matches", { - So(nng_stream_get_addr(c1, - NNG_OPT_REMADDR, - &sa2) == 0); - So(sa2.s_in.sa_family == - NNG_AF_INET); - So(sa2.s_in.sa_addr == - sa.s_in.sa_addr); - So(sa2.s_in.sa_port == - sa.s_in.sa_port); - }); - }); - }); - }); - }); -}) diff --git a/tests/ws.c b/tests/ws.c deleted file mode 100644 index 041fe4d00..000000000 --- a/tests/ws.c +++ /dev/null @@ -1,59 +0,0 @@ -// -// Copyright 2024 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// 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. -// - -#ifndef _WIN32 -#include -#endif - -#include -#include - -#include "convey.h" -#include "stubs.h" -#include "trantest.h" - -static int -check_props_v4(nng_msg *msg) -{ - nng_pipe p; - nng_sockaddr la; - nng_sockaddr ra; - char *buf; - - p = nng_msg_get_pipe(msg); - So(nng_pipe_id(p) > 0); - - So(nng_pipe_get_addr(p, NNG_OPT_LOCADDR, &la) == 0); - So(la.s_family == NNG_AF_INET); - So(la.s_in.sa_port == htons(trantest_port - 1)); - So(la.s_in.sa_port != 0); - So(la.s_in.sa_addr == htonl(0x7f000001)); - - So(nng_pipe_get_addr(p, NNG_OPT_REMADDR, &ra) == 0); - So(ra.s_family == NNG_AF_INET); - So(ra.s_in.sa_port != 0); - So(ra.s_in.sa_addr == htonl(0x7f000001)); - - // Request Header - buf = NULL; - So(nng_pipe_get_string(p, NNG_OPT_WS_REQUEST_HEADERS, &buf) == 0); - So(strstr(buf, "Sec-WebSocket-Key") != NULL); - nng_strfree(buf); - - // Response Header - So(nng_pipe_get_string(p, NNG_OPT_WS_RESPONSE_HEADERS, &buf) == 0); - So(strstr(buf, "Sec-WebSocket-Accept") != NULL); - nng_strfree(buf); - - return (0); -} - -TestMain("WebSocket Transport", - { trantest_test_extended("ws://127.0.0.1:", check_props_v4); })