summaryrefslogtreecommitdiff
path: root/src/platform
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2020-11-16 20:44:29 -0800
committerGarrett D'Amore <garrett@damore.org>2020-11-18 21:05:16 -0800
commitb826bfc171d90f8bde7bd672c0ac14201b8b2742 (patch)
tree5c416487f24104e6305a797af31c5e8b1aab99d1 /src/platform
parentcda4885676f009e2e7f2ad5e6c52743efc8b8924 (diff)
downloadnng-b826bfc171d90f8bde7bd672c0ac14201b8b2742.tar.gz
nng-b826bfc171d90f8bde7bd672c0ac14201b8b2742.tar.bz2
nng-b826bfc171d90f8bde7bd672c0ac14201b8b2742.zip
Work for test refactoring.
There are a few major areas in this change. * CMake options are now located in a common cmake/NNGOptions.cmake file. This should make it easier for folks to figure out what the options are, and how they are used. * Tests are now scoped with their directory name, which should avoid possible name collisions with test names. * A number of tests have been either moved or incorporated into the newer testutil/acutest framework. We are moving away from my old c-convey framework to something easier to debug. * We use CMake directories a bit more extensively leading to a much cleaner CMake structure. It's not complete, but a big step in the right direction, and a preview of future work. * Tests are now run with verbose flags, so we get more test results in the CI/CD logs.
Diffstat (limited to 'src/platform')
-rw-r--r--src/platform/CMakeLists.txt17
-rw-r--r--src/platform/platform_test.c181
-rw-r--r--src/platform/posix/posix_file.c13
-rw-r--r--src/platform/resolver_test.c199
4 files changed, 402 insertions, 8 deletions
diff --git a/src/platform/CMakeLists.txt b/src/platform/CMakeLists.txt
new file mode 100644
index 00000000..2b2288e1
--- /dev/null
+++ b/src/platform/CMakeLists.txt
@@ -0,0 +1,17 @@
+#
+# Copyright 2020 Staysail Systems, Inc. <info@staystail.tech>
+#
+# 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.
+#
+
+# Platforms.
+nng_directory(platform)
+
+add_subdirectory(posix)
+add_subdirectory(windows)
+
+nng_test(platform_test)
+nng_test(resolver_test) \ No newline at end of file
diff --git a/src/platform/platform_test.c b/src/platform/platform_test.c
new file mode 100644
index 00000000..e7dcabaa
--- /dev/null
+++ b/src/platform/platform_test.c
@@ -0,0 +1,181 @@
+//
+// Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 Capitar IT Group BV <info@capitar.com>
+//
+// 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 "testutil.h"
+
+#include <nng/nng.h>
+#include <nng/supplemental/util/platform.h>
+
+#include "acutest.h"
+
+struct add_arg {
+ int cnt;
+ nng_mtx *mx;
+ nng_cv * cv;
+};
+
+void
+add(void *arg)
+{
+ struct add_arg *aa = arg;
+
+ nng_mtx_lock(aa->mx);
+ aa->cnt++;
+ nng_cv_wake(aa->cv);
+ nng_mtx_unlock(aa->mx);
+}
+
+void
+test_sleep(void)
+{
+ uint64_t start, end;
+ start = testutil_clock();
+ nng_msleep(100);
+ end = testutil_clock();
+ TEST_CHECK((end - start) >= 100);
+#ifdef __has_feature
+#if !__has_feature(thread_sanitizer) && !__has_feature(memory_sanitizer)
+ TEST_CHECK((end - start) <= 500);
+#endif
+#endif
+}
+
+void
+test_clock(void)
+{
+ uint64_t mstart;
+ uint64_t msend;
+ nng_time usend;
+ nng_time usnow;
+
+ mstart = testutil_clock();
+ usnow = nng_clock();
+ nng_msleep(200);
+ usend = nng_clock();
+ msend = testutil_clock();
+
+ TEST_CHECK(usend > usnow);
+ TEST_CHECK(msend > mstart);
+
+#ifdef __has_feature
+#if !__has_feature(thread_sanitizer) && !__has_feature(memory_sanitizer)
+ uint64_t usdelta;
+ uint64_t msdelta;
+ usdelta = usend - usnow;
+ msdelta = msend - mstart;
+ TEST_CHECK(usdelta >= 200);
+ TEST_CHECK(usdelta < 500); // increased tolerance for CIs
+ if (msdelta > usdelta) {
+ TEST_CHECK((msdelta - usdelta) < 50);
+ } else {
+ TEST_CHECK((usdelta - msdelta) < 50);
+ }
+#endif
+#endif
+}
+
+void
+test_mutex(void)
+{
+ nng_mtx *mx, *mx2;
+
+ TEST_CHECK(nng_mtx_alloc(&mx) == 0);
+ nng_mtx_lock(mx);
+ nng_mtx_unlock(mx);
+
+ nng_mtx_lock(mx);
+ nng_mtx_unlock(mx);
+ nng_mtx_free(mx);
+
+ // Verify that the mutexes are not always the same!
+ TEST_CHECK(nng_mtx_alloc(&mx) == 0);
+ TEST_CHECK(nng_mtx_alloc(&mx2) == 0);
+ TEST_CHECK(mx != mx2);
+ nng_mtx_free(mx);
+ nng_mtx_free(mx2);
+}
+
+void
+test_thread(void)
+{
+ nng_thread * thr;
+ int rv;
+ struct add_arg aa;
+
+ TEST_CHECK(nng_mtx_alloc(&aa.mx) == 0);
+ TEST_CHECK(nng_cv_alloc(&aa.cv, aa.mx) == 0);
+ aa.cnt = 0;
+
+ TEST_CHECK((rv = nng_thread_create(&thr, add, &aa)) == 0);
+ nng_thread_destroy(thr);
+ TEST_CHECK(aa.cnt == 1);
+
+ nng_cv_free(aa.cv);
+ nng_mtx_free(aa.mx);
+}
+
+void
+test_cond_var(void)
+{
+ nng_thread * thr;
+ int rv;
+ struct add_arg aa;
+
+ TEST_CHECK(nng_mtx_alloc(&aa.mx) == 0);
+ TEST_CHECK(nng_cv_alloc(&aa.cv, aa.mx) == 0);
+ aa.cnt = 0;
+
+ TEST_CHECK((rv = nng_thread_create(&thr, add, &aa)) == 0);
+
+ nng_mtx_lock(aa.mx);
+ while (aa.cnt == 0) {
+ nng_cv_wait(aa.cv);
+ }
+ nng_mtx_unlock(aa.mx);
+ nng_thread_destroy(thr);
+ TEST_CHECK(aa.cnt == 1);
+
+ nng_cv_free(aa.cv);
+ nng_mtx_free(aa.mx);
+}
+
+void
+test_random(void)
+{
+ int same = 0;
+ uint32_t values[1000];
+
+ for (int i = 0; i < 1000; i++) {
+ values[i] = nng_random();
+ }
+ for (int i = 0; i < 1000; i++) {
+ for (int j = 0; j < i; j++) {
+ if (values[j] == values[i]) {
+ same++;
+ }
+ }
+ }
+
+ // 1% reproduction is *highly* unlikely.
+ // There are 4 billion possible options, we are only looking at
+ // 1000 of them. In general, it would be an extreme outlier
+ // to see more than 2 repeats, unless you RNG is biased.
+ TEST_CHECK_(same < 5, "fewer than 5 in 1000 repeats: %d", same);
+}
+
+TEST_LIST = {
+ { "sleep", test_sleep },
+ { "clock", test_clock },
+ { "mutex", test_mutex },
+ { "thread", test_thread },
+ { "cond var", test_cond_var },
+ { "random", test_random },
+ { NULL, NULL },
+};
diff --git a/src/platform/posix/posix_file.c b/src/platform/posix/posix_file.c
index 5d918d6b..d5fb5016 100644
--- a/src/platform/posix/posix_file.c
+++ b/src/platform/posix/posix_file.c
@@ -1,5 +1,5 @@
//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This software is supplied under the terms of the MIT License, a
@@ -323,15 +323,12 @@ nni_plat_temp_dir(void)
char *
nni_plat_join_dir(const char *prefix, const char *suffix)
{
- char * newdir;
- size_t len;
+ char *result;
- len = strlen(prefix) + strlen(suffix) + 2;
- newdir = nni_alloc(strlen(prefix) + strlen(suffix) + 2);
- if (newdir != NULL) {
- (void) snprintf(newdir, len, "%s/%s", prefix, suffix);
+ if (nni_asprintf(&result, "%s/%s", prefix, suffix) == 0) {
+ return (result);
}
- return (newdir);
+ return (NULL);
}
#endif // NNG_PLATFORM_POSIX
diff --git a/src/platform/resolver_test.c b/src/platform/resolver_test.c
new file mode 100644
index 00000000..43168cdb
--- /dev/null
+++ b/src/platform/resolver_test.c
@@ -0,0 +1,199 @@
+//
+// Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 Capitar IT Group BV <info@capitar.com>
+//
+// 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 "testutil.h"
+
+#include <string.h>
+
+#include "core/nng_impl.h"
+#include "stubs.h"
+
+#include "acutest.h"
+
+#ifndef _WIN32
+#include <arpa/inet.h> // for htons, htonl
+#endif
+
+uint8_t v6loop[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
+
+void
+test_google_dns(void)
+{
+ nng_aio * aio;
+ nng_sockaddr sa;
+
+ TEST_NNG_PASS(nng_aio_alloc(&aio, NULL, NULL));
+ nni_resolv_ip("google-public-dns-a.google.com", "80", NNG_AF_INET,
+ true, &sa, aio);
+ nng_aio_wait(aio);
+ TEST_NNG_PASS(nng_aio_result(aio));
+ TEST_CHECK(sa.s_in.sa_family == NNG_AF_INET);
+ TEST_CHECK(sa.s_in.sa_port == ntohs(80));
+ TEST_CHECK(sa.s_in.sa_addr == 0x08080808); // aka 8.8.8.8
+ nng_aio_free(aio);
+}
+
+void
+test_numeric_addr(void)
+{
+ nng_aio * aio;
+ nng_sockaddr sa;
+
+ TEST_NNG_PASS(nng_aio_alloc(&aio, NULL, NULL));
+ nni_resolv_ip("8.8.4.4", "69", NNG_AF_INET, true, &sa, aio);
+ nng_aio_wait(aio);
+ TEST_NNG_PASS(nng_aio_result(aio));
+ TEST_CHECK(sa.s_in.sa_family == NNG_AF_INET);
+ TEST_CHECK(sa.s_in.sa_port == ntohs(69));
+ TEST_CHECK(sa.s_in.sa_addr == ntohl(0x08080404)); // 8.8.4.4.
+ nng_aio_free(aio);
+}
+
+void
+test_numeric_v6(void)
+{
+ nng_aio * aio;
+ nng_sockaddr sa;
+
+ // Travis CI has moved some of their services to host that
+ // apparently don't support IPv6 at all. This is very sad.
+ // CircleCI 2.0 is in the same boat. (Amazon to blame.)
+ if ((getenv("TRAVIS") != NULL) || (getenv("CIRCLECI") != NULL)) {
+ return; // skip this one.
+ }
+
+ TEST_NNG_PASS(nng_aio_alloc(&aio, NULL, NULL));
+ nni_resolv_ip("::1", "80", NNG_AF_INET6, true, &sa, aio);
+ nng_aio_wait(aio);
+ TEST_NNG_PASS(nng_aio_result(aio));
+ TEST_CHECK(sa.s_in6.sa_family == NNG_AF_INET6);
+ TEST_CHECK(sa.s_in6.sa_port == ntohs(80));
+ TEST_CHECK(memcmp(sa.s_in6.sa_addr, v6loop, 16) == 0);
+ nng_aio_free(aio);
+}
+
+void
+test_service_names(void)
+{
+ nng_aio * aio;
+ nng_sockaddr sa;
+
+ TEST_NNG_PASS(nng_aio_alloc(&aio, NULL, NULL));
+ nni_resolv_ip("8.8.4.4", "http", NNG_AF_INET, true, &sa, aio);
+ nng_aio_wait(aio);
+ TEST_NNG_PASS(nng_aio_result(aio));
+ TEST_CHECK(sa.s_in.sa_port == ntohs(80));
+ TEST_CHECK(sa.s_in.sa_addr = ntohl(0x08080404));
+ nng_aio_free(aio);
+}
+
+void
+test_localhost_v4(void)
+{
+ nng_aio * aio;
+ nng_sockaddr sa;
+
+ TEST_NNG_PASS(nng_aio_alloc(&aio, NULL, NULL));
+ nni_resolv_ip("localhost", "80", NNG_AF_INET, true, &sa, aio);
+ nng_aio_wait(aio);
+ TEST_NNG_PASS(nng_aio_result(aio));
+ TEST_CHECK(sa.s_in.sa_family == NNG_AF_INET);
+ TEST_CHECK(sa.s_in.sa_port == ntohs(80));
+ TEST_CHECK(sa.s_in.sa_addr == ntohl(0x7f000001));
+ nng_aio_free(aio);
+}
+
+void
+test_localhost_unspec(void)
+{
+ nng_aio * aio;
+ nng_sockaddr sa;
+
+ TEST_NNG_PASS(nng_aio_alloc(&aio, NULL, NULL));
+ nni_resolv_ip("localhost", "80", NNG_AF_UNSPEC, true, &sa, aio);
+ nng_aio_wait(aio);
+ TEST_NNG_PASS(nng_aio_result(aio));
+ TEST_CHECK(
+ (sa.s_family == NNG_AF_INET) || (sa.s_family == NNG_AF_INET6));
+ switch (sa.s_family) {
+ case NNG_AF_INET:
+ TEST_CHECK(sa.s_in.sa_port == ntohs(80));
+ TEST_CHECK(sa.s_in.sa_addr == ntohl(0x7f000001));
+ break;
+ case NNG_AF_INET6:
+ TEST_CHECK(sa.s_in6.sa_port == ntohs(80));
+ TEST_CHECK(memcmp(sa.s_in6.sa_addr, v6loop, 16) == 0);
+ break;
+ }
+ nng_aio_free(aio);
+}
+
+void
+test_null_passive(void)
+{
+ nng_aio * aio;
+ nng_sockaddr sa;
+
+ TEST_NNG_PASS(nng_aio_alloc(&aio, NULL, NULL));
+ nni_resolv_ip(NULL, "80", NNG_AF_INET, true, &sa, aio);
+ nng_aio_wait(aio);
+ TEST_NNG_PASS(nng_aio_result(aio));
+ TEST_CHECK(sa.s_in.sa_family == NNG_AF_INET);
+ TEST_CHECK(sa.s_in.sa_port == ntohs(80));
+ TEST_CHECK(sa.s_in.sa_addr == 0); // INADDR_ANY
+ nng_aio_free(aio);
+}
+
+void
+test_null_not_passive(void)
+{
+ nng_aio * aio;
+ nng_sockaddr sa;
+
+ TEST_NNG_PASS(nng_aio_alloc(&aio, NULL, NULL));
+ nni_resolv_ip(NULL, "80", NNG_AF_INET, false, &sa, aio);
+ nng_aio_wait(aio);
+ // We can either get NNG_EADDRINVAL, or a loopback address.
+ // Most systems do the former, but Linux does the latter.
+ if (nng_aio_result(aio) == 0) {
+ TEST_CHECK(sa.s_family == NNG_AF_INET);
+ TEST_CHECK(sa.s_in.sa_addr == htonl(0x7f000001));
+ TEST_CHECK(sa.s_in.sa_port == htons(80));
+ } else {
+ TEST_NNG_FAIL(nng_aio_result(aio), NNG_EADDRINVAL);
+ }
+ nng_aio_free(aio);
+}
+
+void
+test_bad_port_number(void)
+{
+ nng_aio * aio;
+ nng_sockaddr sa;
+
+ TEST_NNG_PASS(nng_aio_alloc(&aio, NULL, NULL));
+ nni_resolv_ip("1.1.1.1", "1000000", NNG_AF_INET, true, &sa, aio);
+ nng_aio_wait(aio);
+ TEST_NNG_FAIL(nng_aio_result(aio), NNG_EADDRINVAL);
+ nng_aio_free(aio);
+}
+
+TEST_LIST = {
+ { "resolve google dns", test_google_dns },
+ { "resolve numeric addr", test_numeric_addr },
+ { "resolve numeric v6", test_numeric_v6 },
+ { "resolve service names", test_service_names },
+ { "resolve localhost v4", test_localhost_v4 },
+ { "resolve localhost unspec", test_localhost_unspec },
+ { "resolve null passive", test_null_passive },
+ { "resolve null not passive", test_null_not_passive },
+ { "resolve bad port number", test_bad_port_number },
+ { NULL, NULL },
+};