zt_test.c 8.41 KB
Newer Older
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4 5 6
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 8 9
 *
 * See the COPYRIGHT file distributed with this work for additional
 * information regarding copyright ownership.
10 11
 */

Evan Hunt's avatar
Evan Hunt committed
12 13 14 15 16
#if HAVE_CMOCKA

#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
17

18
#include <sched.h> /* IWYU pragma: keep */
19
#include <stdbool.h>
Evan Hunt's avatar
Evan Hunt committed
20 21
#include <stdlib.h>
#include <string.h>
22 23
#include <unistd.h>

Evan Hunt's avatar
Evan Hunt committed
24 25 26
#define UNIT_TESTING
#include <cmocka.h>

27
#include <isc/app.h>
28
#include <isc/atomic.h>
29
#include <isc/buffer.h>
Evan Hunt's avatar
Evan Hunt committed
30
#include <isc/print.h>
31 32
#include <isc/task.h>
#include <isc/timer.h>
Evan Hunt's avatar
Evan Hunt committed
33
#include <isc/util.h>
34 35 36 37 38 39 40 41 42

#include <dns/db.h>
#include <dns/name.h>
#include <dns/view.h>
#include <dns/zone.h>
#include <dns/zt.h>

#include "dnstest.h"

43 44 45
struct args {
	void *arg1;
	void *arg2;
46
	bool arg3;
47 48
};

Evan Hunt's avatar
Evan Hunt committed
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
static int
_setup(void **state) {
	isc_result_t result;

	UNUSED(state);

	result = dns_test_begin(NULL, true);
	assert_int_equal(result, ISC_R_SUCCESS);

	return (0);
}

static int
_teardown(void **state) {
	UNUSED(state);

	dns_test_end();

	return (0);
}

70 71 72 73 74 75 76 77 78 79 80
static isc_result_t
count_zone(dns_zone_t *zone, void *uap) {
	int *nzones = (int *)uap;

	UNUSED(zone);

	*nzones += 1;
	return (ISC_R_SUCCESS);
}

static isc_result_t
Evan Hunt's avatar
Evan Hunt committed
81
load_done(dns_zt_t *zt, dns_zone_t *zone, isc_task_t *task) {
82
	/* We treat zt as a pointer to a boolean for testing purposes */
83
	atomic_bool *done = (atomic_bool *) zt;
84 85

	UNUSED(zone);
Evan Hunt's avatar
Evan Hunt committed
86
	UNUSED(task);
87

88
	atomic_store(done, true);
89 90 91 92 93 94
	isc_app_shutdown();
	return (ISC_R_SUCCESS);
}

static isc_result_t
all_done(void *arg) {
95
	atomic_bool *done = (atomic_bool *) arg;
96

97
	atomic_store(done, true);
98 99 100 101
	isc_app_shutdown();
	return (ISC_R_SUCCESS);
}

102 103 104 105 106 107
static void
start_zt_asyncload(isc_task_t *task, isc_event_t *event) {
	struct args *args = (struct args *)(event->ev_arg);

	UNUSED(task);

108
	dns_zt_asyncload(args->arg1, false, all_done, args->arg2);
109 110 111 112 113 114 115 116 117 118

	isc_event_free(&event);
}

static void
start_zone_asyncload(isc_task_t *task, isc_event_t *event) {
	struct args *args = (struct args *)(event->ev_arg);

	UNUSED(task);

119
	dns_zone_asyncload(args->arg1, args->arg3, load_done, args->arg2);
120 121 122
	isc_event_free(&event);
}

Evan Hunt's avatar
Evan Hunt committed
123 124 125
/* apply a function to a zone table */
static void
apply(void **state) {
126 127 128 129 130
	isc_result_t result;
	dns_zone_t *zone = NULL;
	dns_view_t *view = NULL;
	int nzones = 0;

Evan Hunt's avatar
Evan Hunt committed
131
	UNUSED(state);
132

133
	result = dns_test_makezone("foo", &zone, NULL, true);
Evan Hunt's avatar
Evan Hunt committed
134
	assert_int_equal(result, ISC_R_SUCCESS);
Automatic Updater's avatar
Automatic Updater committed
135

136
	view = dns_zone_getview(zone);
Evan Hunt's avatar
Evan Hunt committed
137
	assert_non_null(view->zonetable);
138

Evan Hunt's avatar
Evan Hunt committed
139
	assert_int_equal(nzones, 0);
140 141
	result = dns_zt_apply(view->zonetable, false, NULL,
			      count_zone, &nzones);
Evan Hunt's avatar
Evan Hunt committed
142 143
	assert_int_equal(result, ISC_R_SUCCESS);
	assert_int_equal(nzones, 1);
144 145 146

	/* These steps are necessary so the zone can be detached properly */
	result = dns_test_setupzonemgr();
Evan Hunt's avatar
Evan Hunt committed
147
	assert_int_equal(result, ISC_R_SUCCESS);
148
	result = dns_test_managezone(zone);
Evan Hunt's avatar
Evan Hunt committed
149
	assert_int_equal(result, ISC_R_SUCCESS);
150 151 152 153 154 155 156 157
	dns_test_releasezone(zone);
	dns_test_closezonemgr();

	/* The view was left attached in dns_test_makezone() */
	dns_view_detach(&view);
	dns_zone_detach(&zone);
}

