1/*	$NetBSD: dbiterator_test.c,v 1.1.1.1.4.1 2012/06/06 18:18:17 bouyer Exp $	*/
2
3/*
4 * Copyright (C) 2011, 2012  Internet Systems Consortium, Inc. ("ISC")
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
17 */
18
19/* Id */
20
21/*! \file */
22
23#include <config.h>
24
25#include <atf-c.h>
26
27#include <unistd.h>
28#include <stdlib.h>
29
30#include <dns/db.h>
31#include <dns/dbiterator.h>
32#include <dns/name.h>
33
34#include "dnstest.h"
35
36/*
37 * Helper functions
38 */
39
40#define	BUFLEN		255
41#define	BIGBUFLEN	(64 * 1024)
42#define TEST_ORIGIN	"test"
43
44static isc_result_t
45make_name(const char *src, dns_name_t *name) {
46	isc_buffer_t b;
47	isc_buffer_init(&b, src, strlen(src));
48	isc_buffer_add(&b, strlen(src));
49	return (dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
50}
51
52/*
53 * Individual unit tests
54 */
55
56/* create: make sure we can create a dbiterator */
57static void
58test_create(const atf_tc_t *tc) {
59	isc_result_t result;
60	dns_db_t *db = NULL;
61	dns_dbiterator_t *iter = NULL;
62
63	result = dns_test_begin(NULL, ISC_FALSE);
64	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
65
66	result = dns_test_loaddb(&db, dns_dbtype_cache, TEST_ORIGIN,
67				 atf_tc_get_md_var(tc, "X-filename"));
68	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
69
70	result = dns_db_createiterator(db, 0, &iter);
71	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
72
73	dns_dbiterator_destroy(&iter);
74	dns_db_detach(&db);
75	dns_test_end();
76}
77
78ATF_TC(create);
79ATF_TC_HEAD(create, tc) {
80	atf_tc_set_md_var(tc, "descr", "create a database iterator");
81	atf_tc_set_md_var(tc, "X-filename", "testdata/dbiterator/zone1.data");
82}
83ATF_TC_BODY(create, tc) {
84	test_create(tc);
85}
86
87ATF_TC(create_nsec3);
88ATF_TC_HEAD(create_nsec3, tc) {
89	atf_tc_set_md_var(tc, "descr", "create a database iterator (NSEC3)");
90	atf_tc_set_md_var(tc, "X-filename", "testdata/dbiterator/zone2.data");
91}
92ATF_TC_BODY(create_nsec3, tc) {
93	test_create(tc);
94}
95
96/* walk: walk a database */
97static void
98test_walk(const atf_tc_t *tc) {
99	isc_result_t result;
100	dns_db_t *db = NULL;
101	dns_dbiterator_t *iter = NULL;
102	dns_dbnode_t *node = NULL;
103	dns_name_t *name;
104	dns_fixedname_t f;
105	int i = 0;
106
107	UNUSED(tc);
108
109	dns_fixedname_init(&f);
110	name = dns_fixedname_name(&f);
111
112	result = dns_test_begin(NULL, ISC_FALSE);
113	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
114
115	result = dns_test_loaddb(&db, dns_dbtype_cache, TEST_ORIGIN,
116				 atf_tc_get_md_var(tc, "X-filename"));
117	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
118
119	result = dns_db_createiterator(db, 0, &iter);
120	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
121
122	for (result = dns_dbiterator_first(iter);
123	     result == ISC_R_SUCCESS;
124	     result = dns_dbiterator_next(iter)) {
125		result = dns_dbiterator_current(iter, &node, name);
126		if (result == DNS_R_NEWORIGIN)
127			result = ISC_R_SUCCESS;
128		ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
129		dns_db_detachnode(db, &node);
130		i++;
131	}
132
133	ATF_CHECK_EQ(i, atoi(atf_tc_get_md_var(tc, "X-nodes")));
134
135	dns_dbiterator_destroy(&iter);
136	dns_db_detach(&db);
137	dns_test_end();
138}
139
140ATF_TC(walk);
141ATF_TC_HEAD(walk, tc) {
142	atf_tc_set_md_var(tc, "descr", "walk database");
143	atf_tc_set_md_var(tc, "X-filename", "testdata/dbiterator/zone1.data");
144	atf_tc_set_md_var(tc, "X-nodes", "12");
145}
146ATF_TC_BODY(walk, tc) {
147	test_walk(tc);
148}
149
150ATF_TC(walk_nsec3);
151ATF_TC_HEAD(walk_nsec3, tc) {
152	atf_tc_set_md_var(tc, "descr", "walk database");
153	atf_tc_set_md_var(tc, "X-filename", "testdata/dbiterator/zone2.data");
154	atf_tc_set_md_var(tc, "X-nodes", "33");
155}
156ATF_TC_BODY(walk_nsec3, tc) {
157	test_walk(tc);
158}
159
160/* reverse: walk database backwards */
161static void test_reverse(const atf_tc_t *tc) {
162	isc_result_t result;
163	dns_db_t *db = NULL;
164	dns_dbiterator_t *iter = NULL;
165	dns_dbnode_t *node = NULL;
166	dns_name_t *name;
167	dns_fixedname_t f;
168	int i = 0;
169
170	UNUSED(tc);
171
172	dns_fixedname_init(&f);
173	name = dns_fixedname_name(&f);
174
175	result = dns_test_begin(NULL, ISC_FALSE);
176	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
177
178	result = dns_test_loaddb(&db, dns_dbtype_cache, TEST_ORIGIN,
179				 atf_tc_get_md_var(tc, "X-filename"));
180	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
181
182	result = dns_db_createiterator(db, 0, &iter);
183	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
184
185	for (result = dns_dbiterator_last(iter);
186	     result == ISC_R_SUCCESS;
187	     result = dns_dbiterator_prev(iter)) {
188		result = dns_dbiterator_current(iter, &node, name);
189		if (result == DNS_R_NEWORIGIN)
190			result = ISC_R_SUCCESS;
191		ATF_CHECK_EQ(result, ISC_R_SUCCESS);
192		dns_db_detachnode(db, &node);
193		i++;
194	}
195
196	ATF_CHECK_EQ(i, 12);
197
198	dns_dbiterator_destroy(&iter);
199	dns_db_detach(&db);
200	dns_test_end();
201}
202
203ATF_TC(reverse);
204ATF_TC_HEAD(reverse, tc) {
205	atf_tc_set_md_var(tc, "descr", "walk database backwards");
206	atf_tc_set_md_var(tc, "X-filename", "testdata/dbiterator/zone1.data");
207}
208ATF_TC_BODY(reverse, tc) {
209	test_reverse(tc);
210}
211
212ATF_TC(reverse_nsec3);
213ATF_TC_HEAD(reverse_nsec3, tc) {
214	atf_tc_set_md_var(tc, "descr", "walk database backwards");
215	atf_tc_set_md_var(tc, "X-filename", "testdata/dbiterator/zone2.data");
216}
217ATF_TC_BODY(reverse_nsec3, tc) {
218	test_reverse(tc);
219}
220
221/* seek: walk database starting at a particular node */
222static void test_seek(const atf_tc_t *tc) {
223	isc_result_t result;
224	dns_db_t *db = NULL;
225	dns_dbiterator_t *iter = NULL;
226	dns_dbnode_t *node = NULL;
227	dns_name_t *name, *seekname;
228	dns_fixedname_t f1, f2;
229	int i = 0;
230
231	UNUSED(tc);
232
233	dns_fixedname_init(&f1);
234	name = dns_fixedname_name(&f1);
235	dns_fixedname_init(&f2);
236	seekname = dns_fixedname_name(&f2);
237
238	result = dns_test_begin(NULL, ISC_FALSE);
239	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
240
241	result = dns_test_loaddb(&db, dns_dbtype_cache, TEST_ORIGIN,
242				 atf_tc_get_md_var(tc, "X-filename"));
243	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
244
245	result = dns_db_createiterator(db, 0, &iter);
246	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
247
248	result = make_name("c." TEST_ORIGIN, seekname);
249	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
250
251	result = dns_dbiterator_seek(iter, seekname);
252	ATF_CHECK_EQ(result, ISC_R_SUCCESS);
253
254	while (result == ISC_R_SUCCESS) {
255		result = dns_dbiterator_current(iter, &node, name);
256		if (result == DNS_R_NEWORIGIN)
257			result = ISC_R_SUCCESS;
258		ATF_CHECK_EQ(result, ISC_R_SUCCESS);
259		dns_db_detachnode(db, &node);
260		result = dns_dbiterator_next(iter);
261		i++;
262	}
263
264	ATF_CHECK_EQ(i, atoi(atf_tc_get_md_var(tc, "X-nodes")));
265
266	dns_dbiterator_destroy(&iter);
267	dns_db_detach(&db);
268	dns_test_end();
269}
270
271ATF_TC(seek);
272ATF_TC_HEAD(seek, tc) {
273	atf_tc_set_md_var(tc, "descr", "walk database starting at "
274				       "a particular node");
275	atf_tc_set_md_var(tc, "X-filename", "testdata/dbiterator/zone1.data");
276	atf_tc_set_md_var(tc, "X-nodes", "9");
277}
278ATF_TC_BODY(seek, tc) {
279	test_seek(tc);
280}
281
282ATF_TC(seek_nsec3);
283ATF_TC_HEAD(seek_nsec3, tc) {
284	atf_tc_set_md_var(tc, "descr", "walk database starting at "
285				       "a particular node");
286	atf_tc_set_md_var(tc, "X-filename", "testdata/dbiterator/zone2.data");
287	atf_tc_set_md_var(tc, "X-nodes", "30");
288}
289ATF_TC_BODY(seek_nsec3, tc) {
290	test_seek(tc);
291}
292
293/*
294 * seek_emty: walk database starting at an empty nonterminal node
295 * (should fail)
296 */
297static void test_seek_empty(const atf_tc_t *tc) {
298	isc_result_t result;
299	dns_db_t *db = NULL;
300	dns_dbiterator_t *iter = NULL;
301	dns_name_t *seekname;
302	dns_fixedname_t f1;
303
304	UNUSED(tc);
305
306	dns_fixedname_init(&f1);
307	seekname = dns_fixedname_name(&f1);
308
309	result = dns_test_begin(NULL, ISC_FALSE);
310	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
311
312	result = dns_test_loaddb(&db, dns_dbtype_cache, TEST_ORIGIN,
313				 atf_tc_get_md_var(tc, "X-filename"));
314	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
315
316	result = dns_db_createiterator(db, 0, &iter);
317	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
318
319	result = make_name("d." TEST_ORIGIN, seekname);
320	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
321
322	result = dns_dbiterator_seek(iter, seekname);
323	ATF_CHECK_EQ(result, ISC_R_NOTFOUND);
324
325	dns_dbiterator_destroy(&iter);
326	dns_db_detach(&db);
327	dns_test_end();
328}
329
330ATF_TC(seek_empty);
331ATF_TC_HEAD(seek_empty, tc) {
332	atf_tc_set_md_var(tc, "descr", "walk database starting at an "
333				       "empty nonterminal node");
334	atf_tc_set_md_var(tc, "X-filename", "testdata/dbiterator/zone1.data");
335}
336ATF_TC_BODY(seek_empty, tc) {
337	test_seek_empty(tc);
338}
339
340ATF_TC(seek_empty_nsec3);
341ATF_TC_HEAD(seek_empty_nsec3, tc) {
342	atf_tc_set_md_var(tc, "descr", "walk database starting at an "
343				       "empty nonterminal node");
344	atf_tc_set_md_var(tc, "X-filename", "testdata/dbiterator/zone2.data");
345}
346ATF_TC_BODY(seek_empty_nsec3, tc) {
347	test_seek_empty(tc);
348}
349
350/*
351 * seek_emty: walk database starting at an empty nonterminal node
352 * (should fail)
353 */
354static void test_seek_nx(const atf_tc_t *tc) {
355	isc_result_t result;
356	dns_db_t *db = NULL;
357	dns_dbiterator_t *iter = NULL;
358	dns_name_t *seekname;
359	dns_fixedname_t f1;
360
361	UNUSED(tc);
362
363	dns_fixedname_init(&f1);
364	seekname = dns_fixedname_name(&f1);
365
366	result = dns_test_begin(NULL, ISC_FALSE);
367	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
368
369	result = dns_test_loaddb(&db, dns_dbtype_cache, TEST_ORIGIN,
370				 atf_tc_get_md_var(tc, "X-filename"));
371	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
372
373	result = dns_db_createiterator(db, 0, &iter);
374	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
375
376	result = make_name("nonexistent." TEST_ORIGIN, seekname);
377	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
378
379	result = dns_dbiterator_seek(iter, seekname);
380	ATF_CHECK_EQ(result, ISC_R_NOTFOUND);
381
382	dns_dbiterator_destroy(&iter);
383	dns_db_detach(&db);
384	dns_test_end();
385}
386
387ATF_TC(seek_nx);
388ATF_TC_HEAD(seek_nx, tc) {
389	atf_tc_set_md_var(tc, "descr", "attempt to walk database starting "
390				       "at a nonexistent node");
391	atf_tc_set_md_var(tc, "X-filename", "testdata/dbiterator/zone1.data");
392}
393ATF_TC_BODY(seek_nx, tc) {
394	test_seek_nx(tc);
395}
396
397ATF_TC(seek_nx_nsec3);
398ATF_TC_HEAD(seek_nx_nsec3, tc) {
399	atf_tc_set_md_var(tc, "descr", "attempt to walk database starting "
400				       "at a nonexistent node");
401	atf_tc_set_md_var(tc, "X-filename", "testdata/dbiterator/zone2.data");
402}
403ATF_TC_BODY(seek_nx_nsec3, tc) {
404	test_seek_nx(tc);
405}
406
407/*
408 * Main
409 */
410ATF_TP_ADD_TCS(tp) {
411	ATF_TP_ADD_TC(tp, create);
412	ATF_TP_ADD_TC(tp, create_nsec3);
413	ATF_TP_ADD_TC(tp, walk);
414	ATF_TP_ADD_TC(tp, walk_nsec3);
415	ATF_TP_ADD_TC(tp, reverse);
416	ATF_TP_ADD_TC(tp, reverse_nsec3);
417	ATF_TP_ADD_TC(tp, seek);
418	ATF_TP_ADD_TC(tp, seek_nsec3);
419	ATF_TP_ADD_TC(tp, seek_empty);
420	ATF_TP_ADD_TC(tp, seek_empty_nsec3);
421	ATF_TP_ADD_TC(tp, seek_nx);
422	ATF_TP_ADD_TC(tp, seek_nx_nsec3);
423	return (atf_no_error());
424}
425
426/*
427 * XXX:
428 * dns_dbiterator API calls that are not yet part of this unit test:
429 *
430 * dns_dbiterator_pause
431 * dns_dbiterator_origin
432 * dns_dbiterator_setcleanmode
433 */
434