mirror of
https://github.com/isc-projects/bind9.git
synced 2026-03-03 14:00:47 -05:00
Make sure pointer checks in unit tests use cmocka assertion macros
dedicated for use with pointers instead of those dedicated for use with
integers or booleans.
(cherry picked from commit f440600126)
375 lines
8.2 KiB
C
375 lines
8.2 KiB
C
/*
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
|
*
|
|
* 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 <config.h>
|
|
|
|
#if HAVE_CMOCKA
|
|
|
|
#include <stdarg.h>
|
|
#include <stddef.h>
|
|
#include <setjmp.h>
|
|
|
|
#include <inttypes.h>
|
|
#include <sched.h> /* IWYU pragma: keep */
|
|
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#define UNIT_TESTING
|
|
#include <cmocka.h>
|
|
|
|
#include <isc/app.h>
|
|
#include <isc/buffer.h>
|
|
#include <isc/print.h>
|
|
#include <isc/socket.h>
|
|
#include <isc/task.h>
|
|
#include <isc/timer.h>
|
|
#include <isc/util.h>
|
|
|
|
#include <dns/dispatch.h>
|
|
#include <dns/name.h>
|
|
#include <dns/view.h>
|
|
|
|
#include "dnstest.h"
|
|
|
|
dns_dispatchmgr_t *dispatchmgr = NULL;
|
|
dns_dispatchset_t *dset = NULL;
|
|
|
|
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);
|
|
}
|
|
|
|
static isc_result_t
|
|
make_dispatchset(unsigned int ndisps) {
|
|
isc_result_t result;
|
|
isc_sockaddr_t any;
|
|
unsigned int attrs;
|
|
dns_dispatch_t *disp = NULL;
|
|
|
|
result = dns_dispatchmgr_create(mctx, NULL, &dispatchmgr);
|
|
if (result != ISC_R_SUCCESS)
|
|
return (result);
|
|
|
|
isc_sockaddr_any(&any);
|
|
attrs = DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_UDP;
|
|
result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr,
|
|
&any, 512, 6, 1024, 17, 19, attrs,
|
|
attrs, &disp);
|
|
if (result != ISC_R_SUCCESS)
|
|
return (result);
|
|
|
|
result = dns_dispatchset_create(mctx, socketmgr, taskmgr, disp,
|
|
&dset, ndisps);
|
|
dns_dispatch_detach(&disp);
|
|
|
|
return (result);
|
|
}
|
|
|
|
static void
|
|
reset(void) {
|
|
if (dset != NULL) {
|
|
dns_dispatchset_destroy(&dset);
|
|
}
|
|
if (dispatchmgr != NULL) {
|
|
dns_dispatchmgr_destroy(&dispatchmgr);
|
|
}
|
|
}
|
|
|
|
/* create dispatch set */
|
|
static void
|
|
dispatchset_create(void **state) {
|
|
isc_result_t result;
|
|
|
|
UNUSED(state);
|
|
|
|
result = make_dispatchset(1);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
reset();
|
|
|
|
result = make_dispatchset(10);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
reset();
|
|
}
|
|
|
|
/* test dispatch set round-robin */
|
|
static void
|
|
dispatchset_get(void **state) {
|
|
isc_result_t result;
|
|
dns_dispatch_t *d1, *d2, *d3, *d4, *d5;
|
|
|
|
UNUSED(state);
|
|
|
|
result = make_dispatchset(1);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
|
|
d1 = dns_dispatchset_get(dset);
|
|
d2 = dns_dispatchset_get(dset);
|
|
d3 = dns_dispatchset_get(dset);
|
|
d4 = dns_dispatchset_get(dset);
|
|
d5 = dns_dispatchset_get(dset);
|
|
|
|
assert_ptr_equal(d1, d2);
|
|
assert_ptr_equal(d2, d3);
|
|
assert_ptr_equal(d3, d4);
|
|
assert_ptr_equal(d4, d5);
|
|
|
|
reset();
|
|
|
|
result = make_dispatchset(4);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
|
|
d1 = dns_dispatchset_get(dset);
|
|
d2 = dns_dispatchset_get(dset);
|
|
d3 = dns_dispatchset_get(dset);
|
|
d4 = dns_dispatchset_get(dset);
|
|
d5 = dns_dispatchset_get(dset);
|
|
|
|
assert_ptr_equal(d1, d5);
|
|
assert_ptr_not_equal(d1, d2);
|
|
assert_ptr_not_equal(d2, d3);
|
|
assert_ptr_not_equal(d3, d4);
|
|
assert_ptr_not_equal(d4, d5);
|
|
|
|
reset();
|
|
}
|
|
|
|
static void
|
|
senddone(isc_task_t *task, isc_event_t *event) {
|
|
isc_socket_t *sock = event->ev_arg;
|
|
|
|
UNUSED(task);
|
|
|
|
isc_socket_detach(&sock);
|
|
isc_event_free(&event);
|
|
}
|
|
|
|
static void
|
|
nameserver(isc_task_t *task, isc_event_t *event) {
|
|
isc_result_t result;
|
|
isc_region_t region;
|
|
isc_socket_t *dummy;
|
|
isc_socket_t *sock = event->ev_arg;
|
|
isc_socketevent_t *ev = (isc_socketevent_t *)event;
|
|
static unsigned char buf1[16];
|
|
static unsigned char buf2[16];
|
|
|
|
memmove(buf1, ev->region.base, 12);
|
|
memset(buf1 + 12, 0, 4);
|
|
buf1[2] |= 0x80; /* qr=1 */
|
|
|
|
memmove(buf2, ev->region.base, 12);
|
|
memset(buf2 + 12, 1, 4);
|
|
buf2[2] |= 0x80; /* qr=1 */
|
|
|
|
/*
|
|
* send message to be discarded.
|
|
*/
|
|
region.base = buf1;
|
|
region.length = sizeof(buf1);
|
|
dummy = NULL;
|
|
isc_socket_attach(sock, &dummy);
|
|
result = isc_socket_sendto(sock, ®ion, task, senddone, sock,
|
|
&ev->address, NULL);
|
|
if (result != ISC_R_SUCCESS)
|
|
isc_socket_detach(&dummy);
|
|
|
|
/*
|
|
* send nextitem message.
|
|
*/
|
|
region.base = buf2;
|
|
region.length = sizeof(buf2);
|
|
dummy = NULL;
|
|
isc_socket_attach(sock, &dummy);
|
|
result = isc_socket_sendto(sock, ®ion, task, senddone, sock,
|
|
&ev->address, NULL);
|
|
if (result != ISC_R_SUCCESS)
|
|
isc_socket_detach(&dummy);
|
|
isc_event_free(&event);
|
|
}
|
|
|
|
static dns_dispatch_t *dispatch = NULL;
|
|
static dns_dispentry_t *dispentry = NULL;
|
|
static bool first = true;
|
|
static isc_mutex_t lock;
|
|
static isc_sockaddr_t local;
|
|
static unsigned int responses = 0;
|
|
|
|
static void
|
|
response(isc_task_t *task, isc_event_t *event) {
|
|
dns_dispatchevent_t *devent = (dns_dispatchevent_t *)event;
|
|
isc_result_t result;
|
|
bool wasfirst;
|
|
|
|
UNUSED(task);
|
|
|
|
LOCK(&lock);
|
|
wasfirst = first;
|
|
first = false;
|
|
responses++;
|
|
UNLOCK(&lock);
|
|
|
|
if (wasfirst) {
|
|
result = dns_dispatch_getnext(dispentry, &devent);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
} else {
|
|
dns_dispatch_removeresponse(&dispentry, &devent);
|
|
isc_app_shutdown();
|
|
}
|
|
}
|
|
|
|
static void
|
|
startit(isc_task_t *task, isc_event_t *event) {
|
|
isc_result_t result;
|
|
isc_socket_t *sock = NULL;
|
|
|
|
isc_socket_attach(dns_dispatch_getsocket(dispatch), &sock);
|
|
result = isc_socket_sendto(sock, event->ev_arg, task, senddone, sock,
|
|
&local, NULL);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
isc_event_free(&event);
|
|
}
|
|
|
|
/* test dispatch getnext */
|
|
static void
|
|
dispatch_getnext(void **state) {
|
|
isc_region_t region;
|
|
isc_result_t result;
|
|
isc_socket_t *sock = NULL;
|
|
isc_task_t *task = NULL;
|
|
uint16_t id;
|
|
struct in_addr ina;
|
|
unsigned char message[12];
|
|
unsigned int attrs;
|
|
unsigned char rbuf[12];
|
|
|
|
UNUSED(state);
|
|
|
|
result = isc_mutex_init(&lock);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
|
|
result = isc_task_create(taskmgr, 0, &task);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
|
|
result = dns_dispatchmgr_create(mctx, NULL, &dispatchmgr);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
|
|
ina.s_addr = htonl(INADDR_LOOPBACK);
|
|
isc_sockaddr_fromin(&local, &ina, 0);
|
|
attrs = DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_UDP;
|
|
result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr,
|
|
&local, 512, 6, 1024, 17, 19, attrs,
|
|
attrs, &dispatch);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
|
|
/*
|
|
* Create a local udp nameserver on the loopback.
|
|
*/
|
|
result = isc_socket_create(socketmgr, AF_INET, isc_sockettype_udp,
|
|
&sock);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
|
|
ina.s_addr = htonl(INADDR_LOOPBACK);
|
|
isc_sockaddr_fromin(&local, &ina, 0);
|
|
result = isc_socket_bind(sock, &local, 0);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
|
|
result = isc_socket_getsockname(sock, &local);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
|
|
first = true;
|
|
region.base = rbuf;
|
|
region.length = sizeof(rbuf);
|
|
result = isc_socket_recv(sock, ®ion, 1, task, nameserver, sock);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
|
|
result = dns_dispatch_addresponse(dispatch, &local, task, response,
|
|
NULL, &id, &dispentry);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
|
|
memset(message, 0, sizeof(message));
|
|
message[0] = (id >> 8) & 0xff;
|
|
message[1] = id & 0xff;
|
|
|
|
region.base = message;
|
|
region.length = sizeof(message);
|
|
result = isc_app_onrun(mctx, task, startit, ®ion);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
|
|
result = isc_app_run();
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
|
|
LOCK(&lock);
|
|
assert_int_equal(responses, 2);
|
|
UNLOCK(&lock);
|
|
|
|
/*
|
|
* Shutdown nameserver.
|
|
*/
|
|
isc_socket_cancel(sock, task, ISC_SOCKCANCEL_RECV);
|
|
isc_socket_detach(&sock);
|
|
isc_task_detach(&task);
|
|
|
|
/*
|
|
* Shutdown the dispatch.
|
|
*/
|
|
dns_dispatch_detach(&dispatch);
|
|
dns_dispatchmgr_destroy(&dispatchmgr);
|
|
|
|
/*
|
|
* Destroy the mutex.
|
|
*/
|
|
result = isc_mutex_destroy(&lock);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
}
|
|
|
|
int
|
|
main(void) {
|
|
const struct CMUnitTest tests[] = {
|
|
cmocka_unit_test_setup_teardown(dispatchset_create,
|
|
_setup, _teardown),
|
|
cmocka_unit_test_setup_teardown(dispatchset_get,
|
|
_setup, _teardown),
|
|
cmocka_unit_test_setup_teardown(dispatch_getnext,
|
|
_setup, _teardown),
|
|
};
|
|
|
|
return (cmocka_run_group_tests(tests, dns_test_init, dns_test_final));
|
|
}
|
|
|
|
#else /* HAVE_CMOCKA */
|
|
|
|
#include <stdio.h>
|
|
|
|
int
|
|
main(void) {
|
|
printf("1..0 # Skipped: cmocka not available\n");
|
|
return (0);
|
|
}
|
|
|
|
#endif
|