Evan Hunt's avatar
Evan Hunt committed
158 159 160
/* asynchronous zone load */
static void
asyncload_zone(void **state) {
161
	isc_result_t result;
162
	int n;
163 164 165
	dns_zone_t *zone = NULL;
	dns_view_t *view = NULL;
	dns_db_t *db = NULL;
166 167
	FILE* zonefile, *origfile;
	char buf[4096];
168
	atomic_bool done;
169
	int i = 0;
170
	struct args args;
171

Evan Hunt's avatar
Evan Hunt committed
172
	UNUSED(state);
173

174 175
	atomic_init(&done, false);

176
	result = dns_test_makezone("foo", &zone, NULL, true);
Evan Hunt's avatar
Evan Hunt committed
177
	assert_int_equal(result, ISC_R_SUCCESS);
178 179

	result = dns_test_setupzonemgr();
Evan Hunt's avatar
Evan Hunt committed
180
	assert_int_equal(result, ISC_R_SUCCESS);
181
	result = dns_test_managezone(zone);
Evan Hunt's avatar
Evan Hunt committed
182
	assert_int_equal(result, ISC_R_SUCCESS);
183 184

	view = dns_zone_getview(zone);
Evan Hunt's avatar
Evan Hunt committed
185
	assert_non_null(view->zonetable);
186

Evan Hunt's avatar
Evan Hunt committed
187
	assert_false(dns__zone_loadpending(zone));
188
	assert_false(atomic_load(&done));
189
	zonefile = fopen("./zone.data", "wb");
Evan Hunt's avatar
Evan Hunt committed
190
	assert_non_null(zonefile);
191
	origfile = fopen("./testdata/zt/zone1.db", "r+b");
Evan Hunt's avatar
Evan Hunt committed
192
	assert_non_null(origfile);
193
	n = fread(buf, 1, 4096, origfile);
Mark Andrews's avatar
Mark Andrews committed
194
	fclose(origfile);
195 196 197 198 199
	fwrite(buf, 1, n, zonefile);
	fflush(zonefile);

	dns_zone_setfile(zone, "./zone.data",
			 dns_masterformat_text, &dns_master_style_default);
200 201 202

	args.arg1 = zone;
	args.arg2 = &done;
203
	args.arg3 = false;
204
	isc_app_onrun(dt_mctx, maintask, start_zone_asyncload, &args);
205 206 207 208

	isc_app_run();
	while (dns__zone_loadpending(zone) && i++ < 5000)
		dns_test_nap(1000);
209
	assert_true(atomic_load(&done));
210 211
	/* The zone should now be loaded; test it */
	result = dns_zone_getdb(zone, &db);
Evan Hunt's avatar
Evan Hunt committed
212
	assert_int_equal(result, ISC_R_SUCCESS);
213 214 215 216 217 218 219
	dns_db_detach(&db);
	/*
	 * Add something to zone file, reload zone with newonly - it should
	 * not be reloaded.
	 */
	fprintf(zonefile, "\nb in b 1.2.3.4\n");
	fflush(zonefile);
Mark Andrews's avatar
Mark Andrews committed
220
	fclose(zonefile);
221 222 223 224

	args.arg1 = zone;
	args.arg2 = &done;
	args.arg3 = true;
225
	isc_app_onrun(dt_mctx, maintask, start_zone_asyncload, &args);
226 227

	isc_app_run();
228

229 230
	while (dns__zone_loadpending(zone) && i++ < 5000)
		dns_test_nap(1000);
231
	assert_true(atomic_load(&done));
232 233
	/* The zone should now be loaded; test it */
	result = dns_zone_getdb(zone, &db);
Evan Hunt's avatar
Evan Hunt committed
234
	assert_int_equal(result, ISC_R_SUCCESS);
235 236 237 238 239 240
	dns_db_detach(&db);

	/* Now reload it without newonly - it should be reloaded */
	args.arg1 = zone;
	args.arg2 = &done;
	args.arg3 = false;
241
	isc_app_onrun(dt_mctx, maintask, start_zone_asyncload, &args);
242 243 244 245 246

	isc_app_run();

	while (dns__zone_loadpending(zone) && i++ < 5000)
		dns_test_nap(1000);
247
	assert_true(atomic_load(&done));
248 249
	/* The zone should now be loaded; test it */
	result = dns_zone_getdb(zone, &db);
Evan Hunt's avatar
Evan Hunt committed
250
	assert_int_equal(result, ISC_R_SUCCESS);
251

Evan Hunt's avatar
Evan Hunt committed
252
	assert_non_null(db);
253 254 255 256 257 258 259 260 261 262
	if (db != NULL)
		dns_db_detach(&db);

	dns_test_releasezone(zone);
	dns_test_closezonemgr();

	dns_zone_detach(&zone);
	dns_view_detach(&view);
}

