mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-22 01:59:26 +00:00
The unit tests are now using a common base, which means that lib/dns/tests/ code now has to include lib/isc/include/isc/test.h and link with lib/isc/test.c and lib/ns/tests has to include both libisc and libdns parts. Instead of cross-linking code between the directories, move the /lib/<foo>/test.c to /tests/<foo>.c and /lib/<foo>/include/<foo>test.h to /tests/include/tests/<foo>.h and create a single libtest.la convenience library in /tests/. At the same time, move the /lib/<foo>/tests/ to /tests/<foo>/ (but keep it symlinked to the old location) and adjust paths accordingly. In few places, we are now using absolute paths instead of relative paths, because the directory level has changed. By moving the directories under the /tests/ directory, the test-related code is kept in a single place and we can avoid referencing files between libns->libdns->libisc which is unhealthy because they live in a separate Makefile-space. In the future, the /bin/tests/ should be merged to /tests/ and symlink kept, and the /fuzz/ directory moved to /tests/fuzz/.
446 lines
12 KiB
C
446 lines
12 KiB
C
/*
|
|
* 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 <sched.h> /* IWYU pragma: keep */
|
|
#include <setjmp.h>
|
|
#include <stdarg.h>
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#define UNIT_TESTING
|
|
#include <cmocka.h>
|
|
|
|
#include <isc/buffer.h>
|
|
#include <isc/list.h>
|
|
#include <isc/region.h>
|
|
#include <isc/result.h>
|
|
#include <isc/stdtime.h>
|
|
#include <isc/types.h>
|
|
#include <isc/util.h>
|
|
|
|
#include <dns/db.h>
|
|
#include <dns/diff.h>
|
|
#include <dns/dnssec.h>
|
|
#include <dns/fixedname.h>
|
|
#include <dns/name.h>
|
|
#include <dns/rdata.h>
|
|
#include <dns/rdatastruct.h>
|
|
#include <dns/rdatatype.h>
|
|
#include <dns/types.h>
|
|
#include <dns/zone.h>
|
|
|
|
#include <dst/dst.h>
|
|
|
|
#include "zone_p.h"
|
|
|
|
#include <tests/dns.h>
|
|
|
|
/*%
|
|
* Structure characterizing a single diff tuple in the dns_diff_t structure
|
|
* prepared by dns__zone_updatesigs().
|
|
*/
|
|
typedef struct {
|
|
dns_diffop_t op;
|
|
const char *owner;
|
|
dns_ttl_t ttl;
|
|
const char *type;
|
|
} zonediff_t;
|
|
|
|
#define ZONEDIFF_SENTINEL \
|
|
{ \
|
|
0, NULL, 0, NULL \
|
|
}
|
|
|
|
/*%
|
|
* Structure defining a dns__zone_updatesigs() test.
|
|
*/
|
|
typedef struct {
|
|
const char *description; /* test description */
|
|
const zonechange_t *changes; /* array of "raw" zone changes */
|
|
const zonediff_t *zonediff; /* array of "processed" zone changes
|
|
* */
|
|
} updatesigs_test_params_t;
|
|
|
|
static int
|
|
setup_test(void **state) {
|
|
isc_result_t result;
|
|
|
|
UNUSED(state);
|
|
|
|
result = dst_lib_init(mctx, NULL);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
return (1);
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
teardown_test(void **state) {
|
|
UNUSED(state);
|
|
|
|
dst_lib_destroy();
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*%
|
|
* Check whether the 'found' tuple matches the 'expected' tuple. 'found' is
|
|
* the 'index'th tuple output by dns__zone_updatesigs() in test 'test'.
|
|
*/
|
|
static void
|
|
compare_tuples(const zonediff_t *expected, dns_difftuple_t *found,
|
|
size_t index) {
|
|
char found_covers[DNS_RDATATYPE_FORMATSIZE] = {};
|
|
char found_type[DNS_RDATATYPE_FORMATSIZE] = {};
|
|
char found_name[DNS_NAME_FORMATSIZE];
|
|
isc_consttextregion_t typeregion;
|
|
dns_fixedname_t expected_fname;
|
|
dns_rdatatype_t expected_type;
|
|
dns_name_t *expected_name;
|
|
dns_rdata_rrsig_t rrsig;
|
|
isc_buffer_t typebuf;
|
|
isc_result_t result;
|
|
|
|
REQUIRE(expected != NULL);
|
|
REQUIRE(found != NULL);
|
|
REQUIRE(index > 0);
|
|
|
|
/*
|
|
* Check operation.
|
|
*/
|
|
assert_int_equal(expected->op, found->op);
|
|
|
|
/*
|
|
* Check owner name.
|
|
*/
|
|
expected_name = dns_fixedname_initname(&expected_fname);
|
|
result = dns_name_fromstring(expected_name, expected->owner, 0, mctx);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
dns_name_format(&found->name, found_name, sizeof(found_name));
|
|
assert_true(dns_name_equal(expected_name, &found->name));
|
|
|
|
/*
|
|
* Check TTL.
|
|
*/
|
|
assert_int_equal(expected->ttl, found->ttl);
|
|
|
|
/*
|
|
* Parse expected RR type.
|
|
*/
|
|
typeregion.base = expected->type;
|
|
typeregion.length = strlen(expected->type);
|
|
result = dns_rdatatype_fromtext(&expected_type,
|
|
(isc_textregion_t *)&typeregion);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
|
|
/*
|
|
* Format found RR type for reporting purposes.
|
|
*/
|
|
isc_buffer_init(&typebuf, found_type, sizeof(found_type));
|
|
result = dns_rdatatype_totext(found->rdata.type, &typebuf);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
|
|
/*
|
|
* Check RR type.
|
|
*/
|
|
switch (expected->op) {
|
|
case DNS_DIFFOP_ADDRESIGN:
|
|
case DNS_DIFFOP_DELRESIGN:
|
|
/*
|
|
* Found tuple must be of type RRSIG.
|
|
*/
|
|
assert_int_equal(found->rdata.type, dns_rdatatype_rrsig);
|
|
if (found->rdata.type != dns_rdatatype_rrsig) {
|
|
break;
|
|
}
|
|
/*
|
|
* The signature must cover an RRset of type 'expected->type'.
|
|
*/
|
|
result = dns_rdata_tostruct(&found->rdata, &rrsig, NULL);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
isc_buffer_init(&typebuf, found_covers, sizeof(found_covers));
|
|
result = dns_rdatatype_totext(rrsig.covered, &typebuf);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
assert_int_equal(expected_type, rrsig.covered);
|
|
break;
|
|
default:
|
|
/*
|
|
* Found tuple must be of type 'expected->type'.
|
|
*/
|
|
assert_int_equal(expected_type, found->rdata.type);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*%
|
|
* Perform a single dns__zone_updatesigs() test defined in 'test'. All other
|
|
* arguments are expected to remain constant between subsequent invocations of
|
|
* this function.
|
|
*/
|
|
static void
|
|
updatesigs_test(const updatesigs_test_params_t *test, dns_zone_t *zone,
|
|
dns_db_t *db, dst_key_t *zone_keys[], unsigned int nkeys,
|
|
isc_stdtime_t now) {
|
|
size_t tuples_expected, tuples_found, index;
|
|
dns_dbversion_t *version = NULL;
|
|
dns_diff_t raw_diff, zone_diff;
|
|
const zonediff_t *expected;
|
|
dns_difftuple_t *found;
|
|
isc_result_t result;
|
|
|
|
dns__zonediff_t zonediff = {
|
|
.diff = &zone_diff,
|
|
.offline = false,
|
|
};
|
|
|
|
REQUIRE(test != NULL);
|
|
REQUIRE(test->description != NULL);
|
|
REQUIRE(test->changes != NULL);
|
|
REQUIRE(zone != NULL);
|
|
REQUIRE(db != NULL);
|
|
REQUIRE(zone_keys != NULL);
|
|
|
|
/*
|
|
* Create a new version of the zone's database.
|
|
*/
|
|
result = dns_db_newversion(db, &version);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
|
|
/*
|
|
* Create a diff representing the supplied changes.
|
|
*/
|
|
result = dns_test_difffromchanges(&raw_diff, test->changes, false);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
|
|
/*
|
|
* Apply the "raw" diff to the new version of the zone's database as
|
|
* this is what dns__zone_updatesigs() expects to happen before it is
|
|
* called.
|
|
*/
|
|
dns_diff_apply(&raw_diff, db, version);
|
|
|
|
/*
|
|
* Initialize the structure dns__zone_updatesigs() will modify.
|
|
*/
|
|
dns_diff_init(mctx, &zone_diff);
|
|
|
|
/*
|
|
* Check whether dns__zone_updatesigs() behaves as expected.
|
|
*/
|
|
result = dns__zone_updatesigs(&raw_diff, db, version, zone_keys, nkeys,
|
|
zone, now - 3600, now + 3600, 0, now,
|
|
true, false, &zonediff);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
assert_true(ISC_LIST_EMPTY(raw_diff.tuples));
|
|
assert_false(ISC_LIST_EMPTY(zone_diff.tuples));
|
|
|
|
/*
|
|
* Ensure that the number of tuples in the zone diff is as expected.
|
|
*/
|
|
|
|
tuples_expected = 0;
|
|
for (expected = test->zonediff; expected->owner != NULL; expected++) {
|
|
tuples_expected++;
|
|
}
|
|
|
|
tuples_found = 0;
|
|
for (found = ISC_LIST_HEAD(zone_diff.tuples); found != NULL;
|
|
found = ISC_LIST_NEXT(found, link))
|
|
{
|
|
tuples_found++;
|
|
}
|
|
|
|
assert_int_equal(tuples_expected, tuples_found);
|
|
|
|
/*
|
|
* Ensure that every tuple in the zone diff matches expectations.
|
|
*/
|
|
expected = test->zonediff;
|
|
index = 1;
|
|
for (found = ISC_LIST_HEAD(zone_diff.tuples); found != NULL;
|
|
found = ISC_LIST_NEXT(found, link))
|
|
{
|
|
compare_tuples(expected, found, index);
|
|
expected++;
|
|
index++;
|
|
}
|
|
|
|
/*
|
|
* Apply changes to zone database contents and clean up.
|
|
*/
|
|
dns_db_closeversion(db, &version, true);
|
|
dns_diff_clear(&zone_diff);
|
|
dns_diff_clear(&raw_diff);
|
|
}
|
|
|
|
/* dns__zone_updatesigs() tests */
|
|
ISC_RUN_TEST_IMPL(updatesigs_next) {
|
|
dst_key_t *zone_keys[DNS_MAXZONEKEYS];
|
|
dns_zone_t *zone = NULL;
|
|
dns_db_t *db = NULL;
|
|
isc_result_t result;
|
|
unsigned int nkeys;
|
|
isc_stdtime_t now;
|
|
size_t i;
|
|
|
|
UNUSED(state);
|
|
|
|
/*
|
|
* Prepare a zone along with its signing keys.
|
|
*/
|
|
|
|
result = dns_test_makezone("example", &zone, NULL, false);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
|
|
result = dns_test_loaddb(&db, dns_dbtype_zone, "example",
|
|
"testdata/master/master18.data");
|
|
assert_int_equal(result, DNS_R_SEENINCLUDE);
|
|
|
|
result = dns_zone_setkeydirectory(zone, "testkeys");
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
|
|
isc_stdtime_get(&now);
|
|
result = dns__zone_findkeys(zone, db, NULL, now, mctx, DNS_MAXZONEKEYS,
|
|
zone_keys, &nkeys);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
assert_int_equal(nkeys, 2);
|
|
|
|
/*
|
|
* Define the tests to be run. Note that changes to zone database
|
|
* contents introduced by each test are preserved between tests.
|
|
*/
|
|
|
|
const zonechange_t changes_add[] = {
|
|
{ DNS_DIFFOP_ADD, "foo.example", 300, "TXT", "foo" },
|
|
{ DNS_DIFFOP_ADD, "bar.example", 600, "TXT", "bar" },
|
|
ZONECHANGE_SENTINEL,
|
|
};
|
|
const zonediff_t zonediff_add[] = {
|
|
{ DNS_DIFFOP_ADDRESIGN, "foo.example", 300, "TXT" },
|
|
{ DNS_DIFFOP_ADD, "foo.example", 300, "TXT" },
|
|
{ DNS_DIFFOP_ADDRESIGN, "bar.example", 600, "TXT" },
|
|
{ DNS_DIFFOP_ADD, "bar.example", 600, "TXT" },
|
|
ZONEDIFF_SENTINEL,
|
|
};
|
|
const updatesigs_test_params_t test_add = {
|
|
.description = "add new RRsets",
|
|
.changes = changes_add,
|
|
.zonediff = zonediff_add,
|
|
};
|
|
|
|
const zonechange_t changes_append[] = {
|
|
{ DNS_DIFFOP_ADD, "foo.example", 300, "TXT", "foo1" },
|
|
{ DNS_DIFFOP_ADD, "foo.example", 300, "TXT", "foo2" },
|
|
ZONECHANGE_SENTINEL,
|
|
};
|
|
const zonediff_t zonediff_append[] = {
|
|
{ DNS_DIFFOP_DELRESIGN, "foo.example", 300, "TXT" },
|
|
{ DNS_DIFFOP_ADDRESIGN, "foo.example", 300, "TXT" },
|
|
{ DNS_DIFFOP_ADD, "foo.example", 300, "TXT" },
|
|
{ DNS_DIFFOP_ADD, "foo.example", 300, "TXT" },
|
|
ZONEDIFF_SENTINEL,
|
|
};
|
|
const updatesigs_test_params_t test_append = {
|
|
.description = "append multiple RRs to an existing RRset",
|
|
.changes = changes_append,
|
|
.zonediff = zonediff_append,
|
|
};
|
|
|
|
const zonechange_t changes_replace[] = {
|
|
{ DNS_DIFFOP_DEL, "bar.example", 600, "TXT", "bar" },
|
|
{ DNS_DIFFOP_ADD, "bar.example", 600, "TXT", "rab" },
|
|
ZONECHANGE_SENTINEL,
|
|
};
|
|
const zonediff_t zonediff_replace[] = {
|
|
{ DNS_DIFFOP_DELRESIGN, "bar.example", 600, "TXT" },
|
|
{ DNS_DIFFOP_ADDRESIGN, "bar.example", 600, "TXT" },
|
|
{ DNS_DIFFOP_DEL, "bar.example", 600, "TXT" },
|
|
{ DNS_DIFFOP_ADD, "bar.example", 600, "TXT" },
|
|
ZONEDIFF_SENTINEL,
|
|
};
|
|
const updatesigs_test_params_t test_replace = {
|
|
.description = "replace an existing RRset",
|
|
.changes = changes_replace,
|
|
.zonediff = zonediff_replace,
|
|
};
|
|
|
|
const zonechange_t changes_delete[] = {
|
|
{ DNS_DIFFOP_DEL, "bar.example", 600, "TXT", "rab" },
|
|
ZONECHANGE_SENTINEL,
|
|
};
|
|
const zonediff_t zonediff_delete[] = {
|
|
{ DNS_DIFFOP_DELRESIGN, "bar.example", 600, "TXT" },
|
|
{ DNS_DIFFOP_DEL, "bar.example", 600, "TXT" },
|
|
ZONEDIFF_SENTINEL,
|
|
};
|
|
const updatesigs_test_params_t test_delete = {
|
|
.description = "delete an existing RRset",
|
|
.changes = changes_delete,
|
|
.zonediff = zonediff_delete,
|
|
};
|
|
|
|
const zonechange_t changes_mixed[] = {
|
|
{ DNS_DIFFOP_ADD, "baz.example", 900, "TXT", "baz1" },
|
|
{ DNS_DIFFOP_ADD, "baz.example", 900, "A", "127.0.0.1" },
|
|
{ DNS_DIFFOP_ADD, "baz.example", 900, "TXT", "baz2" },
|
|
{ DNS_DIFFOP_ADD, "baz.example", 900, "AAAA", "::1" },
|
|
ZONECHANGE_SENTINEL,
|
|
};
|
|
const zonediff_t zonediff_mixed[] = {
|
|
{ DNS_DIFFOP_ADDRESIGN, "baz.example", 900, "TXT" },
|
|
{ DNS_DIFFOP_ADD, "baz.example", 900, "TXT" },
|
|
{ DNS_DIFFOP_ADD, "baz.example", 900, "TXT" },
|
|
{ DNS_DIFFOP_ADDRESIGN, "baz.example", 900, "A" },
|
|
{ DNS_DIFFOP_ADD, "baz.example", 900, "A" },
|
|
{ DNS_DIFFOP_ADDRESIGN, "baz.example", 900, "AAAA" },
|
|
{ DNS_DIFFOP_ADD, "baz.example", 900, "AAAA" },
|
|
ZONEDIFF_SENTINEL,
|
|
};
|
|
const updatesigs_test_params_t test_mixed = {
|
|
.description = "add different RRsets with common owner name",
|
|
.changes = changes_mixed,
|
|
.zonediff = zonediff_mixed,
|
|
};
|
|
|
|
const updatesigs_test_params_t *tests[] = {
|
|
&test_add, &test_append, &test_replace,
|
|
&test_delete, &test_mixed,
|
|
};
|
|
|
|
/*
|
|
* Run tests.
|
|
*/
|
|
for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
|
|
updatesigs_test(tests[i], zone, db, zone_keys, nkeys, now);
|
|
}
|
|
|
|
/*
|
|
* Clean up.
|
|
*/
|
|
for (i = 0; i < nkeys; i++) {
|
|
dst_key_free(&zone_keys[i]);
|
|
}
|
|
dns_db_detach(&db);
|
|
dns_zone_detach(&zone);
|
|
}
|
|
|
|
ISC_TEST_LIST_START
|
|
ISC_TEST_ENTRY_CUSTOM(updatesigs_next, setup_test, teardown_test)
|
|
ISC_TEST_LIST_END
|
|
|
|
ISC_TEST_MAIN
|