xref: /netbsd-src/external/mpl/bind/dist/tests/dns/zt_test.c (revision bcda20f65a8566e103791ec395f7f499ef322704)
1 /*	$NetBSD: zt_test.c,v 1.3 2025/01/26 16:25:48 christos Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * SPDX-License-Identifier: MPL-2.0
7  *
8  * This Source Code Form is subject to the terms of the Mozilla Public
9  * License, v. 2.0. If a copy of the MPL was not distributed with this
10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11  *
12  * See the COPYRIGHT file distributed with this work for additional
13  * information regarding copyright ownership.
14  */
15 
16 #include <inttypes.h>
17 #include <sched.h> /* IWYU pragma: keep */
18 #include <setjmp.h>
19 #include <stdarg.h>
20 #include <stdbool.h>
21 #include <stddef.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 
26 #define UNIT_TESTING
27 #include <cmocka.h>
28 
29 #include <isc/atomic.h>
30 #include <isc/buffer.h>
31 #include <isc/loop.h>
32 #include <isc/timer.h>
33 #include <isc/urcu.h>
34 #include <isc/util.h>
35 
36 #include <dns/db.h>
37 #include <dns/name.h>
38 #include <dns/view.h>
39 #include <dns/zone.h>
40 #include <dns/zt.h>
41 
42 #include <tests/dns.h>
43 
44 static dns_db_t *db = NULL;
45 static FILE *zonefile, *origfile;
46 static dns_view_t *view = NULL;
47 
48 static isc_result_t
49 count_zone(dns_zone_t *zone, void *uap) {
50 	int *nzones = (int *)uap;
51 
52 	UNUSED(zone);
53 
54 	*nzones += 1;
55 	return ISC_R_SUCCESS;
56 }
57 
58 /* apply a function to a zone table */
59 ISC_LOOP_TEST_IMPL(apply) {
60 	isc_result_t result;
61 	dns_zone_t *zone = NULL;
62 	dns_zt_t *zt = NULL;
63 	int nzones = 0;
64 
65 	result = dns_test_makezone("foo", &zone, NULL, true);
66 	assert_int_equal(result, ISC_R_SUCCESS);
67 
68 	view = dns_zone_getview(zone);
69 	rcu_read_lock();
70 	zt = rcu_dereference(view->zonetable);
71 	rcu_read_unlock();
72 
73 	assert_non_null(zt);
74 
75 	assert_int_equal(nzones, 0);
76 	result = dns_view_apply(view, false, NULL, count_zone, &nzones);
77 	assert_int_equal(result, ISC_R_SUCCESS);
78 	assert_int_equal(nzones, 1);
79 
80 	/* These steps are necessary so the zone can be detached properly */
81 	dns_test_setupzonemgr();
82 	result = dns_test_managezone(zone);
83 	assert_int_equal(result, ISC_R_SUCCESS);
84 	dns_test_releasezone(zone);
85 	dns_test_closezonemgr();
86 
87 	/* The view was left attached in dns_test_makezone() */
88 	dns_view_detach(&view);
89 	dns_zone_detach(&zone);
90 	isc_loopmgr_shutdown(loopmgr);
91 }
92 
93 static isc_result_t
94 load_done_last(void *uap) {
95 	dns_zone_t *zone = uap;
96 	isc_result_t result;
97 
98 	/* The zone should now be loaded; test it */
99 	result = dns_zone_getdb(zone, &db);
100 	assert_int_equal(result, ISC_R_SUCCESS);
101 
102 	assert_non_null(db);
103 	if (db != NULL) {
104 		dns_db_detach(&db);
105 	}
106 
107 	dns_test_releasezone(zone);
108 	dns_test_closezonemgr();
109 
110 	dns_zone_detach(&zone);
111 	dns_view_detach(&view);
112 
113 	isc_loopmgr_shutdown(loopmgr);
114 
115 	return ISC_R_SUCCESS;
116 }
117 
118 static isc_result_t
119 load_done_new_only(void *uap) {
120 	dns_zone_t *zone = uap;
121 	isc_result_t result;
122 
123 	/* The zone should now be loaded; test it */
124 	result = dns_zone_getdb(zone, &db);
125 	assert_int_equal(result, ISC_R_SUCCESS);
126 	dns_db_detach(&db);
127 
128 	dns_zone_asyncload(zone, true, load_done_last, zone);
129 
130 	return ISC_R_SUCCESS;
131 }
132 
133 static isc_result_t
134 load_done_first(void *uap) {
135 	dns_zone_t *zone = uap;
136 	isc_result_t result;
137 
138 	/* The zone should now be loaded; test it */
139 	result = dns_zone_getdb(zone, &db);
140 	assert_int_equal(result, ISC_R_SUCCESS);
141 	dns_db_detach(&db);
142 
143 	/*
144 	 * Add something to zone file, reload zone with newonly - it should
145 	 * not be reloaded.
146 	 */
147 	fprintf(zonefile, "\nb in b 1.2.3.4\n");
148 	fflush(zonefile);
149 	fclose(zonefile);
150 
151 	dns_zone_asyncload(zone, true, load_done_new_only, zone);
152 
153 	return ISC_R_SUCCESS;
154 }
155 
156 /* asynchronous zone load */
157 ISC_LOOP_TEST_IMPL(asyncload_zone) {
158 	isc_result_t result;
159 	int n;
160 	dns_zone_t *zone = NULL;
161 	dns_zt_t *zt = NULL;
162 	char buf[4096];
163 
164 	result = dns_test_makezone("foo", &zone, NULL, true);
165 	assert_int_equal(result, ISC_R_SUCCESS);
166 
167 	dns_test_setupzonemgr();
168 	result = dns_test_managezone(zone);
169 	assert_int_equal(result, ISC_R_SUCCESS);
170 
171 	view = dns_zone_getview(zone);
172 	rcu_read_lock();
173 	zt = rcu_dereference(view->zonetable);
174 	rcu_read_unlock();
175 	assert_non_null(zt);
176 
177 	assert_false(dns__zone_loadpending(zone));
178 	zonefile = fopen("./zone.data", "wb");
179 	assert_non_null(zonefile);
180 	origfile = fopen(TESTS_DIR "/testdata/zt/zone1.db", "r+b");
181 	assert_non_null(origfile);
182 	n = fread(buf, 1, 4096, origfile);
183 	fclose(origfile);
184 	fwrite(buf, 1, n, zonefile);
185 	fflush(zonefile);
186 
187 	dns_zone_setfile(zone, "./zone.data", dns_masterformat_text,
188 			 &dns_master_style_default);
189 
190 	dns_zone_asyncload(zone, false, load_done_first, zone);
191 }
192 
193 dns_zone_t *zone1 = NULL, *zone2 = NULL, *zone3 = NULL;
194 
195 static isc_result_t
196 all_done(void *arg ISC_ATTR_UNUSED) {
197 	isc_result_t result;
198 
199 	/* Both zones should now be loaded; test them */
200 	result = dns_zone_getdb(zone1, &db);
201 	assert_int_equal(result, ISC_R_SUCCESS);
202 	assert_non_null(db);
203 	if (db != NULL) {
204 		dns_db_detach(&db);
205 	}
206 
207 	result = dns_zone_getdb(zone2, &db);
208 	assert_int_equal(result, ISC_R_SUCCESS);
209 	assert_non_null(db);
210 	if (db != NULL) {
211 		dns_db_detach(&db);
212 	}
213 
214 	dns_test_releasezone(zone3);
215 	dns_test_releasezone(zone2);
216 	dns_test_releasezone(zone1);
217 	dns_test_closezonemgr();
218 
219 	dns_zone_detach(&zone1);
220 	dns_zone_detach(&zone2);
221 	dns_zone_detach(&zone3);
222 	dns_view_detach(&view);
223 
224 	isc_loopmgr_shutdown(loopmgr);
225 	return ISC_R_SUCCESS;
226 }
227 
228 /* asynchronous zone table load */
229 ISC_LOOP_TEST_IMPL(asyncload_zt) {
230 	isc_result_t result;
231 	dns_zt_t *zt = NULL;
232 	atomic_bool done;
233 
234 	atomic_init(&done, false);
235 
236 	result = dns_test_makezone("foo", &zone1, NULL, true);
237 	assert_int_equal(result, ISC_R_SUCCESS);
238 	dns_zone_setfile(zone1, TESTS_DIR "/testdata/zt/zone1.db",
239 			 dns_masterformat_text, &dns_master_style_default);
240 	view = dns_zone_getview(zone1);
241 
242 	result = dns_test_makezone("bar", &zone2, view, false);
243 	assert_int_equal(result, ISC_R_SUCCESS);
244 	dns_zone_setfile(zone2, TESTS_DIR "/testdata/zt/zone1.db",
245 			 dns_masterformat_text, &dns_master_style_default);
246 
247 	/* This one will fail to load */
248 	result = dns_test_makezone("fake", &zone3, view, false);
249 	assert_int_equal(result, ISC_R_SUCCESS);
250 	dns_zone_setfile(zone3, TESTS_DIR "/testdata/zt/nonexistent.db",
251 			 dns_masterformat_text, &dns_master_style_default);
252 
253 	rcu_read_lock();
254 	zt = rcu_dereference(view->zonetable);
255 	rcu_read_unlock();
256 	assert_non_null(zt);
257 
258 	dns_test_setupzonemgr();
259 	result = dns_test_managezone(zone1);
260 	assert_int_equal(result, ISC_R_SUCCESS);
261 	result = dns_test_managezone(zone2);
262 	assert_int_equal(result, ISC_R_SUCCESS);
263 	result = dns_test_managezone(zone3);
264 	assert_int_equal(result, ISC_R_SUCCESS);
265 
266 	assert_false(dns__zone_loadpending(zone1));
267 	assert_false(dns__zone_loadpending(zone2));
268 	assert_false(atomic_load(&done));
269 
270 	rcu_read_lock();
271 	zt = rcu_dereference(view->zonetable);
272 	dns_zt_asyncload(zt, false, all_done, NULL);
273 	rcu_read_unlock();
274 }
275 
276 ISC_TEST_LIST_START
277 ISC_TEST_ENTRY_CUSTOM(apply, setup_managers, teardown_managers)
278 ISC_TEST_ENTRY_CUSTOM(asyncload_zone, setup_managers, teardown_managers)
279 ISC_TEST_ENTRY_CUSTOM(asyncload_zt, setup_managers, teardown_managers)
280 ISC_TEST_LIST_END
281 
282 ISC_TEST_MAIN
283