Evan Hunt's avatar
Evan Hunt committed
263 264 265
/* asynchronous zone table load */
static void
asyncload_zt(void **state) {
266 267 268
	isc_result_t result;
	dns_zone_t *zone1 = NULL, *zone2 = NULL, *zone3 = NULL;
	dns_view_t *view;
269
	dns_zt_t *zt = NULL;
270
	dns_db_t *db = NULL;
271
	atomic_bool done;
272
	int i = 0;
273
	struct args args;
274

Evan Hunt's avatar
Evan Hunt committed
275
	UNUSED(state);
276

277 278
	atomic_init(&done, false);

279
	result = dns_test_makezone("foo", &zone1, NULL, true);
Evan Hunt's avatar
Evan Hunt committed
280
	assert_int_equal(result, ISC_R_SUCCESS);
281 282
	dns_zone_setfile(zone1, "testdata/zt/zone1.db",
			 dns_masterformat_text, &dns_master_style_default);
283 284
	view = dns_zone_getview(zone1);

285
	result = dns_test_makezone("bar", &zone2, view, false);
Evan Hunt's avatar
Evan Hunt committed
286
	assert_int_equal(result, ISC_R_SUCCESS);
287 288
	dns_zone_setfile(zone2, "testdata/zt/zone1.db",
			 dns_masterformat_text, &dns_master_style_default);
289 290

	/* This one will fail to load */
291
	result = dns_test_makezone("fake", &zone3, view, false);
Evan Hunt's avatar
Evan Hunt committed
292
	assert_int_equal(result, ISC_R_SUCCESS);
293 294
	dns_zone_setfile(zone3, "testdata/zt/nonexistent.db",
			 dns_masterformat_text, &dns_master_style_default);
295 296

	zt = view->zonetable;
Evan Hunt's avatar
Evan Hunt committed
297
	assert_non_null(zt);
298 299

	result = dns_test_setupzonemgr();
Evan Hunt's avatar
Evan Hunt committed
300
	assert_int_equal(result, ISC_R_SUCCESS);
301
	result = dns_test_managezone(zone1);
Evan Hunt's avatar
Evan Hunt committed
302
	assert_int_equal(result, ISC_R_SUCCESS);
303
	result = dns_test_managezone(zone2);
Evan Hunt's avatar
Evan Hunt committed
304
	assert_int_equal(result, ISC_R_SUCCESS);
305
	result = dns_test_managezone(zone3);
Evan Hunt's avatar
Evan Hunt committed
306
	assert_int_equal(result, ISC_R_SUCCESS);
307

Evan Hunt's avatar
Evan Hunt committed
308 309
	assert_false(dns__zone_loadpending(zone1));
	assert_false(dns__zone_loadpending(zone2));
310
	assert_false(atomic_load(&done));
311 312 313

	args.arg1 = zt;
	args.arg2 = &done;
314
	isc_app_onrun(dt_mctx, maintask, start_zt_asyncload, &args);
315 316

	isc_app_run();
317
	while (!atomic_load(&done) && i++ < 5000) {
318
		dns_test_nap(1000);
319 320
	}
	assert_true(atomic_load(&done));
321 322 323

	/* Both zones should now be loaded; test them */
	result = dns_zone_getdb(zone1, &db);
Evan Hunt's avatar
Evan Hunt committed
324 325
	assert_int_equal(result, ISC_R_SUCCESS);
	assert_non_null(db);
326 327 328 329
	if (db != NULL)
		dns_db_detach(&db);

	result = dns_zone_getdb(zone2, &db);
Evan Hunt's avatar
Evan Hunt committed
330 331
	assert_int_equal(result, ISC_R_SUCCESS);
	assert_non_null(db);
332 333 334 335 336 337 338 339 340 341 342 343
	if (db != NULL)
		dns_db_detach(&db);

	dns_test_releasezone(zone3);
	dns_test_releasezone(zone2);
	dns_test_releasezone(zone1);
	dns_test_closezonemgr();

	dns_zone_detach(&zone1);
	dns_zone_detach(&zone2);
	dns_zone_detach(&zone3);
	dns_view_detach(&view);
Evan Hunt's avatar
Evan Hunt committed
344
}
345

Evan Hunt's avatar
Evan Hunt committed
346 347 348 349 350 351 352 353 354 355 356
int
main(void) {
	const struct CMUnitTest tests[] = {
		cmocka_unit_test_setup_teardown(apply, _setup, _teardown),
		cmocka_unit_test_setup_teardown(asyncload_zone,
						_setup, _teardown),
		cmocka_unit_test_setup_teardown(asyncload_zt,
						_setup, _teardown),
	};

	return (cmocka_run_group_tests(tests, NULL, NULL));
357 358
}

Evan Hunt's avatar
Evan Hunt committed
359 360 361 362 363 364 365 366
#else /* HAVE_CMOCKA */

#include <stdio.h>

int
main(void) {
	printf("1..0 # Skipped: cmocka not available\n");
	return (0);
367
}
Evan Hunt's avatar
Evan Hunt committed
368 369

#endif