2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-24 11:08:45 +00:00
bind/lib/dns/tests/rbt_test.c

1389 lines
34 KiB
C
Raw Normal View History

/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
2018-10-24 22:12:06 -07:00
#if HAVE_CMOCKA
#include <ctype.h>
#include <fcntl.h>
#include <inttypes.h>
Include <sched.h> where necessary for musl libc All unit tests define the UNIT_TESTING macro, which causes <cmocka.h> to replace malloc(), calloc(), realloc(), and free() with its own functions tracking memory allocations. In order for this not to break compilation, the system header declaring the prototypes for these standard functions must be included before <cmocka.h>. Normally, these prototypes are only present in <stdlib.h>, so we make sure it is included before <cmocka.h>. However, musl libc also defines the prototypes for calloc() and free() in <sched.h>, which is included by <pthread.h>, which is included e.g. by <isc/mutex.h>. Thus, unit tests including "dnstest.h" (which includes <isc/mem.h>, which includes <isc/mutex.h>) after <cmocka.h> will not compile with musl libc as for these programs, <sched.h> will be included after <cmocka.h>. Always including <cmocka.h> after all other header files is not a feasible solution as that causes the mock assertion macros defined in <isc/util.h> to mangle the contents of <cmocka.h>, thus breaking compilation. We cannot really use the __noreturn__ or analyzer_noreturn attributes with cmocka assertion functions because they do return if the tested condition is true. The problem is that what BIND unit tests do is incompatible with Clang Static Analyzer's assumptions: since we use cmocka, our custom assertion handlers are present in a shared library (i.e. it is the cmocka library that checks the assertion condition, not a macro in unit test code). Redefining cmocka's assertion macros in <isc/util.h> is an ugly hack to overcome that problem - unfortunately, this is the only way we can think of to make Clang Static Analyzer properly process unit test code. Giving up on Clang Static Analyzer being able to properly process unit test code is not a satisfactory solution. Undefining _GNU_SOURCE for unit test code could work around the problem (musl libc's <sched.h> only defines the prototypes for calloc() and free() when _GNU_SOURCE is defined), but doing that could introduce discrepancies for unit tests including entire *.c files, so it is also not a good solution. All in all, including <sched.h> before <cmocka.h> for all affected unit tests seems to be the most benign way of working around this musl libc quirk. While quite an ugly solution, it achieves our goals here, which are to keep the benefit of proper static analysis of unit test code and to fix compilation against musl libc.
2019-07-30 21:08:40 +02:00
#include <sched.h> /* IWYU pragma: keep */
#include <setjmp.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
2018-10-24 22:12:06 -07:00
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
2018-10-24 22:12:06 -07:00
#define UNIT_TESTING
#include <cmocka.h>
#include <isc/app.h>
#include <isc/buffer.h>
#include <isc/file.h>
#include <isc/hash.h>
#include <isc/mem.h>
#include <isc/os.h>
2018-10-24 22:12:06 -07:00
#include <isc/print.h>
#include <isc/random.h>
#include <isc/socket.h>
#include <isc/stdio.h>
2018-10-24 22:12:06 -07:00
#include <isc/string.h>
#include <isc/task.h>
2016-03-04 13:58:35 +05:30
#include <isc/thread.h>
2018-10-24 22:12:06 -07:00
#include <isc/time.h>
#include <isc/timer.h>
#include <isc/util.h>
2018-10-24 22:12:06 -07:00
#include <dns/compress.h>
#include <dns/fixedname.h>
#include <dns/log.h>
#include <dns/name.h>
2018-10-24 22:12:06 -07:00
#include <dns/rbt.h>
#include <dns/result.h>
#include <dst/dst.h>
#include "dnstest.h"
typedef struct {
dns_rbt_t *rbt;
dns_rbt_t *rbt_distances;
} test_context_t;
/* The initial structure of domain tree will be as follows:
*
* .
* |
* b
* / \
* a d.e.f
* / | \
* c | g.h
* | |
* w.y i
* / | \ \
* x | z k
* | |
* p j
* / \
* o q
*/
/* The full absolute names of the nodes in the tree (the tree also
* contains "." which is not included in this list).
*/
static const char *const domain_names[] = {
"c", "b", "a", "x.d.e.f",
"z.d.e.f", "g.h", "i.g.h", "o.w.y.d.e.f",
"j.z.d.e.f", "p.w.y.d.e.f", "q.w.y.d.e.f", "k.g.h"
};
static const size_t domain_names_count =
(sizeof(domain_names) / sizeof(domain_names[0]));
/* These are set as the node data for the tree used in distances check
* (for the names in domain_names[] above).
*/
static const int node_distances[] = { 3, 1, 2, 2, 2, 3, 1, 2, 1, 1, 2, 2 };
/*
* The domain order should be:
* ., a, b, c, d.e.f, x.d.e.f, w.y.d.e.f, o.w.y.d.e.f, p.w.y.d.e.f,
* q.w.y.d.e.f, z.d.e.f, j.z.d.e.f, g.h, i.g.h, k.g.h
* . (no data, can't be found)
* |
* b
* / \
* a d.e.f
* / | \
* c | g.h
* | |
* w.y i
* / | \ \
* x | z k
* | |
* p j
* / \
* o q
*/
static const char *const ordered_names[] = {
"a", "b", "c", "d.e.f", "x.d.e.f",
"w.y.d.e.f", "o.w.y.d.e.f", "p.w.y.d.e.f", "q.w.y.d.e.f", "z.d.e.f",
"j.z.d.e.f", "g.h", "i.g.h", "k.g.h"
};
static const size_t ordered_names_count =
(sizeof(ordered_names) / sizeof(*ordered_names));
2018-10-24 22:12:06 -07:00
static int
2020-02-13 14:44:37 -08:00
_setup(void **state) {
2018-10-24 22:12:06 -07:00
isc_result_t result;
UNUSED(state);
result = dns_test_begin(NULL, false);
assert_int_equal(result, ISC_R_SUCCESS);
return (0);
}
static int
2020-02-13 14:44:37 -08:00
_teardown(void **state) {
2018-10-24 22:12:06 -07:00
UNUSED(state);
dns_test_end();
return (0);
}
static void
2020-02-13 14:44:37 -08:00
delete_data(void *data, void *arg) {
UNUSED(arg);
isc_mem_put(dt_mctx, data, sizeof(size_t));
}
static test_context_t *
2020-02-13 14:44:37 -08:00
test_context_setup(void) {
test_context_t *ctx;
2020-02-13 14:44:37 -08:00
isc_result_t result;
size_t i;
2012-06-21 23:46:36 +00:00
ctx = isc_mem_get(dt_mctx, sizeof(*ctx));
2018-10-24 22:12:06 -07:00
assert_non_null(ctx);
ctx->rbt = NULL;
result = dns_rbt_create(dt_mctx, delete_data, NULL, &ctx->rbt);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
2013-05-03 16:01:22 +10:00
ctx->rbt_distances = NULL;
2020-02-13 14:44:37 -08:00
result = dns_rbt_create(dt_mctx, delete_data, NULL,
&ctx->rbt_distances);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
2013-05-09 21:29:57 +10:00
for (i = 0; i < domain_names_count; i++) {
2020-02-13 14:44:37 -08:00
size_t *n;
dns_fixedname_t fname;
2020-02-13 14:44:37 -08:00
dns_name_t *name;
2012-06-21 23:46:36 +00:00
dns_test_namefromstring(domain_names[i], &fname);
name = dns_fixedname_name(&fname);
n = isc_mem_get(dt_mctx, sizeof(size_t));
2018-10-24 22:12:06 -07:00
assert_non_null(n);
*n = i + 1;
result = dns_rbt_addname(ctx->rbt, name, n);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
n = isc_mem_get(dt_mctx, sizeof(size_t));
2018-10-24 22:12:06 -07:00
assert_non_null(n);
*n = node_distances[i];
result = dns_rbt_addname(ctx->rbt_distances, name, n);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
}
return (ctx);
}
static void
2020-02-13 14:44:37 -08:00
test_context_teardown(test_context_t *ctx) {
dns_rbt_destroy(&ctx->rbt);
dns_rbt_destroy(&ctx->rbt_distances);
isc_mem_put(dt_mctx, ctx, sizeof(*ctx));
}
/*
* Walk the tree and ensure that all the test nodes are present.
*/
static void
2020-02-13 14:44:37 -08:00
check_test_data(dns_rbt_t *rbt) {
dns_fixedname_t fixed;
2020-02-13 14:44:37 -08:00
isc_result_t result;
dns_name_t *foundname;
size_t i;
foundname = dns_fixedname_initname(&fixed);
for (i = 0; i < domain_names_count; i++) {
dns_fixedname_t fname;
2020-02-13 14:44:37 -08:00
dns_name_t *name;
size_t *n;
2012-06-21 23:46:36 +00:00
dns_test_namefromstring(domain_names[i], &fname);
2012-06-21 23:46:36 +00:00
name = dns_fixedname_name(&fname);
n = NULL;
result = dns_rbt_findname(rbt, name, 0, foundname, (void *)&n);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
assert_int_equal(*n, i + 1);
}
}
2018-10-24 22:12:06 -07:00
/* Test the creation of an rbt */
static void
2020-02-13 14:44:37 -08:00
rbt_create(void **state) {
test_context_t *ctx;
2020-02-13 14:44:37 -08:00
bool tree_ok;
2018-10-24 22:12:06 -07:00
UNUSED(state);
isc_mem_debugging = ISC_MEM_DEBUGRECORD;
ctx = test_context_setup();
check_test_data(ctx->rbt);
tree_ok = dns__rbt_checkproperties(ctx->rbt);
2018-10-24 22:12:06 -07:00
assert_true(tree_ok);
test_context_teardown(ctx);
}
2018-10-24 22:12:06 -07:00
/* Test dns_rbt_nodecount() on a tree */
static void
2020-02-13 14:44:37 -08:00
rbt_nodecount(void **state) {
test_context_t *ctx;
2018-10-24 22:12:06 -07:00
UNUSED(state);
isc_mem_debugging = ISC_MEM_DEBUGRECORD;
ctx = test_context_setup();
2018-10-24 22:12:06 -07:00
assert_int_equal(15, dns_rbt_nodecount(ctx->rbt));
test_context_teardown(ctx);
}
2018-10-24 22:12:06 -07:00
/* Test dns_rbtnode_get_distance() on a tree */
static void
2020-02-13 14:44:37 -08:00
rbtnode_get_distance(void **state) {
isc_result_t result;
test_context_t *ctx;
const char *name_str = "a";
dns_fixedname_t fname;
dns_name_t *name;
dns_rbtnode_t *node = NULL;
dns_rbtnodechain_t chain;
2012-06-21 23:46:36 +00:00
2018-10-24 22:12:06 -07:00
UNUSED(state);
2012-06-21 23:46:36 +00:00
isc_mem_debugging = ISC_MEM_DEBUGRECORD;
ctx = test_context_setup();
dns_test_namefromstring(name_str, &fname);
name = dns_fixedname_name(&fname);
dns_rbtnodechain_init(&chain);
result = dns_rbt_findnode(ctx->rbt_distances, name, NULL, &node, &chain,
0, NULL, NULL);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
2012-06-21 23:46:36 +00:00
while (node != NULL) {
const size_t *distance = (const size_t *)node->data;
if (distance != NULL) {
2018-10-24 22:12:06 -07:00
assert_int_equal(*distance,
dns__rbtnode_getdistance(node));
}
result = dns_rbtnodechain_next(&chain, NULL, NULL);
if (result == ISC_R_NOMORE) {
break;
}
dns_rbtnodechain_current(&chain, NULL, NULL, &node);
}
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_NOMORE);
dns_rbtnodechain_invalidate(&chain);
test_context_teardown(ctx);
}
2018-10-24 22:12:06 -07:00
/*
* Test tree balance, inserting names in random order.
*
* This test checks an important performance-related property of
* the red-black tree, which is important for us: the longest
* path from a sub-tree's root to a node is no more than
* 2log(n). This check verifies that the tree is balanced.
*/
static void
2020-02-13 14:44:37 -08:00
rbt_check_distance_random(void **state) {
dns_rbt_t *mytree = NULL;
2014-06-25 00:19:17 +10:00
const unsigned int log_num_nodes = 16;
2020-02-13 14:44:37 -08:00
isc_result_t result;
bool tree_ok;
int i;
2018-10-24 22:12:06 -07:00
UNUSED(state);
isc_mem_debugging = ISC_MEM_DEBUGRECORD;
result = dns_rbt_create(dt_mctx, delete_data, NULL, &mytree);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
/* Names are inserted in random order. */
/* Make a large 65536 node top-level domain tree, i.e., the
* following code inserts names such as:
*
* savoucnsrkrqzpkqypbygwoiliawpbmz.
* wkadamcbbpjtundbxcmuayuycposvngx.
* wzbpznemtooxdpjecdxynsfztvnuyfao.
* yueojmhyffslpvfmgyfwioxegfhepnqq.
*/
for (i = 0; i < (1 << log_num_nodes); i++) {
size_t *n;
2020-02-13 14:44:37 -08:00
char namebuf[34];
n = isc_mem_get(dt_mctx, sizeof(size_t));
2018-10-24 22:12:06 -07:00
assert_non_null(n);
*n = i + 1;
while (1) {
2020-02-13 14:44:37 -08:00
int j;
dns_fixedname_t fname;
2020-02-13 14:44:37 -08:00
dns_name_t *name;
for (j = 0; j < 32; j++) {
uint32_t v = isc_random_uniform(26);
namebuf[j] = 'a' + v;
}
namebuf[32] = '.';
namebuf[33] = 0;
dns_test_namefromstring(namebuf, &fname);
name = dns_fixedname_name(&fname);
result = dns_rbt_addname(mytree, name, n);
if (result == ISC_R_SUCCESS) {
break;
}
}
}
/* 1 (root . node) + (1 << log_num_nodes) */
assert_int_equal(1U + (1U << log_num_nodes), dns_rbt_nodecount(mytree));
/* The distance from each node to its sub-tree root must be less
* than 2 * log(n).
*/
2018-10-24 22:12:06 -07:00
assert_true((2U * log_num_nodes) >= dns__rbt_getheight(mytree));
/* Also check RB tree properties */
tree_ok = dns__rbt_checkproperties(mytree);
2018-10-24 22:12:06 -07:00
assert_true(tree_ok);
dns_rbt_destroy(&mytree);
}
2018-10-24 22:12:06 -07:00
/*
* Test tree balance, inserting names in sorted order.
*
* This test checks an important performance-related property of
* the red-black tree, which is important for us: the longest
* path from a sub-tree's root to a node is no more than
* 2log(n). This check verifies that the tree is balanced.
*/
static void
2020-02-13 14:44:37 -08:00
rbt_check_distance_ordered(void **state) {
dns_rbt_t *mytree = NULL;
2014-06-25 00:19:17 +10:00
const unsigned int log_num_nodes = 16;
2020-02-13 14:44:37 -08:00
isc_result_t result;
bool tree_ok;
int i;
2012-06-21 23:46:36 +00:00
2018-10-24 22:12:06 -07:00
UNUSED(state);
isc_mem_debugging = ISC_MEM_DEBUGRECORD;
2012-06-21 23:46:36 +00:00
result = dns_rbt_create(dt_mctx, delete_data, NULL, &mytree);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
2012-06-21 23:46:36 +00:00
/* Names are inserted in sorted order. */
/* Make a large 65536 node top-level domain tree, i.e., the
* following code inserts names such as:
*
* name00000000.
* name00000001.
* name00000002.
* name00000003.
*/
for (i = 0; i < (1 << log_num_nodes); i++) {
2020-02-13 14:44:37 -08:00
size_t *n;
char namebuf[14];
dns_fixedname_t fname;
2020-02-13 14:44:37 -08:00
dns_name_t *name;
2012-06-21 23:46:36 +00:00
n = isc_mem_get(dt_mctx, sizeof(size_t));
2018-10-24 22:12:06 -07:00
assert_non_null(n);
*n = i + 1;
snprintf(namebuf, sizeof(namebuf), "name%08x.", i);
dns_test_namefromstring(namebuf, &fname);
name = dns_fixedname_name(&fname);
result = dns_rbt_addname(mytree, name, n);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
}
/* 1 (root . node) + (1 << log_num_nodes) */
assert_int_equal(1U + (1U << log_num_nodes), dns_rbt_nodecount(mytree));
/* The distance from each node to its sub-tree root must be less
* than 2 * log(n).
*/
2018-10-24 22:12:06 -07:00
assert_true((2U * log_num_nodes) >= dns__rbt_getheight(mytree));
/* Also check RB tree properties */
tree_ok = dns__rbt_checkproperties(mytree);
2018-10-24 22:12:06 -07:00
assert_true(tree_ok);
dns_rbt_destroy(&mytree);
}
static isc_result_t
2020-02-13 14:44:37 -08:00
insert_helper(dns_rbt_t *rbt, const char *namestr, dns_rbtnode_t **node) {
dns_fixedname_t fname;
2020-02-13 14:44:37 -08:00
dns_name_t *name;
dns_test_namefromstring(namestr, &fname);
name = dns_fixedname_name(&fname);
return (dns_rbt_addnode(rbt, name, node));
}
static bool
2020-02-13 14:44:37 -08:00
compare_labelsequences(dns_rbtnode_t *node, const char *labelstr) {
dns_name_t name;
isc_result_t result;
2020-02-13 14:44:37 -08:00
char *nodestr = NULL;
bool is_equal;
dns_name_init(&name, NULL);
dns_rbt_namefromnode(node, &name);
result = dns_name_tostring(&name, &nodestr, dt_mctx);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
is_equal = strcmp(labelstr, nodestr) == 0 ? true : false;
isc_mem_free(dt_mctx, nodestr);
return (is_equal);
}
2018-10-24 22:12:06 -07:00
/* Test insertion into a tree */
static void
2020-02-13 14:44:37 -08:00
rbt_insert(void **state) {
isc_result_t result;
test_context_t *ctx;
2020-02-13 14:44:37 -08:00
dns_rbtnode_t *node;
2012-06-21 23:46:36 +00:00
2018-10-24 22:12:06 -07:00
UNUSED(state);
isc_mem_debugging = ISC_MEM_DEBUGRECORD;
2012-06-21 23:46:36 +00:00
ctx = test_context_setup();
2012-06-21 23:46:36 +00:00
/* Check node count before beginning. */
2018-10-24 22:12:06 -07:00
assert_int_equal(15, dns_rbt_nodecount(ctx->rbt));
/* Try to insert a node that already exists. */
node = NULL;
result = insert_helper(ctx->rbt, "d.e.f", &node);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_EXISTS);
/* Node count must not have changed. */
2018-10-24 22:12:06 -07:00
assert_int_equal(15, dns_rbt_nodecount(ctx->rbt));
/* Try to insert a node that doesn't exist. */
node = NULL;
result = insert_helper(ctx->rbt, "0", &node);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
assert_true(compare_labelsequences(node, "0"));
/* Node count must have increased. */
2018-10-24 22:12:06 -07:00
assert_int_equal(16, dns_rbt_nodecount(ctx->rbt));
/* Another. */
node = NULL;
result = insert_helper(ctx->rbt, "example.com", &node);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
assert_non_null(node);
assert_null(node->data);
/* Node count must have increased. */
2018-10-24 22:12:06 -07:00
assert_int_equal(17, dns_rbt_nodecount(ctx->rbt));
/* Re-adding it should return EXISTS */
node = NULL;
result = insert_helper(ctx->rbt, "example.com", &node);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_EXISTS);
/* Node count must not have changed. */
2018-10-24 22:12:06 -07:00
assert_int_equal(17, dns_rbt_nodecount(ctx->rbt));
/* Fission the node d.e.f */
node = NULL;
result = insert_helper(ctx->rbt, "k.e.f", &node);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
assert_true(compare_labelsequences(node, "k"));
/* Node count must have incremented twice ("d.e.f" fissioned to
* "d" and "e.f", and the newly added "k").
*/
2018-10-24 22:12:06 -07:00
assert_int_equal(19, dns_rbt_nodecount(ctx->rbt));
/* Fission the node "g.h" */
node = NULL;
result = insert_helper(ctx->rbt, "h", &node);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
assert_true(compare_labelsequences(node, "h"));
/* Node count must have incremented ("g.h" fissioned to "g" and
* "h").
*/
2018-10-24 22:12:06 -07:00
assert_int_equal(20, dns_rbt_nodecount(ctx->rbt));
/* Add child domains */
node = NULL;
result = insert_helper(ctx->rbt, "m.p.w.y.d.e.f", &node);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
assert_true(compare_labelsequences(node, "m"));
assert_int_equal(21, dns_rbt_nodecount(ctx->rbt));
node = NULL;
result = insert_helper(ctx->rbt, "n.p.w.y.d.e.f", &node);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
assert_true(compare_labelsequences(node, "n"));
assert_int_equal(22, dns_rbt_nodecount(ctx->rbt));
node = NULL;
result = insert_helper(ctx->rbt, "l.a", &node);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
assert_true(compare_labelsequences(node, "l"));
assert_int_equal(23, dns_rbt_nodecount(ctx->rbt));
node = NULL;
result = insert_helper(ctx->rbt, "r.d.e.f", &node);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
node = NULL;
result = insert_helper(ctx->rbt, "s.d.e.f", &node);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
assert_int_equal(25, dns_rbt_nodecount(ctx->rbt));
node = NULL;
result = insert_helper(ctx->rbt, "h.w.y.d.e.f", &node);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
/* Add more nodes one by one to cover left and right rotation
* functions.
*/
node = NULL;
result = insert_helper(ctx->rbt, "f", &node);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
node = NULL;
result = insert_helper(ctx->rbt, "m", &node);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
node = NULL;
result = insert_helper(ctx->rbt, "nm", &node);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
node = NULL;
result = insert_helper(ctx->rbt, "om", &node);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
node = NULL;
result = insert_helper(ctx->rbt, "k", &node);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
node = NULL;
result = insert_helper(ctx->rbt, "l", &node);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
node = NULL;
result = insert_helper(ctx->rbt, "fe", &node);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
node = NULL;
result = insert_helper(ctx->rbt, "ge", &node);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
node = NULL;
result = insert_helper(ctx->rbt, "i", &node);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
2012-06-21 23:46:36 +00:00
node = NULL;
result = insert_helper(ctx->rbt, "ae", &node);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
node = NULL;
result = insert_helper(ctx->rbt, "n", &node);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
test_context_teardown(ctx);
}
2018-10-24 22:12:06 -07:00
/*
* Test removal from a tree
*
* This testcase checks that after node removal, the binary-search tree is
* valid and all nodes that are supposed to exist are present in the
* correct order. It mainly tests DomainTree as a BST, and not particularly
* as a red-black tree. This test checks node deletion when upper nodes
* have data.
*/
static void
2020-02-13 14:44:37 -08:00
rbt_remove(void **state) {
isc_result_t result;
2020-02-13 14:44:37 -08:00
size_t j;
2018-10-24 22:12:06 -07:00
UNUSED(state);
isc_mem_debugging = ISC_MEM_DEBUGRECORD;
/*
* Delete single nodes and check if the rest of the nodes exist.
*/
for (j = 0; j < ordered_names_count; j++) {
2020-02-13 14:44:37 -08:00
dns_rbt_t *mytree = NULL;
dns_rbtnode_t *node;
size_t i;
size_t *n;
bool tree_ok;
dns_rbtnodechain_t chain;
2020-02-13 14:44:37 -08:00
size_t start_node;
/* Create a tree. */
result = dns_rbt_create(dt_mctx, delete_data, NULL, &mytree);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
/* Insert test data into the tree. */
for (i = 0; i < domain_names_count; i++) {
node = NULL;
result = insert_helper(mytree, domain_names[i], &node);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
}
/* Check that all names exist in order. */
for (i = 0; i < ordered_names_count; i++) {
dns_fixedname_t fname;
2020-02-13 14:44:37 -08:00
dns_name_t *name;
dns_test_namefromstring(ordered_names[i], &fname);
name = dns_fixedname_name(&fname);
node = NULL;
result = dns_rbt_findnode(mytree, name, NULL, &node,
NULL, DNS_RBTFIND_EMPTYDATA,
NULL, NULL);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
/* Add node data */
2018-10-24 22:12:06 -07:00
assert_non_null(node);
assert_null(node->data);
n = isc_mem_get(dt_mctx, sizeof(size_t));
2018-10-24 22:12:06 -07:00
assert_non_null(n);
*n = i;
node->data = n;
}
/* Now, delete the j'th node from the tree. */
{
dns_fixedname_t fname;
2020-02-13 14:44:37 -08:00
dns_name_t *name;
dns_test_namefromstring(ordered_names[j], &fname);
name = dns_fixedname_name(&fname);
result = dns_rbt_deletename(mytree, name, false);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
}
/* Check RB tree properties. */
tree_ok = dns__rbt_checkproperties(mytree);
2018-10-24 22:12:06 -07:00
assert_true(tree_ok);
dns_rbtnodechain_init(&chain);
/* Now, walk through nodes in order. */
if (j == 0) {
/*
* Node for ordered_names[0] was already deleted
* above. We start from node 1.
*/
dns_fixedname_t fname;
2020-02-13 14:44:37 -08:00
dns_name_t *name;
dns_test_namefromstring(ordered_names[0], &fname);
name = dns_fixedname_name(&fname);
node = NULL;
result = dns_rbt_findnode(mytree, name, NULL, &node,
NULL, 0, NULL, NULL);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_NOTFOUND);
dns_test_namefromstring(ordered_names[1], &fname);
name = dns_fixedname_name(&fname);
node = NULL;
result = dns_rbt_findnode(mytree, name, NULL, &node,
&chain, 0, NULL, NULL);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
start_node = 1;
} else {
/* Start from node 0. */
dns_fixedname_t fname;
2020-02-13 14:44:37 -08:00
dns_name_t *name;
dns_test_namefromstring(ordered_names[0], &fname);
name = dns_fixedname_name(&fname);
node = NULL;
result = dns_rbt_findnode(mytree, name, NULL, &node,
&chain, 0, NULL, NULL);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
start_node = 0;
}
/*
* node and chain have been set by the code above at
* this point.
*/
for (i = start_node; i < ordered_names_count; i++) {
dns_fixedname_t fname_j, fname_i;
2020-02-13 14:44:37 -08:00
dns_name_t *name_j, *name_i;
dns_test_namefromstring(ordered_names[j], &fname_j);
name_j = dns_fixedname_name(&fname_j);
dns_test_namefromstring(ordered_names[i], &fname_i);
name_i = dns_fixedname_name(&fname_i);
if (dns_name_equal(name_i, name_j)) {
/*
* This may be true for the last node if
* we seek ahead in the loop using
* dns_rbtnodechain_next() below.
*/
if (node == NULL) {
break;
}
/* All ordered nodes have data
* initially. If any node is empty, it
* means it was removed, but an empty
* node exists because it is a
* super-domain. Just skip it.
*/
if (node->data == NULL) {
result = dns_rbtnodechain_next(
&chain, NULL, NULL);
if (result == ISC_R_NOMORE) {
node = NULL;
} else {
dns_rbtnodechain_current(
&chain, NULL, NULL,
&node);
}
}
continue;
}
2018-10-24 22:12:06 -07:00
assert_non_null(node);
n = (size_t *)node->data;
if (n != NULL) {
/* printf("n=%zu, i=%zu\n", *n, i); */
2018-10-24 22:12:06 -07:00
assert_int_equal(*n, i);
}
result = dns_rbtnodechain_next(&chain, NULL, NULL);
if (result == ISC_R_NOMORE) {
node = NULL;
} else {
dns_rbtnodechain_current(&chain, NULL, NULL,
&node);
}
}
/* We should have reached the end of the tree. */
2018-10-24 22:12:06 -07:00
assert_null(node);
dns_rbt_destroy(&mytree);
}
}
static void
insert_nodes(dns_rbt_t *mytree, char **names, size_t *names_count,
2020-02-13 14:44:37 -08:00
uint32_t num_names) {
uint32_t i;
dns_rbtnode_t *node;
for (i = 0; i < num_names; i++) {
size_t *n;
2020-02-13 14:44:37 -08:00
char namebuf[34];
n = isc_mem_get(dt_mctx, sizeof(size_t));
2018-10-24 22:12:06 -07:00
assert_non_null(n);
*n = i; /* Unused value */
while (1) {
2020-02-13 14:44:37 -08:00
int j;
dns_fixedname_t fname;
2020-02-13 14:44:37 -08:00
dns_name_t *name;
isc_result_t result;
for (j = 0; j < 32; j++) {
uint32_t v = isc_random_uniform(26);
namebuf[j] = 'a' + v;
}
namebuf[32] = '.';
namebuf[33] = 0;
dns_test_namefromstring(namebuf, &fname);
name = dns_fixedname_name(&fname);
node = NULL;
result = dns_rbt_addnode(mytree, name, &node);
if (result == ISC_R_SUCCESS) {
node->data = n;
2020-02-13 14:44:37 -08:00
names[*names_count] = isc_mem_strdup(dt_mctx,
namebuf);
2018-10-24 22:12:06 -07:00
assert_non_null(names[*names_count]);
*names_count += 1;
break;
}
}
}
}
static void
remove_nodes(dns_rbt_t *mytree, char **names, size_t *names_count,
2020-02-13 14:44:37 -08:00
uint32_t num_names) {
uint32_t i;
UNUSED(mytree);
for (i = 0; i < num_names; i++) {
2020-02-13 14:44:37 -08:00
uint32_t node;
dns_fixedname_t fname;
2020-02-13 14:44:37 -08:00
dns_name_t *name;
isc_result_t result;
node = isc_random_uniform(*names_count);
dns_test_namefromstring(names[node], &fname);
name = dns_fixedname_name(&fname);
result = dns_rbt_deletename(mytree, name, false);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
isc_mem_free(dt_mctx, names[node]);
if (*names_count > 0) {
names[node] = names[*names_count - 1];
names[*names_count - 1] = NULL;
*names_count -= 1;
}
}
}
static void
2020-02-13 14:44:37 -08:00
check_tree(dns_rbt_t *mytree, char **names, size_t names_count) {
bool tree_ok;
UNUSED(names);
2018-10-24 22:12:06 -07:00
assert_int_equal(names_count + 1, dns_rbt_nodecount(mytree));
/*
* The distance from each node to its sub-tree root must be less
* than 2 * log_2(1024).
*/
2018-10-24 22:12:06 -07:00
assert_true((2 * 10) >= dns__rbt_getheight(mytree));
/* Also check RB tree properties */
tree_ok = dns__rbt_checkproperties(mytree);
2018-10-24 22:12:06 -07:00
assert_true(tree_ok);
}
2018-10-24 22:12:06 -07:00
/*
* Test insert and remove in a loop.
*
* What is the best way to test our red-black tree code? It is
* not a good method to test every case handled in the actual
* code itself. This is because our approach itself may be
* incorrect.
*
* We test our code at the interface level here by exercising the
* tree randomly multiple times, checking that red-black tree
* properties are valid, and all the nodes that are supposed to be
* in the tree exist and are in order.
*
* NOTE: These tests are run within a single tree level in the
* forest. The number of nodes in the tree level doesn't grow
* over 1024.
*/
static void
2020-02-13 14:44:37 -08:00
rbt_insert_and_remove(void **state) {
isc_result_t result;
2020-02-13 14:44:37 -08:00
dns_rbt_t *mytree = NULL;
size_t *n;
char *names[1024];
size_t names_count;
int i;
2018-10-24 22:12:06 -07:00
UNUSED(state);
2012-06-21 23:46:36 +00:00
isc_mem_debugging = ISC_MEM_DEBUGRECORD;
result = dns_rbt_create(dt_mctx, delete_data, NULL, &mytree);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
n = isc_mem_get(dt_mctx, sizeof(size_t));
2018-10-24 22:12:06 -07:00
assert_non_null(n);
result = dns_rbt_addname(mytree, dns_rootname, n);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
memset(names, 0, sizeof(names));
names_count = 0;
/* Repeat the insert/remove test some 4096 times */
for (i = 0; i < 4096; i++) {
uint32_t num_names;
if (names_count < 1024) {
num_names = isc_random_uniform(1024 - names_count);
num_names++;
} else {
num_names = 0;
}
insert_nodes(mytree, names, &names_count, num_names);
2018-10-24 22:12:06 -07:00
check_tree(mytree, names, names_count);
if (names_count > 0) {
num_names = isc_random_uniform(names_count);
num_names++;
} else {
num_names = 0;
}
remove_nodes(mytree, names, &names_count, num_names);
2018-10-24 22:12:06 -07:00
check_tree(mytree, names, names_count);
}
/* Remove the rest of the nodes */
remove_nodes(mytree, names, &names_count, names_count);
2018-10-24 22:12:06 -07:00
check_tree(mytree, names, names_count);
for (i = 0; i < 1024; i++) {
if (names[i] != NULL) {
isc_mem_free(dt_mctx, names[i]);
}
}
result = dns_rbt_deletename(mytree, dns_rootname, false);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
assert_int_equal(dns_rbt_nodecount(mytree), 0);
dns_rbt_destroy(&mytree);
}
2018-10-24 22:12:06 -07:00
/* Test findname return values */
static void
2020-02-13 14:44:37 -08:00
rbt_findname(void **state) {
isc_result_t result;
test_context_t *ctx = NULL;
dns_fixedname_t fname, found;
2020-02-13 14:44:37 -08:00
dns_name_t *name = NULL, *foundname = NULL;
size_t *n = NULL;
2018-10-24 22:12:06 -07:00
UNUSED(state);
isc_mem_debugging = ISC_MEM_DEBUGRECORD;
ctx = test_context_setup();
/* Try to find a name that exists. */
dns_test_namefromstring("d.e.f", &fname);
name = dns_fixedname_name(&fname);
foundname = dns_fixedname_initname(&found);
result = dns_rbt_findname(ctx->rbt, name, DNS_RBTFIND_EMPTYDATA,
foundname, (void *)&n);
2018-10-24 22:12:06 -07:00
assert_true(dns_name_equal(foundname, name));
assert_int_equal(result, ISC_R_SUCCESS);
/* Now without EMPTYDATA */
result = dns_rbt_findname(ctx->rbt, name, 0, foundname, (void *)&n);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_NOTFOUND);
/* Now one that partially matches */
dns_test_namefromstring("d.e.f.g.h.i.j", &fname);
name = dns_fixedname_name(&fname);
result = dns_rbt_findname(ctx->rbt, name, DNS_RBTFIND_EMPTYDATA,
foundname, (void *)&n);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, DNS_R_PARTIALMATCH);
/* Now one that doesn't match */
dns_test_namefromstring("1.2", &fname);
name = dns_fixedname_name(&fname);
result = dns_rbt_findname(ctx->rbt, name, DNS_RBTFIND_EMPTYDATA,
foundname, (void *)&n);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, DNS_R_PARTIALMATCH);
assert_true(dns_name_equal(foundname, dns_rootname));
test_context_teardown(ctx);
}
2018-10-24 22:12:06 -07:00
/* Test addname return values */
static void
2020-02-13 14:44:37 -08:00
rbt_addname(void **state) {
isc_result_t result;
test_context_t *ctx = NULL;
dns_fixedname_t fname;
2020-02-13 14:44:37 -08:00
dns_name_t *name = NULL;
size_t *n;
2018-10-24 22:12:06 -07:00
UNUSED(state);
isc_mem_debugging = ISC_MEM_DEBUGRECORD;
ctx = test_context_setup();
n = isc_mem_get(dt_mctx, sizeof(size_t));
2018-10-24 22:12:06 -07:00
assert_non_null(n);
*n = 1;
dns_test_namefromstring("d.e.f.g.h.i.j.k", &fname);
name = dns_fixedname_name(&fname);
/* Add a name that doesn't exist */
result = dns_rbt_addname(ctx->rbt, name, n);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
/* Now add again, should get ISC_R_EXISTS */
n = isc_mem_get(dt_mctx, sizeof(size_t));
2018-10-24 22:12:06 -07:00
assert_non_null(n);
*n = 2;
result = dns_rbt_addname(ctx->rbt, name, n);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_EXISTS);
isc_mem_put(dt_mctx, n, sizeof(size_t));
test_context_teardown(ctx);
}
2018-10-24 22:12:06 -07:00
/* Test deletename return values */
static void
2020-02-13 14:44:37 -08:00
rbt_deletename(void **state) {
isc_result_t result;
test_context_t *ctx = NULL;
dns_fixedname_t fname;
2020-02-13 14:44:37 -08:00
dns_name_t *name = NULL;
2018-10-24 22:12:06 -07:00
UNUSED(state);
isc_mem_debugging = ISC_MEM_DEBUGRECORD;
ctx = test_context_setup();
/* Delete a name that doesn't exist */
dns_test_namefromstring("z.x.y.w", &fname);
name = dns_fixedname_name(&fname);
result = dns_rbt_deletename(ctx->rbt, name, false);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_NOTFOUND);
/* Now one that does */
dns_test_namefromstring("d.e.f", &fname);
name = dns_fixedname_name(&fname);
result = dns_rbt_deletename(ctx->rbt, name, false);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_NOTFOUND);
test_context_teardown(ctx);
}
2018-10-24 22:12:06 -07:00
/* Test nodechain */
static void
2020-02-13 14:44:37 -08:00
rbt_nodechain(void **state) {
isc_result_t result;
test_context_t *ctx;
dns_fixedname_t fname, found, expect;
dns_name_t *name, *foundname, *expected;
dns_rbtnode_t *node = NULL;
dns_rbtnodechain_t chain;
2018-10-24 22:12:06 -07:00
UNUSED(state);
isc_mem_debugging = ISC_MEM_DEBUGRECORD;
ctx = test_context_setup();
dns_rbtnodechain_init(&chain);
dns_test_namefromstring("a", &fname);
name = dns_fixedname_name(&fname);
result = dns_rbt_findnode(ctx->rbt, name, NULL, &node, &chain, 0, NULL,
NULL);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
foundname = dns_fixedname_initname(&found);
dns_test_namefromstring("a", &expect);
expected = dns_fixedname_name(&expect);
UNUSED(expected);
result = dns_rbtnodechain_first(&chain, ctx->rbt, foundname, NULL);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, DNS_R_NEWORIGIN);
assert_int_equal(dns_name_countlabels(foundname), 0);
result = dns_rbtnodechain_prev(&chain, NULL, NULL);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_NOMORE);
result = dns_rbtnodechain_next(&chain, NULL, NULL);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
result = dns_rbtnodechain_next(&chain, NULL, NULL);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
result = dns_rbtnodechain_last(&chain, ctx->rbt, NULL, NULL);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, DNS_R_NEWORIGIN);
result = dns_rbtnodechain_next(&chain, NULL, NULL);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_NOMORE);
result = dns_rbtnodechain_last(&chain, ctx->rbt, NULL, NULL);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, DNS_R_NEWORIGIN);
result = dns_rbtnodechain_prev(&chain, NULL, NULL);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
dns_rbtnodechain_invalidate(&chain);
test_context_teardown(ctx);
}
/* Test addname return values */
static void
rbtnode_namelen(void **state) {
isc_result_t result;
test_context_t *ctx = NULL;
dns_rbtnode_t *node;
unsigned int len;
UNUSED(state);
isc_mem_debugging = ISC_MEM_DEBUGRECORD;
ctx = test_context_setup();
node = NULL;
result = insert_helper(ctx->rbt, ".", &node);
len = dns__rbtnode_namelen(node);
assert_int_equal(result, ISC_R_EXISTS);
assert_int_equal(len, 1);
node = NULL;
result = insert_helper(ctx->rbt, "a.b.c.d.e.f.g.h.i.j.k.l.m", &node);
len = dns__rbtnode_namelen(node);
assert_int_equal(result, ISC_R_SUCCESS);
assert_int_equal(len, 27);
node = NULL;
result = insert_helper(ctx->rbt, "isc.org", &node);
len = dns__rbtnode_namelen(node);
assert_int_equal(result, ISC_R_SUCCESS);
assert_int_equal(len, 9);
node = NULL;
result = insert_helper(ctx->rbt, "example.com", &node);
len = dns__rbtnode_namelen(node);
assert_int_equal(result, ISC_R_SUCCESS);
assert_int_equal(len, 13);
test_context_teardown(ctx);
}
#if defined(DNS_BENCHMARK_TESTS) && !defined(__SANITIZE_THREAD__)
2015-12-09 19:15:46 +05:30
/*
* XXXMUKS: Don't delete this code. It is useful in benchmarking the
* RBT, but we don't require it as part of the unit test runs.
*/
2015-12-09 19:07:20 +05:30
static dns_fixedname_t *fnames;
2020-02-13 14:44:37 -08:00
static dns_name_t **names;
static int *values;
2015-12-09 19:07:20 +05:30
static void *
2020-02-13 14:44:37 -08:00
find_thread(void *arg) {
dns_rbt_t *mytree;
isc_result_t result;
2015-12-09 19:07:20 +05:30
dns_rbtnode_t *node;
2020-02-13 14:44:37 -08:00
unsigned int j, i;
unsigned int start = 0;
2015-12-09 19:07:20 +05:30
mytree = (dns_rbt_t *)arg;
while (start == 0) {
2015-12-09 19:07:20 +05:30
start = random() % 4000000;
}
2015-12-09 19:07:20 +05:30
/* Query 32 million random names from it in each thread */
for (j = 0; j < 8; j++) {
for (i = start; i != start - 1; i = (i + 1) % 4000000) {
node = NULL;
result = dns_rbt_findnode(mytree, names[i], NULL, &node,
NULL, DNS_RBTFIND_EMPTYDATA,
2015-12-09 19:07:20 +05:30
NULL, NULL);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
assert_non_null(node);
assert_int_equal(values[i], (intptr_t)node->data);
2015-12-09 19:07:20 +05:30
}
}
return (NULL);
}
2018-10-24 22:12:06 -07:00
/* Benchmark RBT implementation */
static void
2020-02-13 14:44:37 -08:00
benchmark(void **state) {
isc_result_t result;
char namestr[sizeof("name18446744073709551616.example.org.")];
unsigned int r;
dns_rbt_t *mytree;
2015-12-09 19:07:20 +05:30
dns_rbtnode_t *node;
2020-02-13 14:44:37 -08:00
unsigned int i;
unsigned int maxvalue = 1000000;
isc_time_t ts1, ts2;
double t;
unsigned int nthreads;
isc_thread_t threads[32];
2015-12-09 19:07:20 +05:30
2018-10-24 22:12:06 -07:00
UNUSED(state);
2015-12-09 19:07:20 +05:30
srandom(time(NULL));
debug_mem_record = false;
2015-12-09 19:07:20 +05:30
fnames = (dns_fixedname_t *)malloc(4000000 * sizeof(dns_fixedname_t));
names = (dns_name_t **)malloc(4000000 * sizeof(dns_name_t *));
values = (int *)malloc(4000000 * sizeof(int));
2015-12-09 19:07:20 +05:30
for (i = 0; i < 4000000; i++) {
r = ((unsigned long)random()) % maxvalue;
snprintf(namestr, sizeof(namestr), "name%u.example.org.", r);
dns_test_namefromstring(namestr, &fnames[i]);
names[i] = dns_fixedname_name(&fnames[i]);
values[i] = r;
2015-12-09 19:07:20 +05:30
}
/* Create a tree. */
mytree = NULL;
result = dns_rbt_create(dt_mctx, NULL, NULL, &mytree);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
2015-12-09 19:07:20 +05:30
/* Insert test data into the tree. */
for (i = 0; i < maxvalue; i++) {
snprintf(namestr, sizeof(namestr), "name%u.example.org.", i);
node = NULL;
result = insert_helper(mytree, namestr, &node);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
node->data = (void *)(intptr_t)i;
2015-12-09 19:07:20 +05:30
}
result = isc_time_now(&ts1);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
2015-12-09 19:07:20 +05:30
nthreads = ISC_MIN(isc_os_ncpus(), 32);
nthreads = ISC_MAX(nthreads, 1);
for (i = 0; i < nthreads; i++) {
isc_thread_create(find_thread, mytree, &threads[i]);
2015-12-09 19:07:20 +05:30
}
for (i = 0; i < nthreads; i++) {
isc_thread_join(threads[i], NULL);
2015-12-09 19:07:20 +05:30
}
result = isc_time_now(&ts2);
2018-10-24 22:12:06 -07:00
assert_int_equal(result, ISC_R_SUCCESS);
2015-12-09 19:07:20 +05:30
t = isc_time_microdiff(&ts2, &ts1);
printf("%u findnode calls, %f seconds, %f calls/second\n",
nthreads * 8 * 4000000, t / 1000000.0,
(nthreads * 8 * 4000000) / (t / 1000000.0));
free(values);
free(names);
free(fnames);
dns_rbt_destroy(&mytree);
}
#endif /* defined(DNS_BENCHMARK_TESTS) && !defined(__SANITIZE_THREAD__) */
2015-12-09 19:15:46 +05:30
2018-10-24 22:12:06 -07:00
int
2020-02-13 14:44:37 -08:00
main(void) {
2018-10-24 22:12:06 -07:00
const struct CMUnitTest tests[] = {
cmocka_unit_test_setup_teardown(rbt_create, _setup, _teardown),
cmocka_unit_test_setup_teardown(rbt_nodecount, _setup,
_teardown),
cmocka_unit_test_setup_teardown(rbtnode_get_distance, _setup,
_teardown),
2018-10-24 22:12:06 -07:00
cmocka_unit_test_setup_teardown(rbt_check_distance_random,
_setup, _teardown),
cmocka_unit_test_setup_teardown(rbt_check_distance_ordered,
_setup, _teardown),
cmocka_unit_test_setup_teardown(rbt_insert, _setup, _teardown),
cmocka_unit_test_setup_teardown(rbt_remove, _setup, _teardown),
cmocka_unit_test_setup_teardown(rbt_insert_and_remove, _setup,
_teardown),
cmocka_unit_test_setup_teardown(rbt_findname, _setup,
_teardown),
2018-10-24 22:12:06 -07:00
cmocka_unit_test_setup_teardown(rbt_addname, _setup, _teardown),
cmocka_unit_test_setup_teardown(rbt_deletename, _setup,
_teardown),
cmocka_unit_test_setup_teardown(rbt_nodechain, _setup,
_teardown),
cmocka_unit_test_setup_teardown(rbtnode_namelen, _setup,
_teardown),
#if defined(DNS_BENCHMARK_TESTS) && !defined(__SANITIZE_THREAD__)
2018-10-24 22:12:06 -07:00
cmocka_unit_test_setup_teardown(benchmark, _setup, _teardown),
#endif /* defined(DNS_BENCHMARK_TESTS) && !defined(__SANITIZE_THREAD__) */
2018-10-24 22:12:06 -07:00
};
2018-10-24 22:12:06 -07:00
return (cmocka_run_group_tests(tests, NULL, NULL));
}
2018-10-24 22:12:06 -07:00
#else /* HAVE_CMOCKA */
#include <stdio.h>
int
2020-02-13 14:44:37 -08:00
main(void) {
2018-10-24 22:12:06 -07:00
printf("1..0 # Skipped: cmocka not available\n");
return (0);
}
#endif /* if HAVE_CMOCKA */