/* * Copyright (C) Internet Systems Consortium, Inc. ("ISC") * * SPDX-License-Identifier: MPL-2.0 * * 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 https://mozilla.org/MPL/2.0/. * * See the COPYRIGHT file distributed with this work for additional * information regarding copyright ownership. */ #include #include /* IWYU pragma: keep */ #include #include #include #include #include #include #include #define UNIT_TESTING #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int _setup(void **state) { isc_app_start(); setup_managers(state); return (0); } static int _teardown(void **state) { teardown_managers(state); isc_app_finish(); return (0); } struct args { void *arg1; void *arg2; bool arg3; }; 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 load_done(dns_zt_t *zt, dns_zone_t *zone, isc_task_t *task) { /* We treat zt as a pointer to a boolean for testing purposes */ atomic_bool *done = (atomic_bool *)zt; UNUSED(zone); UNUSED(task); atomic_store(done, true); isc_app_shutdown(); return (ISC_R_SUCCESS); } static isc_result_t all_done(void *arg) { atomic_bool *done = (atomic_bool *)arg; atomic_store(done, true); isc_app_shutdown(); return (ISC_R_SUCCESS); } static void start_zt_asyncload(isc_task_t *task, isc_event_t *event) { struct args *args = (struct args *)(event->ev_arg); UNUSED(task); dns_zt_asyncload(args->arg1, false, all_done, args->arg2); 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); dns_zone_asyncload(args->arg1, args->arg3, load_done, args->arg2); isc_event_free(&event); } /* apply a function to a zone table */ ISC_RUN_TEST_IMPL(dns_zt_apply) { isc_result_t result; dns_zone_t *zone = NULL; dns_view_t *view = NULL; int nzones = 0; UNUSED(state); result = dns_test_makezone("foo", &zone, NULL, true); assert_int_equal(result, ISC_R_SUCCESS); view = dns_zone_getview(zone); assert_non_null(view->zonetable); assert_int_equal(nzones, 0); result = dns_zt_apply(view->zonetable, isc_rwlocktype_read, false, NULL, count_zone, &nzones); assert_int_equal(result, ISC_R_SUCCESS); assert_int_equal(nzones, 1); /* These steps are necessary so the zone can be detached properly */ result = dns_test_setupzonemgr(); assert_int_equal(result, ISC_R_SUCCESS); result = dns_test_managezone(zone); assert_int_equal(result, ISC_R_SUCCESS); dns_test_releasezone(zone); dns_test_closezonemgr(); /* The view was left attached in dns_test_makezone() */ dns_view_detach(&view); dns_zone_detach(&zone); } /* asynchronous zone load */ ISC_RUN_TEST_IMPL(dns_zt_asyncload_zone) { isc_result_t result; int n; dns_zone_t *zone = NULL; dns_view_t *view = NULL; dns_db_t *db = NULL; FILE *zonefile, *origfile; char buf[4096]; atomic_bool done; int i = 0; struct args args; UNUSED(state); atomic_init(&done, false); result = dns_test_makezone("foo", &zone, NULL, true); assert_int_equal(result, ISC_R_SUCCESS); result = dns_test_setupzonemgr(); assert_int_equal(result, ISC_R_SUCCESS); result = dns_test_managezone(zone); assert_int_equal(result, ISC_R_SUCCESS); view = dns_zone_getview(zone); assert_non_null(view->zonetable); assert_false(dns__zone_loadpending(zone)); assert_false(atomic_load(&done)); zonefile = fopen("./zone.data", "wb"); assert_non_null(zonefile); origfile = fopen(TESTS_DIR "/testdata/zt/zone1.db", "r+b"); assert_non_null(origfile); n = fread(buf, 1, 4096, origfile); fclose(origfile); fwrite(buf, 1, n, zonefile); fflush(zonefile); dns_zone_setfile(zone, "./zone.data", dns_masterformat_text, &dns_master_style_default); args.arg1 = zone; args.arg2 = &done; args.arg3 = false; isc_app_onrun(mctx, maintask, start_zone_asyncload, &args); isc_app_run(); while (dns__zone_loadpending(zone) && i++ < 5000) { dns_test_nap(1000); } assert_true(atomic_load(&done)); /* The zone should now be loaded; test it */ result = dns_zone_getdb(zone, &db); assert_int_equal(result, ISC_R_SUCCESS); 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); fclose(zonefile); args.arg1 = zone; args.arg2 = &done; args.arg3 = true; isc_app_onrun(mctx, maintask, start_zone_asyncload, &args); isc_app_run(); while (dns__zone_loadpending(zone) && i++ < 5000) { dns_test_nap(1000); } assert_true(atomic_load(&done)); /* The zone should now be loaded; test it */ result = dns_zone_getdb(zone, &db); assert_int_equal(result, ISC_R_SUCCESS); dns_db_detach(&db); /* Now reload it without newonly - it should be reloaded */ args.arg1 = zone; args.arg2 = &done; args.arg3 = false; isc_app_onrun(mctx, maintask, start_zone_asyncload, &args); isc_app_run(); while (dns__zone_loadpending(zone) && i++ < 5000) { dns_test_nap(1000); } assert_true(atomic_load(&done)); /* The zone should now be loaded; test it */ result = dns_zone_getdb(zone, &db); assert_int_equal(result, ISC_R_SUCCESS); assert_non_null(db); if (db != NULL) { dns_db_detach(&db); } dns_test_releasezone(zone); dns_test_closezonemgr(); dns_zone_detach(&zone); dns_view_detach(&view); } /* asynchronous zone table load */ ISC_RUN_TEST_IMPL(dns_zt_asyncload_zt) { isc_result_t result; dns_zone_t *zone1 = NULL, *zone2 = NULL, *zone3 = NULL; dns_view_t *view; dns_zt_t *zt = NULL; dns_db_t *db = NULL; atomic_bool done; int i = 0; struct args args; UNUSED(state); atomic_init(&done, false); result = dns_test_makezone("foo", &zone1, NULL, true); assert_int_equal(result, ISC_R_SUCCESS); dns_zone_setfile(zone1, TESTS_DIR "/testdata/zt/zone1.db", dns_masterformat_text, &dns_master_style_default); view = dns_zone_getview(zone1); result = dns_test_makezone("bar", &zone2, view, false); assert_int_equal(result, ISC_R_SUCCESS); dns_zone_setfile(zone2, TESTS_DIR "/testdata/zt/zone1.db", dns_masterformat_text, &dns_master_style_default); /* This one will fail to load */ result = dns_test_makezone("fake", &zone3, view, false); assert_int_equal(result, ISC_R_SUCCESS); dns_zone_setfile(zone3, TESTS_DIR "/testdata/zt/nonexistent.db", dns_masterformat_text, &dns_master_style_default); zt = view->zonetable; assert_non_null(zt); result = dns_test_setupzonemgr(); assert_int_equal(result, ISC_R_SUCCESS); result = dns_test_managezone(zone1); assert_int_equal(result, ISC_R_SUCCESS); result = dns_test_managezone(zone2); assert_int_equal(result, ISC_R_SUCCESS); result = dns_test_managezone(zone3); assert_int_equal(result, ISC_R_SUCCESS); assert_false(dns__zone_loadpending(zone1)); assert_false(dns__zone_loadpending(zone2)); assert_false(atomic_load(&done)); args.arg1 = zt; args.arg2 = &done; isc_app_onrun(mctx, maintask, start_zt_asyncload, &args); isc_app_run(); while (!atomic_load(&done) && i++ < 5000) { dns_test_nap(1000); } assert_true(atomic_load(&done)); /* Both zones should now be loaded; test them */ result = dns_zone_getdb(zone1, &db); assert_int_equal(result, ISC_R_SUCCESS); assert_non_null(db); if (db != NULL) { dns_db_detach(&db); } result = dns_zone_getdb(zone2, &db); assert_int_equal(result, ISC_R_SUCCESS); assert_non_null(db); 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); } ISC_TEST_LIST_START ISC_TEST_ENTRY_CUSTOM(dns_zt_apply, _setup, _teardown) ISC_TEST_ENTRY_CUSTOM(dns_zt_asyncload_zone, _setup, _teardown) ISC_TEST_ENTRY_CUSTOM(dns_zt_asyncload_zt, _setup, _teardown) ISC_TEST_LIST_END ISC_TEST_MAIN