mirror of
https://github.com/isc-projects/bind9.git
synced 2026-05-22 01:56:00 -04:00
add query unit test
A new query unit test covers the logic where zone hooks must be called first, then view ones, and finally the default hooks. It also ensures that if any hook returns NS_HOOK_RETURN the chain immediately stops.
This commit is contained in:
parent
b8e44d6259
commit
1114b1eac0
3 changed files with 273 additions and 0 deletions
|
|
@ -74,6 +74,12 @@ isc_result_t
|
|||
ns_test_serve_zone(const char *zonename, const char *filename,
|
||||
dns_view_t *view);
|
||||
|
||||
/*%
|
||||
* Set a hooktable on the served zone
|
||||
*/
|
||||
void
|
||||
ns_test_serve_zone_sethooktab(ns_hooktable_t *hooktab);
|
||||
|
||||
/*%
|
||||
* Release the zone loaded by ns_test_serve_zone().
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -139,6 +139,11 @@ teardown_server(void **state) {
|
|||
|
||||
static dns_zone_t *served_zone = NULL;
|
||||
|
||||
void
|
||||
ns_test_serve_zone_sethooktab(ns_hooktable_t *hooktab) {
|
||||
dns_zone_sethooktable(served_zone, hooktab, ns_hooktable_free);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
ns_test_serve_zone(const char *zonename, const char *filename,
|
||||
dns_view_t *view) {
|
||||
|
|
|
|||
|
|
@ -1480,11 +1480,273 @@ ISC_LOOP_TEST_IMPL(ns__query_hookasync_e2e) {
|
|||
isc_loopmgr_shutdown();
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests covering the correctness of hook call order, i.e. hooks from a zone are
|
||||
* called first, then hooks from a view, then the default hook table. And any
|
||||
* hook returning NS_HOOK_RETURN interrupt the whole chain
|
||||
*/
|
||||
typedef struct {
|
||||
ns_hook_action_t zonehookactions[2];
|
||||
ns_hook_action_t viewhookactions[2];
|
||||
ns_hook_action_t defaulthookactions[2];
|
||||
const char *expected;
|
||||
} ns__query_hook_test_params_t;
|
||||
|
||||
static void
|
||||
ns__query_test_concat(char *base, const char *tail) {
|
||||
char b[512];
|
||||
|
||||
strcpy(b, base);
|
||||
snprintf(base, sizeof(b), "%s%s", b, tail);
|
||||
}
|
||||
|
||||
static ns_hookresult_t
|
||||
ns__query_test_zonehook1(void *arg, void *data, isc_result_t *resultp) {
|
||||
UNUSED(arg);
|
||||
UNUSED(resultp);
|
||||
|
||||
ns__query_test_concat(data, "z1");
|
||||
return NS_HOOK_CONTINUE;
|
||||
}
|
||||
|
||||
static ns_hookresult_t
|
||||
ns__query_test_zonehook2(void *arg, void *data, isc_result_t *resultp) {
|
||||
UNUSED(arg);
|
||||
UNUSED(resultp);
|
||||
|
||||
ns__query_test_concat(data, "z2");
|
||||
return NS_HOOK_RETURN;
|
||||
}
|
||||
|
||||
static ns_hookresult_t
|
||||
ns__query_test_viewhook1(void *arg, void *data, isc_result_t *resultp) {
|
||||
UNUSED(arg);
|
||||
UNUSED(resultp);
|
||||
|
||||
ns__query_test_concat(data, "v1");
|
||||
return NS_HOOK_CONTINUE;
|
||||
}
|
||||
|
||||
static ns_hookresult_t
|
||||
ns__query_test_viewhook2(void *arg, void *data, isc_result_t *resultp) {
|
||||
UNUSED(arg);
|
||||
UNUSED(resultp);
|
||||
|
||||
ns__query_test_concat(data, "v2");
|
||||
return NS_HOOK_RETURN;
|
||||
}
|
||||
|
||||
static ns_hookresult_t
|
||||
ns__query_test_defaulthook1(void *arg, void *data, isc_result_t *resultp) {
|
||||
UNUSED(arg);
|
||||
UNUSED(resultp);
|
||||
|
||||
ns__query_test_concat(data, "d1");
|
||||
return NS_HOOK_CONTINUE;
|
||||
}
|
||||
|
||||
static ns_hookresult_t
|
||||
ns__query_test_defaulthook2(void *arg, void *data, isc_result_t *resultp) {
|
||||
UNUSED(arg);
|
||||
UNUSED(resultp);
|
||||
|
||||
ns__query_test_concat(data, "d2");
|
||||
return NS_HOOK_RETURN;
|
||||
}
|
||||
|
||||
static bool
|
||||
ns__query_test_setup_hooks(const ns_hook_t *h1, const ns_hook_t *h2,
|
||||
ns_hooktable_t **tp) {
|
||||
if (h1->action || h2->action) {
|
||||
INSIST(*tp == NULL);
|
||||
ns_hooktable_create(isc_g_mctx, tp);
|
||||
|
||||
if (h1->action) {
|
||||
ns_hook_add(*tp, isc_g_mctx, NS_QUERY_NXDOMAIN_BEGIN,
|
||||
h1);
|
||||
}
|
||||
|
||||
if (h2->action) {
|
||||
ns_hook_add(*tp, isc_g_mctx, NS_QUERY_NXDOMAIN_BEGIN,
|
||||
h2);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
ns__query_test_run_hookchain_test(const ns__query_hook_test_params_t *test) {
|
||||
isc_result_t result;
|
||||
query_ctx_t *qctx = NULL;
|
||||
char buffer[512] = { 0 };
|
||||
ns_hooktable_t *zone_hooktab = NULL;
|
||||
ns_hooktable_t *view_hooktab = NULL;
|
||||
|
||||
const ns_test_qctx_create_params_t qctx_params = {
|
||||
.qname = "idontexists.foo",
|
||||
.qtype = dns_rdatatype_a,
|
||||
.with_cache = true,
|
||||
};
|
||||
|
||||
const ns_hook_t zonehook1 = { .action = test->zonehookactions[0],
|
||||
.action_data = buffer };
|
||||
|
||||
const ns_hook_t zonehook2 = { .action = test->zonehookactions[1],
|
||||
.action_data = buffer };
|
||||
|
||||
const ns_hook_t viewhook1 = { .action = test->viewhookactions[0],
|
||||
.action_data = buffer };
|
||||
|
||||
const ns_hook_t viewhook2 = { .action = test->viewhookactions[1],
|
||||
.action_data = buffer };
|
||||
|
||||
const ns_hook_t defaulthook1 = { .action = test->defaulthookactions[0],
|
||||
.action_data = buffer };
|
||||
|
||||
const ns_hook_t defaulthook2 = { .action = test->defaulthookactions[1],
|
||||
.action_data = buffer };
|
||||
|
||||
/*
|
||||
* Create a fake query context
|
||||
*/
|
||||
result = ns_test_qctx_create(&qctx_params, &qctx);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
|
||||
/*
|
||||
* Load a zone
|
||||
*/
|
||||
result = ns_test_serve_zone("foo", TESTS_DIR "/testdata/query/foo.db",
|
||||
qctx->client->inner.view);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
|
||||
/*
|
||||
* Attach hooks to the zone
|
||||
*/
|
||||
if (ns__query_test_setup_hooks(&zonehook1, &zonehook2, &zone_hooktab)) {
|
||||
ns_test_serve_zone_sethooktab(zone_hooktab);
|
||||
}
|
||||
|
||||
/*
|
||||
* Attach hooks to the view
|
||||
*/
|
||||
if (ns__query_test_setup_hooks(&viewhook1, &viewhook2, &view_hooktab)) {
|
||||
qctx->client->inner.view->hooktable = view_hooktab;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup the default hook table
|
||||
*/
|
||||
(void)ns__query_test_setup_hooks(&defaulthook1, &defaulthook2,
|
||||
&ns__hook_table);
|
||||
|
||||
/*
|
||||
* Handling the response
|
||||
*/
|
||||
qctx->client->inner.sendcb = send_noop;
|
||||
isc_nmhandle_attach(qctx->client->inner.handle,
|
||||
&qctx->client->inner.reqhandle);
|
||||
|
||||
/*
|
||||
* Run the query
|
||||
*/
|
||||
ns__query_start(qctx);
|
||||
ns_query_done(qctx);
|
||||
|
||||
/*
|
||||
* Result checking
|
||||
*/
|
||||
assert_string_equal(buffer, test->expected);
|
||||
|
||||
/*
|
||||
* Cleanup
|
||||
*/
|
||||
ns_test_qctx_destroy(&qctx);
|
||||
ns_test_cleanup_zone();
|
||||
|
||||
if (ns__hook_table) {
|
||||
ns_hooktable_free(isc_g_mctx, (void **)&ns__hook_table);
|
||||
}
|
||||
|
||||
if (view_hooktab) {
|
||||
ns_hooktable_free(isc_g_mctx, (void **)&view_hooktab);
|
||||
}
|
||||
}
|
||||
|
||||
ISC_LOOP_TEST_IMPL(ns__query_hookchain) {
|
||||
const ns__query_hook_test_params_t tests[] = {
|
||||
{ { ns__query_test_zonehook1, ns__query_test_zonehook1 },
|
||||
{ ns__query_test_viewhook1, ns__query_test_viewhook1 },
|
||||
{ ns__query_test_defaulthook1, ns__query_test_defaulthook1 },
|
||||
"z1z1v1v1d1d1" },
|
||||
{ { ns__query_test_zonehook1, ns__query_test_zonehook1 },
|
||||
{ ns__query_test_viewhook1, ns__query_test_viewhook1 },
|
||||
{ ns__query_test_defaulthook2, ns__query_test_defaulthook1 },
|
||||
"z1z1v1v1d2" },
|
||||
{ { ns__query_test_zonehook2, ns__query_test_zonehook1 },
|
||||
{ ns__query_test_viewhook1, ns__query_test_viewhook1 },
|
||||
{ ns__query_test_defaulthook1, ns__query_test_defaulthook1 },
|
||||
"z2" },
|
||||
{ { ns__query_test_zonehook1, ns__query_test_zonehook2 },
|
||||
{ ns__query_test_viewhook1, ns__query_test_viewhook1 },
|
||||
{ ns__query_test_defaulthook1, ns__query_test_defaulthook1 },
|
||||
"z1z2" },
|
||||
{ { ns__query_test_zonehook1, ns__query_test_zonehook1 },
|
||||
{ ns__query_test_viewhook2, ns__query_test_viewhook1 },
|
||||
{ ns__query_test_defaulthook1, ns__query_test_defaulthook1 },
|
||||
"z1z1v2" },
|
||||
{ { ns__query_test_zonehook1, ns__query_test_zonehook1 },
|
||||
{ ns__query_test_viewhook1, ns__query_test_viewhook2 },
|
||||
{ ns__query_test_defaulthook1, ns__query_test_defaulthook1 },
|
||||
"z1z1v1v2" },
|
||||
{ { ns__query_test_zonehook1, NULL },
|
||||
{ ns__query_test_viewhook1, ns__query_test_viewhook2 },
|
||||
{ ns__query_test_defaulthook1, ns__query_test_defaulthook1 },
|
||||
"z1v1v2" },
|
||||
{ { NULL, NULL },
|
||||
{ ns__query_test_viewhook1, ns__query_test_viewhook2 },
|
||||
{ ns__query_test_defaulthook1, ns__query_test_defaulthook1 },
|
||||
"v1v2" },
|
||||
{ { NULL, NULL },
|
||||
{ ns__query_test_viewhook1, NULL },
|
||||
{ ns__query_test_defaulthook1, ns__query_test_defaulthook1 },
|
||||
"v1d1d1" },
|
||||
{ { NULL, NULL },
|
||||
{ ns__query_test_viewhook1, NULL },
|
||||
{ NULL, NULL },
|
||||
"v1" },
|
||||
{ { NULL, NULL },
|
||||
{ ns__query_test_viewhook2, NULL },
|
||||
{ NULL, NULL },
|
||||
"v2" },
|
||||
{ { ns__query_test_zonehook1, NULL },
|
||||
{ NULL, NULL },
|
||||
{ NULL, NULL },
|
||||
"z1" },
|
||||
{ { NULL, NULL },
|
||||
{ NULL, NULL },
|
||||
{ ns__query_test_defaulthook1, NULL },
|
||||
"d1" },
|
||||
{ { NULL, NULL }, { NULL, NULL }, { NULL, NULL }, "" },
|
||||
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(tests); i++) {
|
||||
ns__query_test_run_hookchain_test(&tests[i]);
|
||||
}
|
||||
|
||||
isc_loop_teardown(isc_loop_main(), shutdown_interfacemgr, NULL);
|
||||
isc_loopmgr_shutdown();
|
||||
}
|
||||
|
||||
ISC_TEST_LIST_START
|
||||
ISC_TEST_ENTRY_CUSTOM(ns__query_sfcache, setup_server, teardown_server)
|
||||
ISC_TEST_ENTRY_CUSTOM(ns__query_start, setup_server, teardown_server)
|
||||
ISC_TEST_ENTRY_CUSTOM(ns__query_hookasync, setup_server, teardown_server)
|
||||
ISC_TEST_ENTRY_CUSTOM(ns__query_hookasync_e2e, setup_server, teardown_server)
|
||||
ISC_TEST_ENTRY_CUSTOM(ns__query_hookchain, setup_server, teardown_server)
|
||||
ISC_TEST_LIST_END
|
||||
|
||||
ISC_TEST_MAIN
|
||||
|
|
|
|||
Loading…
Reference in a new issue