xref: /minix3/external/bsd/bind/dist/lib/dns/tests/rbt_test.c (revision 00b67f09dd46474d133c95011a48590a8e8f94c7)
1*00b67f09SDavid van Moolenbroek /*	$NetBSD: rbt_test.c,v 1.1.1.4 2014/12/10 03:34:43 christos Exp $	*/
2*00b67f09SDavid van Moolenbroek 
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek  * Copyright (C) 2012-2014  Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek  *
6*00b67f09SDavid van Moolenbroek  * Permission to use, copy, modify, and/or distribute this software for any
7*00b67f09SDavid van Moolenbroek  * purpose with or without fee is hereby granted, provided that the above
8*00b67f09SDavid van Moolenbroek  * copyright notice and this permission notice appear in all copies.
9*00b67f09SDavid van Moolenbroek  *
10*00b67f09SDavid van Moolenbroek  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11*00b67f09SDavid van Moolenbroek  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12*00b67f09SDavid van Moolenbroek  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13*00b67f09SDavid van Moolenbroek  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14*00b67f09SDavid van Moolenbroek  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15*00b67f09SDavid van Moolenbroek  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16*00b67f09SDavid van Moolenbroek  * PERFORMANCE OF THIS SOFTWARE.
17*00b67f09SDavid van Moolenbroek  */
18*00b67f09SDavid van Moolenbroek 
19*00b67f09SDavid van Moolenbroek /* Id: rbt_test.c,v 1.1.14.8 2012/02/10 16:24:37 ckb Exp  */
20*00b67f09SDavid van Moolenbroek 
21*00b67f09SDavid van Moolenbroek /* ! \file */
22*00b67f09SDavid van Moolenbroek 
23*00b67f09SDavid van Moolenbroek #include <config.h>
24*00b67f09SDavid van Moolenbroek #include <atf-c.h>
25*00b67f09SDavid van Moolenbroek #include <isc/mem.h>
26*00b67f09SDavid van Moolenbroek #include <isc/random.h>
27*00b67f09SDavid van Moolenbroek #include <isc/string.h>
28*00b67f09SDavid van Moolenbroek #include <fcntl.h>
29*00b67f09SDavid van Moolenbroek #include <unistd.h>
30*00b67f09SDavid van Moolenbroek 
31*00b67f09SDavid van Moolenbroek #ifdef HAVE_INTTYPES_H
32*00b67f09SDavid van Moolenbroek #include <inttypes.h> /* uintptr_t */
33*00b67f09SDavid van Moolenbroek #endif
34*00b67f09SDavid van Moolenbroek 
35*00b67f09SDavid van Moolenbroek #include <dns/rbt.h>
36*00b67f09SDavid van Moolenbroek #include <dns/fixedname.h>
37*00b67f09SDavid van Moolenbroek #include <dns/result.h>
38*00b67f09SDavid van Moolenbroek #include <dns/compress.h>
39*00b67f09SDavid van Moolenbroek #include "dnstest.h"
40*00b67f09SDavid van Moolenbroek 
41*00b67f09SDavid van Moolenbroek #include <isc/app.h>
42*00b67f09SDavid van Moolenbroek #include <isc/buffer.h>
43*00b67f09SDavid van Moolenbroek #include <isc/entropy.h>
44*00b67f09SDavid van Moolenbroek #include <isc/file.h>
45*00b67f09SDavid van Moolenbroek #include <isc/hash.h>
46*00b67f09SDavid van Moolenbroek #include <isc/mem.h>
47*00b67f09SDavid van Moolenbroek #include <isc/os.h>
48*00b67f09SDavid van Moolenbroek #include <isc/string.h>
49*00b67f09SDavid van Moolenbroek #include <isc/socket.h>
50*00b67f09SDavid van Moolenbroek #include <isc/stdio.h>
51*00b67f09SDavid van Moolenbroek #include <isc/task.h>
52*00b67f09SDavid van Moolenbroek #include <isc/timer.h>
53*00b67f09SDavid van Moolenbroek #include <isc/util.h>
54*00b67f09SDavid van Moolenbroek #include <isc/print.h>
55*00b67f09SDavid van Moolenbroek 
56*00b67f09SDavid van Moolenbroek #include <dns/log.h>
57*00b67f09SDavid van Moolenbroek #include <dns/name.h>
58*00b67f09SDavid van Moolenbroek #include <dns/result.h>
59*00b67f09SDavid van Moolenbroek 
60*00b67f09SDavid van Moolenbroek #include <dst/dst.h>
61*00b67f09SDavid van Moolenbroek 
62*00b67f09SDavid van Moolenbroek #include <ctype.h>
63*00b67f09SDavid van Moolenbroek 
64*00b67f09SDavid van Moolenbroek typedef struct {
65*00b67f09SDavid van Moolenbroek 	dns_rbt_t *rbt;
66*00b67f09SDavid van Moolenbroek 	dns_rbt_t *rbt_distances;
67*00b67f09SDavid van Moolenbroek } test_context_t;
68*00b67f09SDavid van Moolenbroek 
69*00b67f09SDavid van Moolenbroek /* The initial structure of domain tree will be as follows:
70*00b67f09SDavid van Moolenbroek  *
71*00b67f09SDavid van Moolenbroek  *	       .
72*00b67f09SDavid van Moolenbroek  *	       |
73*00b67f09SDavid van Moolenbroek  *	       b
74*00b67f09SDavid van Moolenbroek  *	     /	 \
75*00b67f09SDavid van Moolenbroek  *	    a	 d.e.f
76*00b67f09SDavid van Moolenbroek  *		/  |   \
77*00b67f09SDavid van Moolenbroek  *	       c   |	g.h
78*00b67f09SDavid van Moolenbroek  *		   |	 |
79*00b67f09SDavid van Moolenbroek  *		  w.y	 i
80*00b67f09SDavid van Moolenbroek  *		/  |  \	  \
81*00b67f09SDavid van Moolenbroek  *	       x   |   z   k
82*00b67f09SDavid van Moolenbroek  *		   |   |
83*00b67f09SDavid van Moolenbroek  *		   p   j
84*00b67f09SDavid van Moolenbroek  *		 /   \
85*00b67f09SDavid van Moolenbroek  *		o     q
86*00b67f09SDavid van Moolenbroek  */
87*00b67f09SDavid van Moolenbroek 
88*00b67f09SDavid van Moolenbroek /* The full absolute names of the nodes in the tree (the tree also
89*00b67f09SDavid van Moolenbroek  * contains "." which is not included in this list).
90*00b67f09SDavid van Moolenbroek  */
91*00b67f09SDavid van Moolenbroek static const char * const domain_names[] = {
92*00b67f09SDavid van Moolenbroek     "c", "b", "a", "x.d.e.f", "z.d.e.f", "g.h", "i.g.h", "o.w.y.d.e.f",
93*00b67f09SDavid van Moolenbroek     "j.z.d.e.f", "p.w.y.d.e.f", "q.w.y.d.e.f", "k.g.h"
94*00b67f09SDavid van Moolenbroek };
95*00b67f09SDavid van Moolenbroek 
96*00b67f09SDavid van Moolenbroek static const size_t domain_names_count = (sizeof(domain_names) /
97*00b67f09SDavid van Moolenbroek 					  sizeof(domain_names[0]));
98*00b67f09SDavid van Moolenbroek 
99*00b67f09SDavid van Moolenbroek /* These are set as the node data for the tree used in distances check
100*00b67f09SDavid van Moolenbroek  * (for the names in domain_names[] above).
101*00b67f09SDavid van Moolenbroek  */
102*00b67f09SDavid van Moolenbroek static const int node_distances[] = {
103*00b67f09SDavid van Moolenbroek     3, 1, 2, 2, 2, 3, 1, 2, 1, 1, 2, 2
104*00b67f09SDavid van Moolenbroek };
105*00b67f09SDavid van Moolenbroek 
106*00b67f09SDavid van Moolenbroek /*
107*00b67f09SDavid van Moolenbroek  * The domain order should be:
108*00b67f09SDavid van Moolenbroek  * ., 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,
109*00b67f09SDavid van Moolenbroek  * q.w.y.d.e.f, z.d.e.f, j.z.d.e.f, g.h, i.g.h, k.g.h
110*00b67f09SDavid van Moolenbroek  *	       . (no data, can't be found)
111*00b67f09SDavid van Moolenbroek  *	       |
112*00b67f09SDavid van Moolenbroek  *	       b
113*00b67f09SDavid van Moolenbroek  *	     /	 \
114*00b67f09SDavid van Moolenbroek  *	    a	 d.e.f
115*00b67f09SDavid van Moolenbroek  *		/  |   \
116*00b67f09SDavid van Moolenbroek  *	       c   |	g.h
117*00b67f09SDavid van Moolenbroek  *		   |	 |
118*00b67f09SDavid van Moolenbroek  *		  w.y	 i
119*00b67f09SDavid van Moolenbroek  *		/  |  \	  \
120*00b67f09SDavid van Moolenbroek  *	       x   |   z   k
121*00b67f09SDavid van Moolenbroek  *		   |   |
122*00b67f09SDavid van Moolenbroek  *		   p   j
123*00b67f09SDavid van Moolenbroek  *		 /   \
124*00b67f09SDavid van Moolenbroek  *		o     q
125*00b67f09SDavid van Moolenbroek  */
126*00b67f09SDavid van Moolenbroek 
127*00b67f09SDavid van Moolenbroek static const char * const ordered_names[] = {
128*00b67f09SDavid van Moolenbroek     "a", "b", "c", "d.e.f", "x.d.e.f", "w.y.d.e.f", "o.w.y.d.e.f",
129*00b67f09SDavid van Moolenbroek     "p.w.y.d.e.f", "q.w.y.d.e.f", "z.d.e.f", "j.z.d.e.f",
130*00b67f09SDavid van Moolenbroek     "g.h", "i.g.h", "k.g.h"};
131*00b67f09SDavid van Moolenbroek 
132*00b67f09SDavid van Moolenbroek static const size_t ordered_names_count = (sizeof(ordered_names) /
133*00b67f09SDavid van Moolenbroek 					   sizeof(*ordered_names));
134*00b67f09SDavid van Moolenbroek 
135*00b67f09SDavid van Moolenbroek static void
delete_data(void * data,void * arg)136*00b67f09SDavid van Moolenbroek delete_data(void *data, void *arg) {
137*00b67f09SDavid van Moolenbroek 	UNUSED(arg);
138*00b67f09SDavid van Moolenbroek 
139*00b67f09SDavid van Moolenbroek 	isc_mem_put(mctx, data, sizeof(size_t));
140*00b67f09SDavid van Moolenbroek }
141*00b67f09SDavid van Moolenbroek 
142*00b67f09SDavid van Moolenbroek static void
build_name_from_str(const char * namestr,dns_fixedname_t * fname)143*00b67f09SDavid van Moolenbroek build_name_from_str(const char *namestr, dns_fixedname_t *fname) {
144*00b67f09SDavid van Moolenbroek 	size_t length;
145*00b67f09SDavid van Moolenbroek 	isc_buffer_t *b = NULL;
146*00b67f09SDavid van Moolenbroek 	isc_result_t result;
147*00b67f09SDavid van Moolenbroek 	dns_name_t *name;
148*00b67f09SDavid van Moolenbroek 
149*00b67f09SDavid van Moolenbroek 	length = strlen(namestr);
150*00b67f09SDavid van Moolenbroek 
151*00b67f09SDavid van Moolenbroek 	result = isc_buffer_allocate(mctx, &b, length);
152*00b67f09SDavid van Moolenbroek 	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
153*00b67f09SDavid van Moolenbroek 	isc_buffer_putmem(b, (const unsigned char *) namestr, length);
154*00b67f09SDavid van Moolenbroek 
155*00b67f09SDavid van Moolenbroek 	dns_fixedname_init(fname);
156*00b67f09SDavid van Moolenbroek 	name = dns_fixedname_name(fname);
157*00b67f09SDavid van Moolenbroek 	ATF_REQUIRE(name != NULL);
158*00b67f09SDavid van Moolenbroek 	result = dns_name_fromtext(name, b, dns_rootname, 0, NULL);
159*00b67f09SDavid van Moolenbroek 	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
160*00b67f09SDavid van Moolenbroek 
161*00b67f09SDavid van Moolenbroek 	isc_buffer_free(&b);
162*00b67f09SDavid van Moolenbroek }
163*00b67f09SDavid van Moolenbroek 
164*00b67f09SDavid van Moolenbroek static test_context_t *
test_context_setup(void)165*00b67f09SDavid van Moolenbroek test_context_setup(void) {
166*00b67f09SDavid van Moolenbroek 	test_context_t *ctx;
167*00b67f09SDavid van Moolenbroek 	isc_result_t result;
168*00b67f09SDavid van Moolenbroek 	size_t i;
169*00b67f09SDavid van Moolenbroek 
170*00b67f09SDavid van Moolenbroek 	ctx = isc_mem_get(mctx, sizeof(*ctx));
171*00b67f09SDavid van Moolenbroek 
172*00b67f09SDavid van Moolenbroek 	ctx->rbt = NULL;
173*00b67f09SDavid van Moolenbroek 	result = dns_rbt_create(mctx, delete_data, NULL, &ctx->rbt);
174*00b67f09SDavid van Moolenbroek 	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
175*00b67f09SDavid van Moolenbroek 
176*00b67f09SDavid van Moolenbroek 	ctx->rbt_distances = NULL;
177*00b67f09SDavid van Moolenbroek 	result = dns_rbt_create(mctx, delete_data, NULL, &ctx->rbt_distances);
178*00b67f09SDavid van Moolenbroek 	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
179*00b67f09SDavid van Moolenbroek 
180*00b67f09SDavid van Moolenbroek 	for (i = 0; i < domain_names_count; i++) {
181*00b67f09SDavid van Moolenbroek 		size_t *n;
182*00b67f09SDavid van Moolenbroek 		dns_fixedname_t fname;
183*00b67f09SDavid van Moolenbroek 		dns_name_t *name;
184*00b67f09SDavid van Moolenbroek 
185*00b67f09SDavid van Moolenbroek 		build_name_from_str(domain_names[i], &fname);
186*00b67f09SDavid van Moolenbroek 
187*00b67f09SDavid van Moolenbroek 		name = dns_fixedname_name(&fname);
188*00b67f09SDavid van Moolenbroek 
189*00b67f09SDavid van Moolenbroek 		n = isc_mem_get(mctx, sizeof(size_t));
190*00b67f09SDavid van Moolenbroek 		*n = i + 1;
191*00b67f09SDavid van Moolenbroek 		result = dns_rbt_addname(ctx->rbt, name, n);
192*00b67f09SDavid van Moolenbroek 		ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
193*00b67f09SDavid van Moolenbroek 
194*00b67f09SDavid van Moolenbroek 		n = isc_mem_get(mctx, sizeof(size_t));
195*00b67f09SDavid van Moolenbroek 		*n = node_distances[i];
196*00b67f09SDavid van Moolenbroek 		result = dns_rbt_addname(ctx->rbt_distances, name, n);
197*00b67f09SDavid van Moolenbroek 		ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
198*00b67f09SDavid van Moolenbroek 	}
199*00b67f09SDavid van Moolenbroek 
200*00b67f09SDavid van Moolenbroek 	return (ctx);
201*00b67f09SDavid van Moolenbroek }
202*00b67f09SDavid van Moolenbroek 
203*00b67f09SDavid van Moolenbroek static void
test_context_teardown(test_context_t * ctx)204*00b67f09SDavid van Moolenbroek test_context_teardown(test_context_t *ctx) {
205*00b67f09SDavid van Moolenbroek 	dns_rbt_destroy(&ctx->rbt);
206*00b67f09SDavid van Moolenbroek 	dns_rbt_destroy(&ctx->rbt_distances);
207*00b67f09SDavid van Moolenbroek 
208*00b67f09SDavid van Moolenbroek 	isc_mem_put(mctx, ctx, sizeof(*ctx));
209*00b67f09SDavid van Moolenbroek }
210*00b67f09SDavid van Moolenbroek 
211*00b67f09SDavid van Moolenbroek /*
212*00b67f09SDavid van Moolenbroek  * Walk the tree and ensure that all the test nodes are present.
213*00b67f09SDavid van Moolenbroek  */
214*00b67f09SDavid van Moolenbroek static void
check_test_data(dns_rbt_t * rbt)215*00b67f09SDavid van Moolenbroek check_test_data(dns_rbt_t *rbt) {
216*00b67f09SDavid van Moolenbroek 	dns_fixedname_t fixed;
217*00b67f09SDavid van Moolenbroek 	isc_result_t result;
218*00b67f09SDavid van Moolenbroek 	dns_name_t *foundname;
219*00b67f09SDavid van Moolenbroek 	size_t i;
220*00b67f09SDavid van Moolenbroek 
221*00b67f09SDavid van Moolenbroek 	dns_fixedname_init(&fixed);
222*00b67f09SDavid van Moolenbroek 	foundname = dns_fixedname_name(&fixed);
223*00b67f09SDavid van Moolenbroek 
224*00b67f09SDavid van Moolenbroek 	for (i = 0; i < domain_names_count; i++) {
225*00b67f09SDavid van Moolenbroek 		dns_fixedname_t fname;
226*00b67f09SDavid van Moolenbroek 		dns_name_t *name;
227*00b67f09SDavid van Moolenbroek 		size_t *n;
228*00b67f09SDavid van Moolenbroek 
229*00b67f09SDavid van Moolenbroek 		build_name_from_str(domain_names[i], &fname);
230*00b67f09SDavid van Moolenbroek 
231*00b67f09SDavid van Moolenbroek 		name = dns_fixedname_name(&fname);
232*00b67f09SDavid van Moolenbroek 		n = NULL;
233*00b67f09SDavid van Moolenbroek 		result = dns_rbt_findname(rbt, name, 0, foundname,
234*00b67f09SDavid van Moolenbroek 					  (void *) &n);
235*00b67f09SDavid van Moolenbroek 		ATF_CHECK_EQ(result, ISC_R_SUCCESS);
236*00b67f09SDavid van Moolenbroek 		ATF_CHECK_EQ(*n, i + 1);
237*00b67f09SDavid van Moolenbroek 	}
238*00b67f09SDavid van Moolenbroek }
239*00b67f09SDavid van Moolenbroek 
240*00b67f09SDavid van Moolenbroek ATF_TC(rbt_create);
ATF_TC_HEAD(rbt_create,tc)241*00b67f09SDavid van Moolenbroek ATF_TC_HEAD(rbt_create, tc) {
242*00b67f09SDavid van Moolenbroek 	atf_tc_set_md_var(tc, "descr", "Test the creation of an rbt");
243*00b67f09SDavid van Moolenbroek }
ATF_TC_BODY(rbt_create,tc)244*00b67f09SDavid van Moolenbroek ATF_TC_BODY(rbt_create, tc) {
245*00b67f09SDavid van Moolenbroek 	isc_result_t result;
246*00b67f09SDavid van Moolenbroek 	test_context_t *ctx;
247*00b67f09SDavid van Moolenbroek 	isc_boolean_t tree_ok;
248*00b67f09SDavid van Moolenbroek 
249*00b67f09SDavid van Moolenbroek 	UNUSED(tc);
250*00b67f09SDavid van Moolenbroek 
251*00b67f09SDavid van Moolenbroek 	isc_mem_debugging = ISC_MEM_DEBUGRECORD;
252*00b67f09SDavid van Moolenbroek 
253*00b67f09SDavid van Moolenbroek 	result = dns_test_begin(NULL, ISC_TRUE);
254*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
255*00b67f09SDavid van Moolenbroek 
256*00b67f09SDavid van Moolenbroek 	ctx = test_context_setup();
257*00b67f09SDavid van Moolenbroek 
258*00b67f09SDavid van Moolenbroek 	check_test_data(ctx->rbt);
259*00b67f09SDavid van Moolenbroek 
260*00b67f09SDavid van Moolenbroek 	tree_ok = dns__rbt_checkproperties(ctx->rbt);
261*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(tree_ok, ISC_TRUE);
262*00b67f09SDavid van Moolenbroek 
263*00b67f09SDavid van Moolenbroek 	test_context_teardown(ctx);
264*00b67f09SDavid van Moolenbroek 
265*00b67f09SDavid van Moolenbroek 	dns_test_end();
266*00b67f09SDavid van Moolenbroek }
267*00b67f09SDavid van Moolenbroek 
268*00b67f09SDavid van Moolenbroek ATF_TC(rbt_nodecount);
ATF_TC_HEAD(rbt_nodecount,tc)269*00b67f09SDavid van Moolenbroek ATF_TC_HEAD(rbt_nodecount, tc) {
270*00b67f09SDavid van Moolenbroek 	atf_tc_set_md_var(tc, "descr", "Test dns_rbt_nodecount() on a tree");
271*00b67f09SDavid van Moolenbroek }
ATF_TC_BODY(rbt_nodecount,tc)272*00b67f09SDavid van Moolenbroek ATF_TC_BODY(rbt_nodecount, tc) {
273*00b67f09SDavid van Moolenbroek 	isc_result_t result;
274*00b67f09SDavid van Moolenbroek 	test_context_t *ctx;
275*00b67f09SDavid van Moolenbroek 
276*00b67f09SDavid van Moolenbroek 	UNUSED(tc);
277*00b67f09SDavid van Moolenbroek 
278*00b67f09SDavid van Moolenbroek 	isc_mem_debugging = ISC_MEM_DEBUGRECORD;
279*00b67f09SDavid van Moolenbroek 
280*00b67f09SDavid van Moolenbroek 	result = dns_test_begin(NULL, ISC_TRUE);
281*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
282*00b67f09SDavid van Moolenbroek 
283*00b67f09SDavid van Moolenbroek 	ctx = test_context_setup();
284*00b67f09SDavid van Moolenbroek 
285*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(15, dns_rbt_nodecount(ctx->rbt));
286*00b67f09SDavid van Moolenbroek 
287*00b67f09SDavid van Moolenbroek 	test_context_teardown(ctx);
288*00b67f09SDavid van Moolenbroek 
289*00b67f09SDavid van Moolenbroek 	dns_test_end();
290*00b67f09SDavid van Moolenbroek }
291*00b67f09SDavid van Moolenbroek 
292*00b67f09SDavid van Moolenbroek ATF_TC(rbtnode_get_distance);
ATF_TC_HEAD(rbtnode_get_distance,tc)293*00b67f09SDavid van Moolenbroek ATF_TC_HEAD(rbtnode_get_distance, tc) {
294*00b67f09SDavid van Moolenbroek 	atf_tc_set_md_var(tc, "descr",
295*00b67f09SDavid van Moolenbroek 			  "Test dns_rbtnode_get_distance() on a tree");
296*00b67f09SDavid van Moolenbroek }
ATF_TC_BODY(rbtnode_get_distance,tc)297*00b67f09SDavid van Moolenbroek ATF_TC_BODY(rbtnode_get_distance, tc) {
298*00b67f09SDavid van Moolenbroek 	isc_result_t result;
299*00b67f09SDavid van Moolenbroek 	test_context_t *ctx;
300*00b67f09SDavid van Moolenbroek 	const char *name_str = "a";
301*00b67f09SDavid van Moolenbroek 	dns_fixedname_t fname;
302*00b67f09SDavid van Moolenbroek 	dns_name_t *name;
303*00b67f09SDavid van Moolenbroek 	dns_rbtnode_t *node = NULL;
304*00b67f09SDavid van Moolenbroek 	dns_rbtnodechain_t chain;
305*00b67f09SDavid van Moolenbroek 
306*00b67f09SDavid van Moolenbroek 	UNUSED(tc);
307*00b67f09SDavid van Moolenbroek 
308*00b67f09SDavid van Moolenbroek 	isc_mem_debugging = ISC_MEM_DEBUGRECORD;
309*00b67f09SDavid van Moolenbroek 
310*00b67f09SDavid van Moolenbroek 	result = dns_test_begin(NULL, ISC_TRUE);
311*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
312*00b67f09SDavid van Moolenbroek 
313*00b67f09SDavid van Moolenbroek 	ctx = test_context_setup();
314*00b67f09SDavid van Moolenbroek 
315*00b67f09SDavid van Moolenbroek 	build_name_from_str(name_str, &fname);
316*00b67f09SDavid van Moolenbroek 	name = dns_fixedname_name(&fname);
317*00b67f09SDavid van Moolenbroek 
318*00b67f09SDavid van Moolenbroek 	dns_rbtnodechain_init(&chain, mctx);
319*00b67f09SDavid van Moolenbroek 
320*00b67f09SDavid van Moolenbroek 	result = dns_rbt_findnode(ctx->rbt_distances, name, NULL,
321*00b67f09SDavid van Moolenbroek 				  &node, &chain, 0, NULL, NULL);
322*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
323*00b67f09SDavid van Moolenbroek 
324*00b67f09SDavid van Moolenbroek 	while (node != NULL) {
325*00b67f09SDavid van Moolenbroek 		const size_t *distance = (const size_t *) node->data;
326*00b67f09SDavid van Moolenbroek 		if (distance != NULL)
327*00b67f09SDavid van Moolenbroek 			ATF_CHECK_EQ(*distance,
328*00b67f09SDavid van Moolenbroek 				     dns__rbtnode_getdistance(node));
329*00b67f09SDavid van Moolenbroek 		result = dns_rbtnodechain_next(&chain, NULL, NULL);
330*00b67f09SDavid van Moolenbroek 		if (result == ISC_R_NOMORE)
331*00b67f09SDavid van Moolenbroek 		      break;
332*00b67f09SDavid van Moolenbroek 		dns_rbtnodechain_current(&chain, NULL, NULL, &node);
333*00b67f09SDavid van Moolenbroek 	}
334*00b67f09SDavid van Moolenbroek 
335*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(result, ISC_R_NOMORE);
336*00b67f09SDavid van Moolenbroek 
337*00b67f09SDavid van Moolenbroek 	dns_rbtnodechain_invalidate(&chain);
338*00b67f09SDavid van Moolenbroek 
339*00b67f09SDavid van Moolenbroek 	test_context_teardown(ctx);
340*00b67f09SDavid van Moolenbroek 
341*00b67f09SDavid van Moolenbroek 	dns_test_end();
342*00b67f09SDavid van Moolenbroek }
343*00b67f09SDavid van Moolenbroek 
344*00b67f09SDavid van Moolenbroek ATF_TC(rbt_check_distance_random);
ATF_TC_HEAD(rbt_check_distance_random,tc)345*00b67f09SDavid van Moolenbroek ATF_TC_HEAD(rbt_check_distance_random, tc) {
346*00b67f09SDavid van Moolenbroek 	atf_tc_set_md_var(tc, "descr",
347*00b67f09SDavid van Moolenbroek 			  "Test tree balance, inserting names in random order");
348*00b67f09SDavid van Moolenbroek }
ATF_TC_BODY(rbt_check_distance_random,tc)349*00b67f09SDavid van Moolenbroek ATF_TC_BODY(rbt_check_distance_random, tc) {
350*00b67f09SDavid van Moolenbroek 	/* This test checks an important performance-related property of
351*00b67f09SDavid van Moolenbroek 	 * the red-black tree, which is important for us: the longest
352*00b67f09SDavid van Moolenbroek 	 * path from a sub-tree's root to a node is no more than
353*00b67f09SDavid van Moolenbroek 	 * 2log(n). This check verifies that the tree is balanced.
354*00b67f09SDavid van Moolenbroek 	 */
355*00b67f09SDavid van Moolenbroek 	dns_rbt_t *mytree = NULL;
356*00b67f09SDavid van Moolenbroek 	const unsigned int log_num_nodes = 16;
357*00b67f09SDavid van Moolenbroek 
358*00b67f09SDavid van Moolenbroek 	int i;
359*00b67f09SDavid van Moolenbroek 	isc_result_t result;
360*00b67f09SDavid van Moolenbroek 	isc_boolean_t tree_ok;
361*00b67f09SDavid van Moolenbroek 
362*00b67f09SDavid van Moolenbroek 	UNUSED(tc);
363*00b67f09SDavid van Moolenbroek 
364*00b67f09SDavid van Moolenbroek 	isc_mem_debugging = ISC_MEM_DEBUGRECORD;
365*00b67f09SDavid van Moolenbroek 
366*00b67f09SDavid van Moolenbroek 	result = dns_test_begin(NULL, ISC_TRUE);
367*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
368*00b67f09SDavid van Moolenbroek 
369*00b67f09SDavid van Moolenbroek 	result = dns_rbt_create(mctx, delete_data, NULL, &mytree);
370*00b67f09SDavid van Moolenbroek 	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
371*00b67f09SDavid van Moolenbroek 
372*00b67f09SDavid van Moolenbroek 	/* Names are inserted in random order. */
373*00b67f09SDavid van Moolenbroek 
374*00b67f09SDavid van Moolenbroek 	/* Make a large 65536 node top-level domain tree, i.e., the
375*00b67f09SDavid van Moolenbroek 	 * following code inserts names such as:
376*00b67f09SDavid van Moolenbroek 	 *
377*00b67f09SDavid van Moolenbroek 	 * savoucnsrkrqzpkqypbygwoiliawpbmz.
378*00b67f09SDavid van Moolenbroek 	 * wkadamcbbpjtundbxcmuayuycposvngx.
379*00b67f09SDavid van Moolenbroek 	 * wzbpznemtooxdpjecdxynsfztvnuyfao.
380*00b67f09SDavid van Moolenbroek 	 * yueojmhyffslpvfmgyfwioxegfhepnqq.
381*00b67f09SDavid van Moolenbroek 	 */
382*00b67f09SDavid van Moolenbroek 	for (i = 0; i < (1 << log_num_nodes); i++) {
383*00b67f09SDavid van Moolenbroek 		size_t *n;
384*00b67f09SDavid van Moolenbroek 		char namebuf[34];
385*00b67f09SDavid van Moolenbroek 
386*00b67f09SDavid van Moolenbroek 		n = isc_mem_get(mctx, sizeof(size_t));
387*00b67f09SDavid van Moolenbroek 		*n = i + 1;
388*00b67f09SDavid van Moolenbroek 
389*00b67f09SDavid van Moolenbroek 		while (1) {
390*00b67f09SDavid van Moolenbroek 			int j;
391*00b67f09SDavid van Moolenbroek 			dns_fixedname_t fname;
392*00b67f09SDavid van Moolenbroek 			dns_name_t *name;
393*00b67f09SDavid van Moolenbroek 
394*00b67f09SDavid van Moolenbroek 			for (j = 0; j < 32; j++) {
395*00b67f09SDavid van Moolenbroek 				isc_uint32_t v;
396*00b67f09SDavid van Moolenbroek 				isc_random_get(&v);
397*00b67f09SDavid van Moolenbroek 				namebuf[j] = 'a' + (v % 26);
398*00b67f09SDavid van Moolenbroek 			}
399*00b67f09SDavid van Moolenbroek 			namebuf[32] = '.';
400*00b67f09SDavid van Moolenbroek 			namebuf[33] = 0;
401*00b67f09SDavid van Moolenbroek 
402*00b67f09SDavid van Moolenbroek 			build_name_from_str(namebuf, &fname);
403*00b67f09SDavid van Moolenbroek 			name = dns_fixedname_name(&fname);
404*00b67f09SDavid van Moolenbroek 
405*00b67f09SDavid van Moolenbroek 			result = dns_rbt_addname(mytree, name, n);
406*00b67f09SDavid van Moolenbroek 			if (result == ISC_R_SUCCESS)
407*00b67f09SDavid van Moolenbroek 				break;
408*00b67f09SDavid van Moolenbroek 		}
409*00b67f09SDavid van Moolenbroek 	}
410*00b67f09SDavid van Moolenbroek 
411*00b67f09SDavid van Moolenbroek 	/* 1 (root . node) + (1 << log_num_nodes) */
412*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(1U + (1U << log_num_nodes), dns_rbt_nodecount(mytree));
413*00b67f09SDavid van Moolenbroek 
414*00b67f09SDavid van Moolenbroek 	/* The distance from each node to its sub-tree root must be less
415*00b67f09SDavid van Moolenbroek 	 * than 2 * log(n).
416*00b67f09SDavid van Moolenbroek 	 */
417*00b67f09SDavid van Moolenbroek 	ATF_CHECK((2U * log_num_nodes) >= dns__rbt_getheight(mytree));
418*00b67f09SDavid van Moolenbroek 
419*00b67f09SDavid van Moolenbroek 	/* Also check RB tree properties */
420*00b67f09SDavid van Moolenbroek 	tree_ok = dns__rbt_checkproperties(mytree);
421*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(tree_ok, ISC_TRUE);
422*00b67f09SDavid van Moolenbroek 
423*00b67f09SDavid van Moolenbroek 	dns_rbt_destroy(&mytree);
424*00b67f09SDavid van Moolenbroek 
425*00b67f09SDavid van Moolenbroek 	dns_test_end();
426*00b67f09SDavid van Moolenbroek }
427*00b67f09SDavid van Moolenbroek 
428*00b67f09SDavid van Moolenbroek ATF_TC(rbt_check_distance_ordered);
ATF_TC_HEAD(rbt_check_distance_ordered,tc)429*00b67f09SDavid van Moolenbroek ATF_TC_HEAD(rbt_check_distance_ordered, tc) {
430*00b67f09SDavid van Moolenbroek 	atf_tc_set_md_var(tc, "descr",
431*00b67f09SDavid van Moolenbroek 			  "Test tree balance, inserting names in sorted order");
432*00b67f09SDavid van Moolenbroek }
ATF_TC_BODY(rbt_check_distance_ordered,tc)433*00b67f09SDavid van Moolenbroek ATF_TC_BODY(rbt_check_distance_ordered, tc) {
434*00b67f09SDavid van Moolenbroek 	/* This test checks an important performance-related property of
435*00b67f09SDavid van Moolenbroek 	 * the red-black tree, which is important for us: the longest
436*00b67f09SDavid van Moolenbroek 	 * path from a sub-tree's root to a node is no more than
437*00b67f09SDavid van Moolenbroek 	 * 2log(n). This check verifies that the tree is balanced.
438*00b67f09SDavid van Moolenbroek 	 */
439*00b67f09SDavid van Moolenbroek 	dns_rbt_t *mytree = NULL;
440*00b67f09SDavid van Moolenbroek 	const unsigned int log_num_nodes = 16;
441*00b67f09SDavid van Moolenbroek 
442*00b67f09SDavid van Moolenbroek 	int i;
443*00b67f09SDavid van Moolenbroek 	isc_result_t result;
444*00b67f09SDavid van Moolenbroek 	isc_boolean_t tree_ok;
445*00b67f09SDavid van Moolenbroek 
446*00b67f09SDavid van Moolenbroek 	UNUSED(tc);
447*00b67f09SDavid van Moolenbroek 
448*00b67f09SDavid van Moolenbroek 	isc_mem_debugging = ISC_MEM_DEBUGRECORD;
449*00b67f09SDavid van Moolenbroek 
450*00b67f09SDavid van Moolenbroek 	result = dns_test_begin(NULL, ISC_TRUE);
451*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
452*00b67f09SDavid van Moolenbroek 
453*00b67f09SDavid van Moolenbroek 	result = dns_rbt_create(mctx, delete_data, NULL, &mytree);
454*00b67f09SDavid van Moolenbroek 	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
455*00b67f09SDavid van Moolenbroek 
456*00b67f09SDavid van Moolenbroek 	/* Names are inserted in sorted order. */
457*00b67f09SDavid van Moolenbroek 
458*00b67f09SDavid van Moolenbroek 	/* Make a large 65536 node top-level domain tree, i.e., the
459*00b67f09SDavid van Moolenbroek 	 * following code inserts names such as:
460*00b67f09SDavid van Moolenbroek 	 *
461*00b67f09SDavid van Moolenbroek 	 *   name00000000.
462*00b67f09SDavid van Moolenbroek 	 *   name00000001.
463*00b67f09SDavid van Moolenbroek 	 *   name00000002.
464*00b67f09SDavid van Moolenbroek 	 *   name00000003.
465*00b67f09SDavid van Moolenbroek 	 */
466*00b67f09SDavid van Moolenbroek 	for (i = 0; i < (1 << log_num_nodes); i++) {
467*00b67f09SDavid van Moolenbroek 		size_t *n;
468*00b67f09SDavid van Moolenbroek 		char namebuf[14];
469*00b67f09SDavid van Moolenbroek 		dns_fixedname_t fname;
470*00b67f09SDavid van Moolenbroek 		dns_name_t *name;
471*00b67f09SDavid van Moolenbroek 
472*00b67f09SDavid van Moolenbroek 		n = isc_mem_get(mctx, sizeof(size_t));
473*00b67f09SDavid van Moolenbroek 		*n = i + 1;
474*00b67f09SDavid van Moolenbroek 
475*00b67f09SDavid van Moolenbroek 		snprintf(namebuf, sizeof(namebuf), "name%08x.", i);
476*00b67f09SDavid van Moolenbroek 		build_name_from_str(namebuf, &fname);
477*00b67f09SDavid van Moolenbroek 		name = dns_fixedname_name(&fname);
478*00b67f09SDavid van Moolenbroek 
479*00b67f09SDavid van Moolenbroek 		result = dns_rbt_addname(mytree, name, n);
480*00b67f09SDavid van Moolenbroek 		ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
481*00b67f09SDavid van Moolenbroek 	}
482*00b67f09SDavid van Moolenbroek 
483*00b67f09SDavid van Moolenbroek 	/* 1 (root . node) + (1 << log_num_nodes) */
484*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(1U + (1U << log_num_nodes), dns_rbt_nodecount(mytree));
485*00b67f09SDavid van Moolenbroek 
486*00b67f09SDavid van Moolenbroek 	/* The distance from each node to its sub-tree root must be less
487*00b67f09SDavid van Moolenbroek 	 * than 2 * log(n).
488*00b67f09SDavid van Moolenbroek 	 */
489*00b67f09SDavid van Moolenbroek 	ATF_CHECK((2U * log_num_nodes) >= dns__rbt_getheight(mytree));
490*00b67f09SDavid van Moolenbroek 
491*00b67f09SDavid van Moolenbroek 	/* Also check RB tree properties */
492*00b67f09SDavid van Moolenbroek 	tree_ok = dns__rbt_checkproperties(mytree);
493*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(tree_ok, ISC_TRUE);
494*00b67f09SDavid van Moolenbroek 
495*00b67f09SDavid van Moolenbroek 	dns_rbt_destroy(&mytree);
496*00b67f09SDavid van Moolenbroek 
497*00b67f09SDavid van Moolenbroek 	dns_test_end();
498*00b67f09SDavid van Moolenbroek }
499*00b67f09SDavid van Moolenbroek 
500*00b67f09SDavid van Moolenbroek static isc_result_t
insert_helper(dns_rbt_t * rbt,const char * namestr,dns_rbtnode_t ** node)501*00b67f09SDavid van Moolenbroek insert_helper(dns_rbt_t *rbt, const char *namestr, dns_rbtnode_t **node) {
502*00b67f09SDavid van Moolenbroek 	dns_fixedname_t fname;
503*00b67f09SDavid van Moolenbroek 	dns_name_t *name;
504*00b67f09SDavid van Moolenbroek 
505*00b67f09SDavid van Moolenbroek 	build_name_from_str(namestr, &fname);
506*00b67f09SDavid van Moolenbroek 	name = dns_fixedname_name(&fname);
507*00b67f09SDavid van Moolenbroek 
508*00b67f09SDavid van Moolenbroek 	return (dns_rbt_addnode(rbt, name, node));
509*00b67f09SDavid van Moolenbroek }
510*00b67f09SDavid van Moolenbroek 
511*00b67f09SDavid van Moolenbroek static isc_boolean_t
compare_labelsequences(dns_rbtnode_t * node,const char * labelstr)512*00b67f09SDavid van Moolenbroek compare_labelsequences(dns_rbtnode_t *node, const char *labelstr) {
513*00b67f09SDavid van Moolenbroek 	dns_name_t name;
514*00b67f09SDavid van Moolenbroek 	isc_result_t result;
515*00b67f09SDavid van Moolenbroek 	char *nodestr = NULL;
516*00b67f09SDavid van Moolenbroek 	isc_boolean_t is_equal;
517*00b67f09SDavid van Moolenbroek 
518*00b67f09SDavid van Moolenbroek 	dns_name_init(&name, NULL);
519*00b67f09SDavid van Moolenbroek 	dns_rbt_namefromnode(node, &name);
520*00b67f09SDavid van Moolenbroek 
521*00b67f09SDavid van Moolenbroek 	result = dns_name_tostring(&name, &nodestr, mctx);
522*00b67f09SDavid van Moolenbroek 	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
523*00b67f09SDavid van Moolenbroek 
524*00b67f09SDavid van Moolenbroek 	is_equal = strcmp(labelstr, nodestr) == 0 ? ISC_TRUE : ISC_FALSE;
525*00b67f09SDavid van Moolenbroek 
526*00b67f09SDavid van Moolenbroek 	isc_mem_free(mctx, nodestr);
527*00b67f09SDavid van Moolenbroek 
528*00b67f09SDavid van Moolenbroek 	return (is_equal);
529*00b67f09SDavid van Moolenbroek }
530*00b67f09SDavid van Moolenbroek 
531*00b67f09SDavid van Moolenbroek ATF_TC(rbt_insert);
ATF_TC_HEAD(rbt_insert,tc)532*00b67f09SDavid van Moolenbroek ATF_TC_HEAD(rbt_insert, tc) {
533*00b67f09SDavid van Moolenbroek 	atf_tc_set_md_var(tc, "descr", "Test insertion into a tree");
534*00b67f09SDavid van Moolenbroek }
ATF_TC_BODY(rbt_insert,tc)535*00b67f09SDavid van Moolenbroek ATF_TC_BODY(rbt_insert, tc) {
536*00b67f09SDavid van Moolenbroek 	isc_result_t result;
537*00b67f09SDavid van Moolenbroek 	test_context_t *ctx;
538*00b67f09SDavid van Moolenbroek 	dns_rbtnode_t *node;
539*00b67f09SDavid van Moolenbroek 
540*00b67f09SDavid van Moolenbroek 	UNUSED(tc);
541*00b67f09SDavid van Moolenbroek 
542*00b67f09SDavid van Moolenbroek 	isc_mem_debugging = ISC_MEM_DEBUGRECORD;
543*00b67f09SDavid van Moolenbroek 
544*00b67f09SDavid van Moolenbroek 	result = dns_test_begin(NULL, ISC_TRUE);
545*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
546*00b67f09SDavid van Moolenbroek 
547*00b67f09SDavid van Moolenbroek 	ctx = test_context_setup();
548*00b67f09SDavid van Moolenbroek 
549*00b67f09SDavid van Moolenbroek 	/* Check node count before beginning. */
550*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(15, dns_rbt_nodecount(ctx->rbt));
551*00b67f09SDavid van Moolenbroek 
552*00b67f09SDavid van Moolenbroek 	/* Try to insert a node that already exists. */
553*00b67f09SDavid van Moolenbroek 	node = NULL;
554*00b67f09SDavid van Moolenbroek 	result = insert_helper(ctx->rbt, "d.e.f", &node);
555*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(result, ISC_R_EXISTS);
556*00b67f09SDavid van Moolenbroek 
557*00b67f09SDavid van Moolenbroek 	/* Node count must not have changed. */
558*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(15, dns_rbt_nodecount(ctx->rbt));
559*00b67f09SDavid van Moolenbroek 
560*00b67f09SDavid van Moolenbroek 	/* Try to insert a node that doesn't exist. */
561*00b67f09SDavid van Moolenbroek 	node = NULL;
562*00b67f09SDavid van Moolenbroek 	result = insert_helper(ctx->rbt, "0", &node);
563*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
564*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(compare_labelsequences(node, "0"), ISC_TRUE);
565*00b67f09SDavid van Moolenbroek 
566*00b67f09SDavid van Moolenbroek 	/* Node count must have increased. */
567*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(16, dns_rbt_nodecount(ctx->rbt));
568*00b67f09SDavid van Moolenbroek 
569*00b67f09SDavid van Moolenbroek 	/* Another. */
570*00b67f09SDavid van Moolenbroek 	node = NULL;
571*00b67f09SDavid van Moolenbroek 	result = insert_helper(ctx->rbt, "example.com", &node);
572*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
573*00b67f09SDavid van Moolenbroek 	ATF_REQUIRE(node != NULL);
574*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(node->data, NULL);
575*00b67f09SDavid van Moolenbroek 
576*00b67f09SDavid van Moolenbroek 	/* Node count must have increased. */
577*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(17, dns_rbt_nodecount(ctx->rbt));
578*00b67f09SDavid van Moolenbroek 
579*00b67f09SDavid van Moolenbroek 	/* Re-adding it should return EXISTS */
580*00b67f09SDavid van Moolenbroek 	node = NULL;
581*00b67f09SDavid van Moolenbroek 	result = insert_helper(ctx->rbt, "example.com", &node);
582*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(result, ISC_R_EXISTS);
583*00b67f09SDavid van Moolenbroek 
584*00b67f09SDavid van Moolenbroek 	/* Node count must not have changed. */
585*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(17, dns_rbt_nodecount(ctx->rbt));
586*00b67f09SDavid van Moolenbroek 
587*00b67f09SDavid van Moolenbroek 	/* Fission the node d.e.f */
588*00b67f09SDavid van Moolenbroek 	node = NULL;
589*00b67f09SDavid van Moolenbroek 	result = insert_helper(ctx->rbt, "k.e.f", &node);
590*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
591*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(compare_labelsequences(node, "k"), ISC_TRUE);
592*00b67f09SDavid van Moolenbroek 
593*00b67f09SDavid van Moolenbroek 	/* Node count must have incremented twice ("d.e.f" fissioned to
594*00b67f09SDavid van Moolenbroek 	 * "d" and "e.f", and the newly added "k").
595*00b67f09SDavid van Moolenbroek 	 */
596*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(19, dns_rbt_nodecount(ctx->rbt));
597*00b67f09SDavid van Moolenbroek 
598*00b67f09SDavid van Moolenbroek 	/* Fission the node "g.h" */
599*00b67f09SDavid van Moolenbroek 	node = NULL;
600*00b67f09SDavid van Moolenbroek 	result = insert_helper(ctx->rbt, "h", &node);
601*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
602*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(compare_labelsequences(node, "h"), ISC_TRUE);
603*00b67f09SDavid van Moolenbroek 
604*00b67f09SDavid van Moolenbroek 	/* Node count must have incremented ("g.h" fissioned to "g" and
605*00b67f09SDavid van Moolenbroek 	 * "h").
606*00b67f09SDavid van Moolenbroek 	 */
607*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(20, dns_rbt_nodecount(ctx->rbt));
608*00b67f09SDavid van Moolenbroek 
609*00b67f09SDavid van Moolenbroek 	/* Add child domains */
610*00b67f09SDavid van Moolenbroek 
611*00b67f09SDavid van Moolenbroek 	node = NULL;
612*00b67f09SDavid van Moolenbroek 	result = insert_helper(ctx->rbt, "m.p.w.y.d.e.f", &node);
613*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
614*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(compare_labelsequences(node, "m"), ISC_TRUE);
615*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(21, dns_rbt_nodecount(ctx->rbt));
616*00b67f09SDavid van Moolenbroek 
617*00b67f09SDavid van Moolenbroek 	node = NULL;
618*00b67f09SDavid van Moolenbroek 	result = insert_helper(ctx->rbt, "n.p.w.y.d.e.f", &node);
619*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
620*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(compare_labelsequences(node, "n"), ISC_TRUE);
621*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(22, dns_rbt_nodecount(ctx->rbt));
622*00b67f09SDavid van Moolenbroek 
623*00b67f09SDavid van Moolenbroek 	node = NULL;
624*00b67f09SDavid van Moolenbroek 	result = insert_helper(ctx->rbt, "l.a", &node);
625*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
626*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(compare_labelsequences(node, "l"), ISC_TRUE);
627*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(23, dns_rbt_nodecount(ctx->rbt));
628*00b67f09SDavid van Moolenbroek 
629*00b67f09SDavid van Moolenbroek 	node = NULL;
630*00b67f09SDavid van Moolenbroek 	result = insert_helper(ctx->rbt, "r.d.e.f", &node);
631*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
632*00b67f09SDavid van Moolenbroek 	node = NULL;
633*00b67f09SDavid van Moolenbroek 	result = insert_helper(ctx->rbt, "s.d.e.f", &node);
634*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
635*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(25, dns_rbt_nodecount(ctx->rbt));
636*00b67f09SDavid van Moolenbroek 
637*00b67f09SDavid van Moolenbroek 	node = NULL;
638*00b67f09SDavid van Moolenbroek 	result = insert_helper(ctx->rbt, "h.w.y.d.e.f", &node);
639*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
640*00b67f09SDavid van Moolenbroek 
641*00b67f09SDavid van Moolenbroek 	/* Add more nodes one by one to cover left and right rotation
642*00b67f09SDavid van Moolenbroek 	 * functions.
643*00b67f09SDavid van Moolenbroek 	 */
644*00b67f09SDavid van Moolenbroek 	node = NULL;
645*00b67f09SDavid van Moolenbroek 	result = insert_helper(ctx->rbt, "f", &node);
646*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
647*00b67f09SDavid van Moolenbroek 
648*00b67f09SDavid van Moolenbroek 	node = NULL;
649*00b67f09SDavid van Moolenbroek 	result = insert_helper(ctx->rbt, "m", &node);
650*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
651*00b67f09SDavid van Moolenbroek 
652*00b67f09SDavid van Moolenbroek 	node = NULL;
653*00b67f09SDavid van Moolenbroek 	result = insert_helper(ctx->rbt, "nm", &node);
654*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
655*00b67f09SDavid van Moolenbroek 
656*00b67f09SDavid van Moolenbroek 	node = NULL;
657*00b67f09SDavid van Moolenbroek 	result = insert_helper(ctx->rbt, "om", &node);
658*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
659*00b67f09SDavid van Moolenbroek 
660*00b67f09SDavid van Moolenbroek 	node = NULL;
661*00b67f09SDavid van Moolenbroek 	result = insert_helper(ctx->rbt, "k", &node);
662*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
663*00b67f09SDavid van Moolenbroek 
664*00b67f09SDavid van Moolenbroek 	node = NULL;
665*00b67f09SDavid van Moolenbroek 	result = insert_helper(ctx->rbt, "l", &node);
666*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
667*00b67f09SDavid van Moolenbroek 
668*00b67f09SDavid van Moolenbroek 	node = NULL;
669*00b67f09SDavid van Moolenbroek 	result = insert_helper(ctx->rbt, "fe", &node);
670*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
671*00b67f09SDavid van Moolenbroek 
672*00b67f09SDavid van Moolenbroek 	node = NULL;
673*00b67f09SDavid van Moolenbroek 	result = insert_helper(ctx->rbt, "ge", &node);
674*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
675*00b67f09SDavid van Moolenbroek 
676*00b67f09SDavid van Moolenbroek 	node = NULL;
677*00b67f09SDavid van Moolenbroek 	result = insert_helper(ctx->rbt, "i", &node);
678*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
679*00b67f09SDavid van Moolenbroek 
680*00b67f09SDavid van Moolenbroek 	node = NULL;
681*00b67f09SDavid van Moolenbroek 	result = insert_helper(ctx->rbt, "ae", &node);
682*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
683*00b67f09SDavid van Moolenbroek 
684*00b67f09SDavid van Moolenbroek 	node = NULL;
685*00b67f09SDavid van Moolenbroek 	result = insert_helper(ctx->rbt, "n", &node);
686*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
687*00b67f09SDavid van Moolenbroek 
688*00b67f09SDavid van Moolenbroek 	test_context_teardown(ctx);
689*00b67f09SDavid van Moolenbroek 
690*00b67f09SDavid van Moolenbroek 	dns_test_end();
691*00b67f09SDavid van Moolenbroek }
692*00b67f09SDavid van Moolenbroek 
693*00b67f09SDavid van Moolenbroek ATF_TC(rbt_remove);
ATF_TC_HEAD(rbt_remove,tc)694*00b67f09SDavid van Moolenbroek ATF_TC_HEAD(rbt_remove, tc) {
695*00b67f09SDavid van Moolenbroek 	atf_tc_set_md_var(tc, "descr", "Test removal from a tree");
696*00b67f09SDavid van Moolenbroek }
ATF_TC_BODY(rbt_remove,tc)697*00b67f09SDavid van Moolenbroek ATF_TC_BODY(rbt_remove, tc) {
698*00b67f09SDavid van Moolenbroek 	/*
699*00b67f09SDavid van Moolenbroek 	 * This testcase checks that after node removal, the
700*00b67f09SDavid van Moolenbroek 	 * binary-search tree is valid and all nodes that are supposed
701*00b67f09SDavid van Moolenbroek 	 * to exist are present in the correct order. It mainly tests
702*00b67f09SDavid van Moolenbroek 	 * DomainTree as a BST, and not particularly as a red-black
703*00b67f09SDavid van Moolenbroek 	 * tree. This test checks node deletion when upper nodes have
704*00b67f09SDavid van Moolenbroek 	 * data.
705*00b67f09SDavid van Moolenbroek 	 */
706*00b67f09SDavid van Moolenbroek 	isc_result_t result;
707*00b67f09SDavid van Moolenbroek 	size_t j;
708*00b67f09SDavid van Moolenbroek 
709*00b67f09SDavid van Moolenbroek 	UNUSED(tc);
710*00b67f09SDavid van Moolenbroek 
711*00b67f09SDavid van Moolenbroek 	isc_mem_debugging = ISC_MEM_DEBUGRECORD;
712*00b67f09SDavid van Moolenbroek 
713*00b67f09SDavid van Moolenbroek 	result = dns_test_begin(NULL, ISC_TRUE);
714*00b67f09SDavid van Moolenbroek 	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
715*00b67f09SDavid van Moolenbroek 
716*00b67f09SDavid van Moolenbroek 	/*
717*00b67f09SDavid van Moolenbroek 	 * Delete single nodes and check if the rest of the nodes exist.
718*00b67f09SDavid van Moolenbroek 	 */
719*00b67f09SDavid van Moolenbroek 	for (j = 0; j < ordered_names_count; j++) {
720*00b67f09SDavid van Moolenbroek 		dns_rbt_t *mytree = NULL;
721*00b67f09SDavid van Moolenbroek 		dns_rbtnode_t *node;
722*00b67f09SDavid van Moolenbroek 		size_t i;
723*00b67f09SDavid van Moolenbroek 		size_t *n;
724*00b67f09SDavid van Moolenbroek 		isc_boolean_t tree_ok;
725*00b67f09SDavid van Moolenbroek 		dns_rbtnodechain_t chain;
726*00b67f09SDavid van Moolenbroek 		size_t start_node;
727*00b67f09SDavid van Moolenbroek 
728*00b67f09SDavid van Moolenbroek 		/* Create a tree. */
729*00b67f09SDavid van Moolenbroek 		result = dns_rbt_create(mctx, delete_data, NULL, &mytree);
730*00b67f09SDavid van Moolenbroek 		ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
731*00b67f09SDavid van Moolenbroek 
732*00b67f09SDavid van Moolenbroek 		/* Insert test data into the tree. */
733*00b67f09SDavid van Moolenbroek 		for (i = 0; i < domain_names_count; i++) {
734*00b67f09SDavid van Moolenbroek 			node = NULL;
735*00b67f09SDavid van Moolenbroek 			result = insert_helper(mytree, domain_names[i], &node);
736*00b67f09SDavid van Moolenbroek 			ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
737*00b67f09SDavid van Moolenbroek 		}
738*00b67f09SDavid van Moolenbroek 
739*00b67f09SDavid van Moolenbroek 		/* Check that all names exist in order. */
740*00b67f09SDavid van Moolenbroek 		for (i = 0; i < ordered_names_count; i++) {
741*00b67f09SDavid van Moolenbroek 			dns_fixedname_t fname;
742*00b67f09SDavid van Moolenbroek 			dns_name_t *name;
743*00b67f09SDavid van Moolenbroek 
744*00b67f09SDavid van Moolenbroek 			build_name_from_str(ordered_names[i], &fname);
745*00b67f09SDavid van Moolenbroek 
746*00b67f09SDavid van Moolenbroek 			name = dns_fixedname_name(&fname);
747*00b67f09SDavid van Moolenbroek 			node = NULL;
748*00b67f09SDavid van Moolenbroek 			result = dns_rbt_findnode(mytree, name, NULL,
749*00b67f09SDavid van Moolenbroek 						  &node, NULL,
750*00b67f09SDavid van Moolenbroek 						  DNS_RBTFIND_EMPTYDATA,
751*00b67f09SDavid van Moolenbroek 						  NULL, NULL);
752*00b67f09SDavid van Moolenbroek 			ATF_CHECK_EQ(result, ISC_R_SUCCESS);
753*00b67f09SDavid van Moolenbroek 
754*00b67f09SDavid van Moolenbroek 			/* Add node data */
755*00b67f09SDavid van Moolenbroek 			ATF_REQUIRE(node != NULL);
756*00b67f09SDavid van Moolenbroek 			ATF_REQUIRE_EQ(node->data, NULL);
757*00b67f09SDavid van Moolenbroek 
758*00b67f09SDavid van Moolenbroek 			n = isc_mem_get(mctx, sizeof(size_t));
759*00b67f09SDavid van Moolenbroek 			*n = i;
760*00b67f09SDavid van Moolenbroek 
761*00b67f09SDavid van Moolenbroek 			node->data = n;
762*00b67f09SDavid van Moolenbroek 		}
763*00b67f09SDavid van Moolenbroek 
764*00b67f09SDavid van Moolenbroek 		/* Now, delete the j'th node from the tree. */
765*00b67f09SDavid van Moolenbroek 		{
766*00b67f09SDavid van Moolenbroek 			dns_fixedname_t fname;
767*00b67f09SDavid van Moolenbroek 			dns_name_t *name;
768*00b67f09SDavid van Moolenbroek 
769*00b67f09SDavid van Moolenbroek 			build_name_from_str(ordered_names[j], &fname);
770*00b67f09SDavid van Moolenbroek 
771*00b67f09SDavid van Moolenbroek 			name = dns_fixedname_name(&fname);
772*00b67f09SDavid van Moolenbroek 
773*00b67f09SDavid van Moolenbroek 			result = dns_rbt_deletename(mytree, name, ISC_FALSE);
774*00b67f09SDavid van Moolenbroek 			ATF_CHECK_EQ(result, ISC_R_SUCCESS);
775*00b67f09SDavid van Moolenbroek 		}
776*00b67f09SDavid van Moolenbroek 
777*00b67f09SDavid van Moolenbroek 		/* Check RB tree properties. */
778*00b67f09SDavid van Moolenbroek 		tree_ok = dns__rbt_checkproperties(mytree);
779*00b67f09SDavid van Moolenbroek 		ATF_CHECK_EQ(tree_ok, ISC_TRUE);
780*00b67f09SDavid van Moolenbroek 
781*00b67f09SDavid van Moolenbroek 		dns_rbtnodechain_init(&chain, mctx);
782*00b67f09SDavid van Moolenbroek 
783*00b67f09SDavid van Moolenbroek 		/* Now, walk through nodes in order. */
784*00b67f09SDavid van Moolenbroek 		if (j == 0) {
785*00b67f09SDavid van Moolenbroek 			/*
786*00b67f09SDavid van Moolenbroek 			 * Node for ordered_names[0] was already deleted
787*00b67f09SDavid van Moolenbroek 			 * above. We start from node 1.
788*00b67f09SDavid van Moolenbroek 			 */
789*00b67f09SDavid van Moolenbroek 			dns_fixedname_t fname;
790*00b67f09SDavid van Moolenbroek 			dns_name_t *name;
791*00b67f09SDavid van Moolenbroek 
792*00b67f09SDavid van Moolenbroek 			build_name_from_str(ordered_names[0], &fname);
793*00b67f09SDavid van Moolenbroek 			name = dns_fixedname_name(&fname);
794*00b67f09SDavid van Moolenbroek 			node = NULL;
795*00b67f09SDavid van Moolenbroek 			result = dns_rbt_findnode(mytree, name, NULL,
796*00b67f09SDavid van Moolenbroek 						  &node, NULL,
797*00b67f09SDavid van Moolenbroek 						  0,
798*00b67f09SDavid van Moolenbroek 						  NULL, NULL);
799*00b67f09SDavid van Moolenbroek 			ATF_CHECK_EQ(result, ISC_R_NOTFOUND);
800*00b67f09SDavid van Moolenbroek 
801*00b67f09SDavid van Moolenbroek 			build_name_from_str(ordered_names[1], &fname);
802*00b67f09SDavid van Moolenbroek 			name = dns_fixedname_name(&fname);
803*00b67f09SDavid van Moolenbroek 			node = NULL;
804*00b67f09SDavid van Moolenbroek 			result = dns_rbt_findnode(mytree, name, NULL,
805*00b67f09SDavid van Moolenbroek 						  &node, &chain,
806*00b67f09SDavid van Moolenbroek 						  0,
807*00b67f09SDavid van Moolenbroek 						  NULL, NULL);
808*00b67f09SDavid van Moolenbroek 			ATF_CHECK_EQ(result, ISC_R_SUCCESS);
809*00b67f09SDavid van Moolenbroek 			start_node = 1;
810*00b67f09SDavid van Moolenbroek 		} else {
811*00b67f09SDavid van Moolenbroek 			/* Start from node 0. */
812*00b67f09SDavid van Moolenbroek 			dns_fixedname_t fname;
813*00b67f09SDavid van Moolenbroek 			dns_name_t *name;
814*00b67f09SDavid van Moolenbroek 
815*00b67f09SDavid van Moolenbroek 			build_name_from_str(ordered_names[0], &fname);
816*00b67f09SDavid van Moolenbroek 			name = dns_fixedname_name(&fname);
817*00b67f09SDavid van Moolenbroek 			node = NULL;
818*00b67f09SDavid van Moolenbroek 			result = dns_rbt_findnode(mytree, name, NULL,
819*00b67f09SDavid van Moolenbroek 						  &node, &chain,
820*00b67f09SDavid van Moolenbroek 						  0,
821*00b67f09SDavid van Moolenbroek 						  NULL, NULL);
822*00b67f09SDavid van Moolenbroek 			ATF_CHECK_EQ(result, ISC_R_SUCCESS);
823*00b67f09SDavid van Moolenbroek 			start_node = 0;
824*00b67f09SDavid van Moolenbroek 		}
825*00b67f09SDavid van Moolenbroek 
826*00b67f09SDavid van Moolenbroek 		/*
827*00b67f09SDavid van Moolenbroek 		 * node and chain have been set by the code above at
828*00b67f09SDavid van Moolenbroek 		 * this point.
829*00b67f09SDavid van Moolenbroek 		 */
830*00b67f09SDavid van Moolenbroek 		for (i = start_node; i < ordered_names_count; i++) {
831*00b67f09SDavid van Moolenbroek 			dns_fixedname_t fname_j, fname_i;
832*00b67f09SDavid van Moolenbroek 			dns_name_t *name_j, *name_i;
833*00b67f09SDavid van Moolenbroek 
834*00b67f09SDavid van Moolenbroek 			build_name_from_str(ordered_names[j], &fname_j);
835*00b67f09SDavid van Moolenbroek 			name_j = dns_fixedname_name(&fname_j);
836*00b67f09SDavid van Moolenbroek 			build_name_from_str(ordered_names[i], &fname_i);
837*00b67f09SDavid van Moolenbroek 			name_i = dns_fixedname_name(&fname_i);
838*00b67f09SDavid van Moolenbroek 
839*00b67f09SDavid van Moolenbroek 			if (dns_name_equal(name_i, name_j)) {
840*00b67f09SDavid van Moolenbroek 				/*
841*00b67f09SDavid van Moolenbroek 				 * This may be true for the last node if
842*00b67f09SDavid van Moolenbroek 				 * we seek ahead in the loop using
843*00b67f09SDavid van Moolenbroek 				 * dns_rbtnodechain_next() below.
844*00b67f09SDavid van Moolenbroek 				 */
845*00b67f09SDavid van Moolenbroek 				if (node == NULL) {
846*00b67f09SDavid van Moolenbroek 					break;
847*00b67f09SDavid van Moolenbroek 				}
848*00b67f09SDavid van Moolenbroek 
849*00b67f09SDavid van Moolenbroek 				/* All ordered nodes have data
850*00b67f09SDavid van Moolenbroek 				 * initially. If any node is empty, it
851*00b67f09SDavid van Moolenbroek 				 * means it was removed, but an empty
852*00b67f09SDavid van Moolenbroek 				 * node exists because it is a
853*00b67f09SDavid van Moolenbroek 				 * super-domain. Just skip it.
854*00b67f09SDavid van Moolenbroek 				 */
855*00b67f09SDavid van Moolenbroek 				if (node->data == NULL) {
856*00b67f09SDavid van Moolenbroek 					result = dns_rbtnodechain_next(&chain,
857*00b67f09SDavid van Moolenbroek 								       NULL,
858*00b67f09SDavid van Moolenbroek 								       NULL);
859*00b67f09SDavid van Moolenbroek 					if (result == ISC_R_NOMORE) {
860*00b67f09SDavid van Moolenbroek 						node = NULL;
861*00b67f09SDavid van Moolenbroek 					} else {
862*00b67f09SDavid van Moolenbroek 						dns_rbtnodechain_current(&chain,
863*00b67f09SDavid van Moolenbroek 									 NULL,
864*00b67f09SDavid van Moolenbroek 									 NULL,
865*00b67f09SDavid van Moolenbroek 									 &node);
866*00b67f09SDavid van Moolenbroek 					}
867*00b67f09SDavid van Moolenbroek 				}
868*00b67f09SDavid van Moolenbroek 				continue;
869*00b67f09SDavid van Moolenbroek 			}
870*00b67f09SDavid van Moolenbroek 
871*00b67f09SDavid van Moolenbroek 			ATF_REQUIRE(node != NULL);
872*00b67f09SDavid van Moolenbroek 
873*00b67f09SDavid van Moolenbroek 			n = (size_t *) node->data;
874*00b67f09SDavid van Moolenbroek 			if (n != NULL) {
875*00b67f09SDavid van Moolenbroek 				/* printf("n=%zu, i=%zu\n", *n, i); */
876*00b67f09SDavid van Moolenbroek 				ATF_CHECK_EQ(*n, i);
877*00b67f09SDavid van Moolenbroek 			}
878*00b67f09SDavid van Moolenbroek 
879*00b67f09SDavid van Moolenbroek 			result = dns_rbtnodechain_next(&chain, NULL, NULL);
880*00b67f09SDavid van Moolenbroek 			if (result == ISC_R_NOMORE) {
881*00b67f09SDavid van Moolenbroek 				node = NULL;
882*00b67f09SDavid van Moolenbroek 			} else {
883*00b67f09SDavid van Moolenbroek 				dns_rbtnodechain_current(&chain, NULL, NULL,
884*00b67f09SDavid van Moolenbroek 							 &node);
885*00b67f09SDavid van Moolenbroek 			}
886*00b67f09SDavid van Moolenbroek 		}
887*00b67f09SDavid van Moolenbroek 
888*00b67f09SDavid van Moolenbroek 		/* We should have reached the end of the tree. */
889*00b67f09SDavid van Moolenbroek 		ATF_REQUIRE_EQ(node, NULL);
890*00b67f09SDavid van Moolenbroek 
891*00b67f09SDavid van Moolenbroek 		dns_rbt_destroy(&mytree);
892*00b67f09SDavid van Moolenbroek 	}
893*00b67f09SDavid van Moolenbroek 
894*00b67f09SDavid van Moolenbroek 	dns_test_end();
895*00b67f09SDavid van Moolenbroek }
896*00b67f09SDavid van Moolenbroek 
897*00b67f09SDavid van Moolenbroek ATF_TC(rbt_remove_empty);
ATF_TC_HEAD(rbt_remove_empty,tc)898*00b67f09SDavid van Moolenbroek ATF_TC_HEAD(rbt_remove_empty, tc) {
899*00b67f09SDavid van Moolenbroek 	atf_tc_set_md_var(tc, "descr",
900*00b67f09SDavid van Moolenbroek 			  "Test removal from a tree when "
901*00b67f09SDavid van Moolenbroek 			  "upper nodes are empty");
902*00b67f09SDavid van Moolenbroek }
ATF_TC_BODY(rbt_remove_empty,tc)903*00b67f09SDavid van Moolenbroek ATF_TC_BODY(rbt_remove_empty, tc) {
904*00b67f09SDavid van Moolenbroek 	/*
905*00b67f09SDavid van Moolenbroek 	 * This test is similar to the rbt_remove test, but checks node
906*00b67f09SDavid van Moolenbroek 	 * deletion when upper nodes are empty.
907*00b67f09SDavid van Moolenbroek 	 */
908*00b67f09SDavid van Moolenbroek 	isc_result_t result;
909*00b67f09SDavid van Moolenbroek 	size_t j;
910*00b67f09SDavid van Moolenbroek 
911*00b67f09SDavid van Moolenbroek 	UNUSED(tc);
912*00b67f09SDavid van Moolenbroek 
913*00b67f09SDavid van Moolenbroek 	isc_mem_debugging = ISC_MEM_DEBUGRECORD;
914*00b67f09SDavid van Moolenbroek 
915*00b67f09SDavid van Moolenbroek 	result = dns_test_begin(NULL, ISC_TRUE);
916*00b67f09SDavid van Moolenbroek 	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
917*00b67f09SDavid van Moolenbroek 
918*00b67f09SDavid van Moolenbroek 	/*
919*00b67f09SDavid van Moolenbroek 	 * Delete single nodes and check if the rest of the nodes exist.
920*00b67f09SDavid van Moolenbroek 	 */
921*00b67f09SDavid van Moolenbroek 	for (j = 0; j < ordered_names_count; j++) {
922*00b67f09SDavid van Moolenbroek 		dns_rbt_t *mytree = NULL;
923*00b67f09SDavid van Moolenbroek 		dns_rbtnode_t *node;
924*00b67f09SDavid van Moolenbroek 		size_t i;
925*00b67f09SDavid van Moolenbroek 		isc_boolean_t tree_ok;
926*00b67f09SDavid van Moolenbroek 		dns_rbtnodechain_t chain;
927*00b67f09SDavid van Moolenbroek 		size_t start_node;
928*00b67f09SDavid van Moolenbroek 
929*00b67f09SDavid van Moolenbroek 		/* Create a tree. */
930*00b67f09SDavid van Moolenbroek 		result = dns_rbt_create(mctx, delete_data, NULL, &mytree);
931*00b67f09SDavid van Moolenbroek 		ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
932*00b67f09SDavid van Moolenbroek 
933*00b67f09SDavid van Moolenbroek 		/* Insert test data into the tree. */
934*00b67f09SDavid van Moolenbroek 		for (i = 0; i < domain_names_count; i++) {
935*00b67f09SDavid van Moolenbroek 			node = NULL;
936*00b67f09SDavid van Moolenbroek 			result = insert_helper(mytree, domain_names[i], &node);
937*00b67f09SDavid van Moolenbroek 			ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
938*00b67f09SDavid van Moolenbroek 		}
939*00b67f09SDavid van Moolenbroek 
940*00b67f09SDavid van Moolenbroek 		/* Check that all names exist in order. */
941*00b67f09SDavid van Moolenbroek 		for (i = 0; i < ordered_names_count; i++) {
942*00b67f09SDavid van Moolenbroek 			dns_fixedname_t fname;
943*00b67f09SDavid van Moolenbroek 			dns_name_t *name;
944*00b67f09SDavid van Moolenbroek 
945*00b67f09SDavid van Moolenbroek 			build_name_from_str(ordered_names[i], &fname);
946*00b67f09SDavid van Moolenbroek 
947*00b67f09SDavid van Moolenbroek 			name = dns_fixedname_name(&fname);
948*00b67f09SDavid van Moolenbroek 			node = NULL;
949*00b67f09SDavid van Moolenbroek 			result = dns_rbt_findnode(mytree, name, NULL,
950*00b67f09SDavid van Moolenbroek 						  &node, NULL,
951*00b67f09SDavid van Moolenbroek 						  DNS_RBTFIND_EMPTYDATA,
952*00b67f09SDavid van Moolenbroek 						  NULL, NULL);
953*00b67f09SDavid van Moolenbroek 			ATF_CHECK_EQ(result, ISC_R_SUCCESS);
954*00b67f09SDavid van Moolenbroek 
955*00b67f09SDavid van Moolenbroek 			/* Check that node data is empty */
956*00b67f09SDavid van Moolenbroek 			ATF_REQUIRE(node != NULL);
957*00b67f09SDavid van Moolenbroek 			ATF_REQUIRE_EQ(node->data, NULL);
958*00b67f09SDavid van Moolenbroek 		}
959*00b67f09SDavid van Moolenbroek 
960*00b67f09SDavid van Moolenbroek 		/* Now, delete the j'th node from the tree. */
961*00b67f09SDavid van Moolenbroek 		{
962*00b67f09SDavid van Moolenbroek 			dns_fixedname_t fname;
963*00b67f09SDavid van Moolenbroek 			dns_name_t *name;
964*00b67f09SDavid van Moolenbroek 
965*00b67f09SDavid van Moolenbroek 			build_name_from_str(ordered_names[j], &fname);
966*00b67f09SDavid van Moolenbroek 
967*00b67f09SDavid van Moolenbroek 			name = dns_fixedname_name(&fname);
968*00b67f09SDavid van Moolenbroek 
969*00b67f09SDavid van Moolenbroek 			node = NULL;
970*00b67f09SDavid van Moolenbroek 			result = dns_rbt_findnode(mytree, name, NULL, &node,
971*00b67f09SDavid van Moolenbroek 						  NULL, DNS_RBTFIND_EMPTYDATA,
972*00b67f09SDavid van Moolenbroek 						  NULL, NULL);
973*00b67f09SDavid van Moolenbroek 			ATF_CHECK_EQ(result, ISC_R_SUCCESS);
974*00b67f09SDavid van Moolenbroek 
975*00b67f09SDavid van Moolenbroek 			result = dns_rbt_deletenode(mytree, node, ISC_FALSE);
976*00b67f09SDavid van Moolenbroek 			ATF_CHECK_EQ(result, ISC_R_SUCCESS);
977*00b67f09SDavid van Moolenbroek 		}
978*00b67f09SDavid van Moolenbroek 
979*00b67f09SDavid van Moolenbroek 		/* Check RB tree properties. */
980*00b67f09SDavid van Moolenbroek 		tree_ok = dns__rbt_checkproperties(mytree);
981*00b67f09SDavid van Moolenbroek 		ATF_CHECK_EQ(tree_ok, ISC_TRUE);
982*00b67f09SDavid van Moolenbroek 
983*00b67f09SDavid van Moolenbroek 		dns_rbtnodechain_init(&chain, mctx);
984*00b67f09SDavid van Moolenbroek 
985*00b67f09SDavid van Moolenbroek 		/* Now, walk through nodes in order. */
986*00b67f09SDavid van Moolenbroek 		if (j == 0) {
987*00b67f09SDavid van Moolenbroek 			/*
988*00b67f09SDavid van Moolenbroek 			 * Node for ordered_names[0] was already deleted
989*00b67f09SDavid van Moolenbroek 			 * above. We start from node 1.
990*00b67f09SDavid van Moolenbroek 			 */
991*00b67f09SDavid van Moolenbroek 			dns_fixedname_t fname;
992*00b67f09SDavid van Moolenbroek 			dns_name_t *name;
993*00b67f09SDavid van Moolenbroek 
994*00b67f09SDavid van Moolenbroek 			build_name_from_str(ordered_names[0], &fname);
995*00b67f09SDavid van Moolenbroek 			name = dns_fixedname_name(&fname);
996*00b67f09SDavid van Moolenbroek 			node = NULL;
997*00b67f09SDavid van Moolenbroek 			result = dns_rbt_findnode(mytree, name, NULL,
998*00b67f09SDavid van Moolenbroek 						  &node, NULL,
999*00b67f09SDavid van Moolenbroek 						  DNS_RBTFIND_EMPTYDATA,
1000*00b67f09SDavid van Moolenbroek 						  NULL, NULL);
1001*00b67f09SDavid van Moolenbroek 			ATF_CHECK(result != ISC_R_SUCCESS);
1002*00b67f09SDavid van Moolenbroek 
1003*00b67f09SDavid van Moolenbroek 			build_name_from_str(ordered_names[1], &fname);
1004*00b67f09SDavid van Moolenbroek 			name = dns_fixedname_name(&fname);
1005*00b67f09SDavid van Moolenbroek 			node = NULL;
1006*00b67f09SDavid van Moolenbroek 			result = dns_rbt_findnode(mytree, name, NULL,
1007*00b67f09SDavid van Moolenbroek 						  &node, &chain,
1008*00b67f09SDavid van Moolenbroek 						  DNS_RBTFIND_EMPTYDATA,
1009*00b67f09SDavid van Moolenbroek 						  NULL, NULL);
1010*00b67f09SDavid van Moolenbroek 			ATF_CHECK_EQ(result, ISC_R_SUCCESS);
1011*00b67f09SDavid van Moolenbroek 			start_node = 1;
1012*00b67f09SDavid van Moolenbroek 		} else {
1013*00b67f09SDavid van Moolenbroek 			/* Start from node 0. */
1014*00b67f09SDavid van Moolenbroek 			dns_fixedname_t fname;
1015*00b67f09SDavid van Moolenbroek 			dns_name_t *name;
1016*00b67f09SDavid van Moolenbroek 
1017*00b67f09SDavid van Moolenbroek 			build_name_from_str(ordered_names[0], &fname);
1018*00b67f09SDavid van Moolenbroek 			name = dns_fixedname_name(&fname);
1019*00b67f09SDavid van Moolenbroek 			node = NULL;
1020*00b67f09SDavid van Moolenbroek 			result = dns_rbt_findnode(mytree, name, NULL,
1021*00b67f09SDavid van Moolenbroek 						  &node, &chain,
1022*00b67f09SDavid van Moolenbroek 						  DNS_RBTFIND_EMPTYDATA,
1023*00b67f09SDavid van Moolenbroek 						  NULL, NULL);
1024*00b67f09SDavid van Moolenbroek 			ATF_CHECK_EQ(result, ISC_R_SUCCESS);
1025*00b67f09SDavid van Moolenbroek 			start_node = 0;
1026*00b67f09SDavid van Moolenbroek 		}
1027*00b67f09SDavid van Moolenbroek 
1028*00b67f09SDavid van Moolenbroek 		/*
1029*00b67f09SDavid van Moolenbroek 		 * node and chain have been set by the code above at
1030*00b67f09SDavid van Moolenbroek 		 * this point.
1031*00b67f09SDavid van Moolenbroek 		 */
1032*00b67f09SDavid van Moolenbroek 		for (i = start_node; i < ordered_names_count; i++) {
1033*00b67f09SDavid van Moolenbroek 			dns_fixedname_t fntmp1, fntmp2;
1034*00b67f09SDavid van Moolenbroek 			dns_name_t *ntmp1, *ntmp2;
1035*00b67f09SDavid van Moolenbroek 			dns_fixedname_t fname_j, fname_i;
1036*00b67f09SDavid van Moolenbroek 			dns_name_t *name_j, *name_i;
1037*00b67f09SDavid van Moolenbroek 
1038*00b67f09SDavid van Moolenbroek 			build_name_from_str("j.z.d.e.f", &fntmp1);
1039*00b67f09SDavid van Moolenbroek 			ntmp1 = dns_fixedname_name(&fntmp1);
1040*00b67f09SDavid van Moolenbroek 			build_name_from_str("z.d.e.f", &fntmp2);
1041*00b67f09SDavid van Moolenbroek 			ntmp2 = dns_fixedname_name(&fntmp2);
1042*00b67f09SDavid van Moolenbroek 
1043*00b67f09SDavid van Moolenbroek 			build_name_from_str(ordered_names[j], &fname_j);
1044*00b67f09SDavid van Moolenbroek 			name_j = dns_fixedname_name(&fname_j);
1045*00b67f09SDavid van Moolenbroek 			build_name_from_str(ordered_names[i], &fname_i);
1046*00b67f09SDavid van Moolenbroek 			name_i = dns_fixedname_name(&fname_i);
1047*00b67f09SDavid van Moolenbroek 
1048*00b67f09SDavid van Moolenbroek 			if (dns_name_equal(name_j, ntmp1) &&
1049*00b67f09SDavid van Moolenbroek 			    dns_name_equal(name_j, ntmp2))
1050*00b67f09SDavid van Moolenbroek 			{
1051*00b67f09SDavid van Moolenbroek 				/*
1052*00b67f09SDavid van Moolenbroek 				 * The only special case in the
1053*00b67f09SDavid van Moolenbroek 				 * tree. Here, "z.d.e.f" will not exist
1054*00b67f09SDavid van Moolenbroek 				 * as it would have been removed during
1055*00b67f09SDavid van Moolenbroek 				 * removal of "j.z.d.e.f".
1056*00b67f09SDavid van Moolenbroek 				 */
1057*00b67f09SDavid van Moolenbroek 				continue;
1058*00b67f09SDavid van Moolenbroek 			}
1059*00b67f09SDavid van Moolenbroek 
1060*00b67f09SDavid van Moolenbroek 			if (dns_name_equal(name_i, name_j)) {
1061*00b67f09SDavid van Moolenbroek 				dns_fixedname_t fntmp3, fntmp4, fntmp5, fntmp6;
1062*00b67f09SDavid van Moolenbroek 				dns_name_t *ntmp3, *ntmp4, *ntmp5, *ntmp6;
1063*00b67f09SDavid van Moolenbroek 
1064*00b67f09SDavid van Moolenbroek 				/*
1065*00b67f09SDavid van Moolenbroek 				 * This may be true for the last node if
1066*00b67f09SDavid van Moolenbroek 				 * we seek ahead in the loop using
1067*00b67f09SDavid van Moolenbroek 				 * dns_rbtnodechain_next() below.
1068*00b67f09SDavid van Moolenbroek 				 */
1069*00b67f09SDavid van Moolenbroek 				if (node == NULL) {
1070*00b67f09SDavid van Moolenbroek 					break;
1071*00b67f09SDavid van Moolenbroek 				}
1072*00b67f09SDavid van Moolenbroek 
1073*00b67f09SDavid van Moolenbroek 				/*
1074*00b67f09SDavid van Moolenbroek 				 * All ordered nodes are empty
1075*00b67f09SDavid van Moolenbroek 				 * initially. If an empty removed node
1076*00b67f09SDavid van Moolenbroek 				 * exists because it is a super-domain,
1077*00b67f09SDavid van Moolenbroek 				 * just skip it.
1078*00b67f09SDavid van Moolenbroek 				 */
1079*00b67f09SDavid van Moolenbroek 				build_name_from_str("d.e.f", &fntmp3);
1080*00b67f09SDavid van Moolenbroek 				ntmp3 = dns_fixedname_name(&fntmp3);
1081*00b67f09SDavid van Moolenbroek 				build_name_from_str("w.y.d.e.f", &fntmp4);
1082*00b67f09SDavid van Moolenbroek 				ntmp4 = dns_fixedname_name(&fntmp4);
1083*00b67f09SDavid van Moolenbroek 				build_name_from_str("z.d.e.f", &fntmp5);
1084*00b67f09SDavid van Moolenbroek 				ntmp5 = dns_fixedname_name(&fntmp5);
1085*00b67f09SDavid van Moolenbroek 				build_name_from_str("g.h", &fntmp6);
1086*00b67f09SDavid van Moolenbroek 				ntmp6 = dns_fixedname_name(&fntmp6);
1087*00b67f09SDavid van Moolenbroek 
1088*00b67f09SDavid van Moolenbroek 				if (dns_name_equal(name_j, ntmp3) ||
1089*00b67f09SDavid van Moolenbroek 				    dns_name_equal(name_j, ntmp4) ||
1090*00b67f09SDavid van Moolenbroek 				    dns_name_equal(name_j, ntmp5) ||
1091*00b67f09SDavid van Moolenbroek 				    dns_name_equal(name_j, ntmp6))
1092*00b67f09SDavid van Moolenbroek 				{
1093*00b67f09SDavid van Moolenbroek 					result = dns_rbtnodechain_next(&chain,
1094*00b67f09SDavid van Moolenbroek 								       NULL,
1095*00b67f09SDavid van Moolenbroek 								       NULL);
1096*00b67f09SDavid van Moolenbroek 					if (result == ISC_R_NOMORE) {
1097*00b67f09SDavid van Moolenbroek 						node = NULL;
1098*00b67f09SDavid van Moolenbroek 					} else {
1099*00b67f09SDavid van Moolenbroek 						dns_rbtnodechain_current(&chain,
1100*00b67f09SDavid van Moolenbroek 									 NULL,
1101*00b67f09SDavid van Moolenbroek 									 NULL,
1102*00b67f09SDavid van Moolenbroek 									 &node);
1103*00b67f09SDavid van Moolenbroek 					}
1104*00b67f09SDavid van Moolenbroek 				}
1105*00b67f09SDavid van Moolenbroek 				continue;
1106*00b67f09SDavid van Moolenbroek 			}
1107*00b67f09SDavid van Moolenbroek 
1108*00b67f09SDavid van Moolenbroek 			ATF_REQUIRE(node != NULL);
1109*00b67f09SDavid van Moolenbroek 
1110*00b67f09SDavid van Moolenbroek 			result = dns_rbtnodechain_next(&chain, NULL, NULL);
1111*00b67f09SDavid van Moolenbroek 			if (result == ISC_R_NOMORE) {
1112*00b67f09SDavid van Moolenbroek 				node = NULL;
1113*00b67f09SDavid van Moolenbroek 			} else {
1114*00b67f09SDavid van Moolenbroek 				dns_rbtnodechain_current(&chain, NULL, NULL,
1115*00b67f09SDavid van Moolenbroek 							 &node);
1116*00b67f09SDavid van Moolenbroek 			}
1117*00b67f09SDavid van Moolenbroek 		}
1118*00b67f09SDavid van Moolenbroek 
1119*00b67f09SDavid van Moolenbroek 		/* We should have reached the end of the tree. */
1120*00b67f09SDavid van Moolenbroek 		ATF_REQUIRE_EQ(node, NULL);
1121*00b67f09SDavid van Moolenbroek 
1122*00b67f09SDavid van Moolenbroek 		dns_rbt_destroy(&mytree);
1123*00b67f09SDavid van Moolenbroek 	}
1124*00b67f09SDavid van Moolenbroek 
1125*00b67f09SDavid van Moolenbroek 	dns_test_end();
1126*00b67f09SDavid van Moolenbroek }
1127*00b67f09SDavid van Moolenbroek 
1128*00b67f09SDavid van Moolenbroek static void
insert_nodes(dns_rbt_t * mytree,char ** names,size_t * names_count,isc_uint32_t num_names)1129*00b67f09SDavid van Moolenbroek insert_nodes(dns_rbt_t *mytree, char **names,
1130*00b67f09SDavid van Moolenbroek 	     size_t *names_count, isc_uint32_t num_names)
1131*00b67f09SDavid van Moolenbroek {
1132*00b67f09SDavid van Moolenbroek 	isc_uint32_t i;
1133*00b67f09SDavid van Moolenbroek 
1134*00b67f09SDavid van Moolenbroek 	for (i = 0; i < num_names; i++) {
1135*00b67f09SDavid van Moolenbroek 		size_t *n;
1136*00b67f09SDavid van Moolenbroek 		char namebuf[34];
1137*00b67f09SDavid van Moolenbroek 
1138*00b67f09SDavid van Moolenbroek 		n = isc_mem_get(mctx, sizeof(size_t));
1139*00b67f09SDavid van Moolenbroek 		*n = i; /* Unused value */
1140*00b67f09SDavid van Moolenbroek 
1141*00b67f09SDavid van Moolenbroek 		while (1) {
1142*00b67f09SDavid van Moolenbroek 			int j;
1143*00b67f09SDavid van Moolenbroek 			dns_fixedname_t fname;
1144*00b67f09SDavid van Moolenbroek 			dns_name_t *name;
1145*00b67f09SDavid van Moolenbroek 			isc_result_t result;
1146*00b67f09SDavid van Moolenbroek 
1147*00b67f09SDavid van Moolenbroek 			for (j = 0; j < 32; j++) {
1148*00b67f09SDavid van Moolenbroek 				isc_uint32_t v;
1149*00b67f09SDavid van Moolenbroek 				isc_random_get(&v);
1150*00b67f09SDavid van Moolenbroek 				namebuf[j] = 'a' + (v % 26);
1151*00b67f09SDavid van Moolenbroek 			}
1152*00b67f09SDavid van Moolenbroek 			namebuf[32] = '.';
1153*00b67f09SDavid van Moolenbroek 			namebuf[33] = 0;
1154*00b67f09SDavid van Moolenbroek 
1155*00b67f09SDavid van Moolenbroek 			build_name_from_str(namebuf, &fname);
1156*00b67f09SDavid van Moolenbroek 			name = dns_fixedname_name(&fname);
1157*00b67f09SDavid van Moolenbroek 
1158*00b67f09SDavid van Moolenbroek 			result = dns_rbt_addname(mytree, name, n);
1159*00b67f09SDavid van Moolenbroek 			if (result == ISC_R_SUCCESS) {
1160*00b67f09SDavid van Moolenbroek 				names[*names_count] = isc_mem_strdup(mctx,
1161*00b67f09SDavid van Moolenbroek 								     namebuf);
1162*00b67f09SDavid van Moolenbroek 				*names_count += 1;
1163*00b67f09SDavid van Moolenbroek 				break;
1164*00b67f09SDavid van Moolenbroek 			}
1165*00b67f09SDavid van Moolenbroek 		}
1166*00b67f09SDavid van Moolenbroek 	}
1167*00b67f09SDavid van Moolenbroek }
1168*00b67f09SDavid van Moolenbroek 
1169*00b67f09SDavid van Moolenbroek static void
remove_nodes(dns_rbt_t * mytree,char ** names,size_t * names_count,isc_uint32_t num_names)1170*00b67f09SDavid van Moolenbroek remove_nodes(dns_rbt_t *mytree, char **names,
1171*00b67f09SDavid van Moolenbroek 	     size_t *names_count, isc_uint32_t num_names)
1172*00b67f09SDavid van Moolenbroek {
1173*00b67f09SDavid van Moolenbroek 	isc_uint32_t i;
1174*00b67f09SDavid van Moolenbroek 
1175*00b67f09SDavid van Moolenbroek 	UNUSED(mytree);
1176*00b67f09SDavid van Moolenbroek 
1177*00b67f09SDavid van Moolenbroek 	for (i = 0; i < num_names; i++) {
1178*00b67f09SDavid van Moolenbroek 		isc_uint32_t node;
1179*00b67f09SDavid van Moolenbroek 		dns_fixedname_t fname;
1180*00b67f09SDavid van Moolenbroek 		dns_name_t *name;
1181*00b67f09SDavid van Moolenbroek 		isc_result_t result;
1182*00b67f09SDavid van Moolenbroek 
1183*00b67f09SDavid van Moolenbroek 		isc_random_get(&node);
1184*00b67f09SDavid van Moolenbroek 
1185*00b67f09SDavid van Moolenbroek 		node %= *names_count;
1186*00b67f09SDavid van Moolenbroek 
1187*00b67f09SDavid van Moolenbroek 		build_name_from_str(names[node], &fname);
1188*00b67f09SDavid van Moolenbroek 		name = dns_fixedname_name(&fname);
1189*00b67f09SDavid van Moolenbroek 
1190*00b67f09SDavid van Moolenbroek 		result = dns_rbt_deletename(mytree, name, ISC_FALSE);
1191*00b67f09SDavid van Moolenbroek 		ATF_CHECK_EQ(result, ISC_R_SUCCESS);
1192*00b67f09SDavid van Moolenbroek 
1193*00b67f09SDavid van Moolenbroek 		isc_mem_free(mctx, names[node]);
1194*00b67f09SDavid van Moolenbroek 		if (*names_count > 0) {
1195*00b67f09SDavid van Moolenbroek 			names[node] = names[*names_count - 1];
1196*00b67f09SDavid van Moolenbroek 			names[*names_count - 1] = NULL;
1197*00b67f09SDavid van Moolenbroek 			*names_count -= 1;
1198*00b67f09SDavid van Moolenbroek 		}
1199*00b67f09SDavid van Moolenbroek 	}
1200*00b67f09SDavid van Moolenbroek }
1201*00b67f09SDavid van Moolenbroek 
1202*00b67f09SDavid van Moolenbroek static void
check_tree(dns_rbt_t * mytree,char ** names,size_t names_count)1203*00b67f09SDavid van Moolenbroek check_tree(dns_rbt_t *mytree, char **names, size_t names_count) {
1204*00b67f09SDavid van Moolenbroek 	isc_boolean_t tree_ok;
1205*00b67f09SDavid van Moolenbroek 
1206*00b67f09SDavid van Moolenbroek 	UNUSED(names);
1207*00b67f09SDavid van Moolenbroek 
1208*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(names_count + 1, dns_rbt_nodecount(mytree));
1209*00b67f09SDavid van Moolenbroek 
1210*00b67f09SDavid van Moolenbroek 	/*
1211*00b67f09SDavid van Moolenbroek 	 * The distance from each node to its sub-tree root must be less
1212*00b67f09SDavid van Moolenbroek 	 * than 2 * log_2(1024).
1213*00b67f09SDavid van Moolenbroek 	 */
1214*00b67f09SDavid van Moolenbroek 	ATF_CHECK((2 * 10) >= dns__rbt_getheight(mytree));
1215*00b67f09SDavid van Moolenbroek 
1216*00b67f09SDavid van Moolenbroek 	/* Also check RB tree properties */
1217*00b67f09SDavid van Moolenbroek 	tree_ok = dns__rbt_checkproperties(mytree);
1218*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(tree_ok, ISC_TRUE);
1219*00b67f09SDavid van Moolenbroek }
1220*00b67f09SDavid van Moolenbroek 
1221*00b67f09SDavid van Moolenbroek ATF_TC(rbt_insert_and_remove);
ATF_TC_HEAD(rbt_insert_and_remove,tc)1222*00b67f09SDavid van Moolenbroek ATF_TC_HEAD(rbt_insert_and_remove, tc) {
1223*00b67f09SDavid van Moolenbroek 	atf_tc_set_md_var(tc, "descr",
1224*00b67f09SDavid van Moolenbroek 			  "Test insert and remove in a loop");
1225*00b67f09SDavid van Moolenbroek }
ATF_TC_BODY(rbt_insert_and_remove,tc)1226*00b67f09SDavid van Moolenbroek ATF_TC_BODY(rbt_insert_and_remove, tc) {
1227*00b67f09SDavid van Moolenbroek 	/*
1228*00b67f09SDavid van Moolenbroek 	 * What is the best way to test our red-black tree code? It is
1229*00b67f09SDavid van Moolenbroek 	 * not a good method to test every case handled in the actual
1230*00b67f09SDavid van Moolenbroek 	 * code itself. This is because our approach itself may be
1231*00b67f09SDavid van Moolenbroek 	 * incorrect.
1232*00b67f09SDavid van Moolenbroek 	 *
1233*00b67f09SDavid van Moolenbroek 	 * We test our code at the interface level here by exercising the
1234*00b67f09SDavid van Moolenbroek 	 * tree randomly multiple times, checking that red-black tree
1235*00b67f09SDavid van Moolenbroek 	 * properties are valid, and all the nodes that are supposed to be
1236*00b67f09SDavid van Moolenbroek 	 * in the tree exist and are in order.
1237*00b67f09SDavid van Moolenbroek 	 *
1238*00b67f09SDavid van Moolenbroek 	 * NOTE: These tests are run within a single tree level in the
1239*00b67f09SDavid van Moolenbroek 	 * forest. The number of nodes in the tree level doesn't grow
1240*00b67f09SDavid van Moolenbroek 	 * over 1024.
1241*00b67f09SDavid van Moolenbroek 	 */
1242*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1243*00b67f09SDavid van Moolenbroek 	dns_rbt_t *mytree = NULL;
1244*00b67f09SDavid van Moolenbroek 	/*
1245*00b67f09SDavid van Moolenbroek 	 * We use an array for storing names instead of a set
1246*00b67f09SDavid van Moolenbroek 	 * structure. It's slow, but works and is good enough for tests.
1247*00b67f09SDavid van Moolenbroek 	 */
1248*00b67f09SDavid van Moolenbroek 	char *names[1024];
1249*00b67f09SDavid van Moolenbroek 	size_t names_count;
1250*00b67f09SDavid van Moolenbroek 	int i;
1251*00b67f09SDavid van Moolenbroek 
1252*00b67f09SDavid van Moolenbroek 	UNUSED(tc);
1253*00b67f09SDavid van Moolenbroek 
1254*00b67f09SDavid van Moolenbroek 	isc_mem_debugging = ISC_MEM_DEBUGRECORD;
1255*00b67f09SDavid van Moolenbroek 
1256*00b67f09SDavid van Moolenbroek 	result = dns_test_begin(NULL, ISC_TRUE);
1257*00b67f09SDavid van Moolenbroek 	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
1258*00b67f09SDavid van Moolenbroek 
1259*00b67f09SDavid van Moolenbroek 	result = dns_rbt_create(mctx, delete_data, NULL, &mytree);
1260*00b67f09SDavid van Moolenbroek 	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
1261*00b67f09SDavid van Moolenbroek 
1262*00b67f09SDavid van Moolenbroek 	memset(names, 0, sizeof(names));
1263*00b67f09SDavid van Moolenbroek 	names_count = 0;
1264*00b67f09SDavid van Moolenbroek 
1265*00b67f09SDavid van Moolenbroek 	/* Repeat the insert/remove test some 4096 times */
1266*00b67f09SDavid van Moolenbroek 	for (i = 0; i < 4096; i++) {
1267*00b67f09SDavid van Moolenbroek 		isc_uint32_t num_names;
1268*00b67f09SDavid van Moolenbroek 		isc_random_get(&num_names);
1269*00b67f09SDavid van Moolenbroek 
1270*00b67f09SDavid van Moolenbroek 		if (names_count < 1024) {
1271*00b67f09SDavid van Moolenbroek 			num_names %= 1024 - names_count;
1272*00b67f09SDavid van Moolenbroek 			num_names++;
1273*00b67f09SDavid van Moolenbroek 		} else {
1274*00b67f09SDavid van Moolenbroek 			num_names = 0;
1275*00b67f09SDavid van Moolenbroek 		}
1276*00b67f09SDavid van Moolenbroek 
1277*00b67f09SDavid van Moolenbroek 		insert_nodes(mytree, names, &names_count, num_names);
1278*00b67f09SDavid van Moolenbroek 		check_tree(mytree, names, names_count);
1279*00b67f09SDavid van Moolenbroek 
1280*00b67f09SDavid van Moolenbroek 		isc_random_get(&num_names);
1281*00b67f09SDavid van Moolenbroek 		if (names_count > 0) {
1282*00b67f09SDavid van Moolenbroek 			num_names %= names_count;
1283*00b67f09SDavid van Moolenbroek 			num_names++;
1284*00b67f09SDavid van Moolenbroek 		} else {
1285*00b67f09SDavid van Moolenbroek 			num_names = 0;
1286*00b67f09SDavid van Moolenbroek 		}
1287*00b67f09SDavid van Moolenbroek 
1288*00b67f09SDavid van Moolenbroek 		remove_nodes(mytree, names, &names_count, num_names);
1289*00b67f09SDavid van Moolenbroek 		check_tree(mytree, names, names_count);
1290*00b67f09SDavid van Moolenbroek 	}
1291*00b67f09SDavid van Moolenbroek 
1292*00b67f09SDavid van Moolenbroek 	/* Remove the rest of the nodes */
1293*00b67f09SDavid van Moolenbroek 	remove_nodes(mytree, names, &names_count, names_count);
1294*00b67f09SDavid van Moolenbroek 	check_tree(mytree, names, names_count);
1295*00b67f09SDavid van Moolenbroek 
1296*00b67f09SDavid van Moolenbroek 	for (i = 0; i < 1024; i++) {
1297*00b67f09SDavid van Moolenbroek 		if (names[i] != NULL) {
1298*00b67f09SDavid van Moolenbroek 			isc_mem_free(mctx, names[i]);
1299*00b67f09SDavid van Moolenbroek 		}
1300*00b67f09SDavid van Moolenbroek 	}
1301*00b67f09SDavid van Moolenbroek 
1302*00b67f09SDavid van Moolenbroek 	dns_rbt_destroy(&mytree);
1303*00b67f09SDavid van Moolenbroek 
1304*00b67f09SDavid van Moolenbroek 	dns_test_end();
1305*00b67f09SDavid van Moolenbroek }
1306*00b67f09SDavid van Moolenbroek 
1307*00b67f09SDavid van Moolenbroek /*
1308*00b67f09SDavid van Moolenbroek  * Main
1309*00b67f09SDavid van Moolenbroek  */
ATF_TP_ADD_TCS(tp)1310*00b67f09SDavid van Moolenbroek ATF_TP_ADD_TCS(tp) {
1311*00b67f09SDavid van Moolenbroek 	ATF_TP_ADD_TC(tp, rbt_create);
1312*00b67f09SDavid van Moolenbroek 	ATF_TP_ADD_TC(tp, rbt_nodecount);
1313*00b67f09SDavid van Moolenbroek 	ATF_TP_ADD_TC(tp, rbtnode_get_distance);
1314*00b67f09SDavid van Moolenbroek 	ATF_TP_ADD_TC(tp, rbt_check_distance_random);
1315*00b67f09SDavid van Moolenbroek 	ATF_TP_ADD_TC(tp, rbt_check_distance_ordered);
1316*00b67f09SDavid van Moolenbroek 	ATF_TP_ADD_TC(tp, rbt_insert);
1317*00b67f09SDavid van Moolenbroek 	ATF_TP_ADD_TC(tp, rbt_remove);
1318*00b67f09SDavid van Moolenbroek 	ATF_TP_ADD_TC(tp, rbt_remove_empty);
1319*00b67f09SDavid van Moolenbroek 	ATF_TP_ADD_TC(tp, rbt_insert_and_remove);
1320*00b67f09SDavid van Moolenbroek 
1321*00b67f09SDavid van Moolenbroek 	return (atf_no_error());
1322*00b67f09SDavid van Moolenbroek }
1323