xref: /netbsd-src/external/bsd/unbound/dist/testcode/unitecs.c (revision 91f7d55fb697b5e0475da4718fa34c3a3ebeac85)
10cd9f4ecSchristos /*
20cd9f4ecSchristos  * testcode/unitecs.c - unit test for ecs routines.
30cd9f4ecSchristos  *
40cd9f4ecSchristos  * Copyright (c) 2013, NLnet Labs. All rights reserved.
50cd9f4ecSchristos  *
60cd9f4ecSchristos  * This software is open source.
70cd9f4ecSchristos  *
80cd9f4ecSchristos  * Redistribution and use in source and binary forms, with or without
90cd9f4ecSchristos  * modification, are permitted provided that the following conditions
100cd9f4ecSchristos  * are met:
110cd9f4ecSchristos  *
120cd9f4ecSchristos  * Redistributions of source code must retain the above copyright notice,
130cd9f4ecSchristos  * this list of conditions and the following disclaimer.
140cd9f4ecSchristos  *
150cd9f4ecSchristos  * Redistributions in binary form must reproduce the above copyright notice,
160cd9f4ecSchristos  * this list of conditions and the following disclaimer in the documentation
170cd9f4ecSchristos  * and/or other materials provided with the distribution.
180cd9f4ecSchristos  *
190cd9f4ecSchristos  * Neither the name of the NLNET LABS nor the names of its contributors may
200cd9f4ecSchristos  * be used to endorse or promote products derived from this software without
210cd9f4ecSchristos  * specific prior written permission.
220cd9f4ecSchristos  *
230cd9f4ecSchristos  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
240cd9f4ecSchristos  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
250cd9f4ecSchristos  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
260cd9f4ecSchristos  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
270cd9f4ecSchristos  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
280cd9f4ecSchristos  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
290cd9f4ecSchristos  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
300cd9f4ecSchristos  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
310cd9f4ecSchristos  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
320cd9f4ecSchristos  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
330cd9f4ecSchristos  * POSSIBILITY OF SUCH DAMAGE.
340cd9f4ecSchristos  *
350cd9f4ecSchristos  */
360cd9f4ecSchristos 
370cd9f4ecSchristos /**
380cd9f4ecSchristos  * \file
390cd9f4ecSchristos  * Calls ecs related unit tests. Exits with code 1 on a failure.
400cd9f4ecSchristos  */
410cd9f4ecSchristos 
420cd9f4ecSchristos #include "config.h"
430cd9f4ecSchristos 
440cd9f4ecSchristos #ifdef CLIENT_SUBNET
450cd9f4ecSchristos 
460cd9f4ecSchristos #include "util/log.h"
470cd9f4ecSchristos #include "util/module.h"
480cd9f4ecSchristos #include "testcode/unitmain.h"
490cd9f4ecSchristos #include "edns-subnet/addrtree.h"
500cd9f4ecSchristos #include "edns-subnet/subnetmod.h"
510cd9f4ecSchristos 
520cd9f4ecSchristos /*
530cd9f4ecSchristos 	void printkey(addrkey_t *k, addrlen_t bits)
540cd9f4ecSchristos 	{
550cd9f4ecSchristos 		int byte;
560cd9f4ecSchristos 		int bytes = bits/8 + ((bits%8)>0);
570cd9f4ecSchristos 		char msk = 0xFF;
580cd9f4ecSchristos 		for (byte = 0; byte < bytes; byte++) {
590cd9f4ecSchristos 			//~ if (byte+1 == bytes)
600cd9f4ecSchristos 				//~ msk = 0xFF<<(8-bits%8);
610cd9f4ecSchristos 			printf("%02x ", k[byte]&msk);
620cd9f4ecSchristos 		}
630cd9f4ecSchristos 	}
640cd9f4ecSchristos 
650cd9f4ecSchristos 	void print_tree(struct addrnode* node, int indent, int maxdepth)
660cd9f4ecSchristos 	{
670cd9f4ecSchristos 		struct addredge* edge;
680cd9f4ecSchristos 		int i, s, byte;
690cd9f4ecSchristos 		if (indent == 0) printf("-----Tree-----\n");
700cd9f4ecSchristos 		if (indent > maxdepth) {
710cd9f4ecSchristos 			printf("\n");
720cd9f4ecSchristos 			return;
730cd9f4ecSchristos 		}
740cd9f4ecSchristos 		printf("[node elem:%d] (%d)\n", node->elem != NULL, node);
750cd9f4ecSchristos 		for (i = 0; i<2; i++) {
760cd9f4ecSchristos 			if (node->edge[i]) {
770cd9f4ecSchristos 				for (s = 0; s < indent; s++) printf(" ");
780cd9f4ecSchristos 				printkey(node->edge[i]->str, node->edge[i]->len);
790cd9f4ecSchristos 				printf("(len %d bits, %d bytes) ", node->edge[i]->len,
800cd9f4ecSchristos 					node->edge[i]->len/8 + ((node->edge[i]->len%8)>0));
810cd9f4ecSchristos 				print_tree(node->edge[i]->node, indent+1, maxdepth);
820cd9f4ecSchristos 			}
830cd9f4ecSchristos 		}
840cd9f4ecSchristos 		if (indent == 0) printf("-----Tree-----");
850cd9f4ecSchristos 	}
860cd9f4ecSchristos */
870cd9f4ecSchristos 
880cd9f4ecSchristos /* what should we check?
890cd9f4ecSchristos  * X - is it balanced? (a node with 1 child should not have
900cd9f4ecSchristos  * a node with 1 child MUST have elem
910cd9f4ecSchristos  * child must be sub of parent
920cd9f4ecSchristos  * edge must be longer than parent edge
930cd9f4ecSchristos  * */
addrtree_inconsistent_subtree(struct addrtree * tree,struct addredge * parent_edge,addrlen_t depth)940cd9f4ecSchristos static int addrtree_inconsistent_subtree(struct addrtree* tree,
950cd9f4ecSchristos 	struct addredge* parent_edge, addrlen_t depth)
960cd9f4ecSchristos {
970cd9f4ecSchristos 	struct addredge* edge;
980cd9f4ecSchristos 	struct addrnode* node = parent_edge->node;
990cd9f4ecSchristos 	int childcount, i, r;
1000cd9f4ecSchristos 	if (depth > tree->max_depth) return 15;
1010cd9f4ecSchristos 	childcount = (node->edge[0] != NULL) + (node->edge[1] != NULL);
1020cd9f4ecSchristos 	/* Only nodes with 2 children should possibly have no element. */
1030cd9f4ecSchristos 	if (childcount < 2 && !node->elem) return 10;
1040cd9f4ecSchristos 	for (i = 0; i<2; i++) {
1050cd9f4ecSchristos 		edge = node->edge[i];
1060cd9f4ecSchristos 		if (!edge) continue;
1070cd9f4ecSchristos 		if (!edge->node) return 11;
1080cd9f4ecSchristos 		if (!edge->str) return 12;
1090cd9f4ecSchristos 		if (edge->len <= parent_edge->len) return 13;
1100cd9f4ecSchristos 		if (!unittest_wrapper_addrtree_issub(parent_edge->str,
1110cd9f4ecSchristos 				parent_edge->len, edge->str, edge->len, 0))
1120cd9f4ecSchristos 			return 14;
1130cd9f4ecSchristos 		if ((r = addrtree_inconsistent_subtree(tree, edge, depth+1)) != 0)
1140cd9f4ecSchristos 			return 100+r;
1150cd9f4ecSchristos 	}
1160cd9f4ecSchristos 	return 0;
1170cd9f4ecSchristos }
1180cd9f4ecSchristos 
addrtree_inconsistent(struct addrtree * tree)1190cd9f4ecSchristos static int addrtree_inconsistent(struct addrtree* tree)
1200cd9f4ecSchristos {
1210cd9f4ecSchristos 	struct addredge* edge;
1220cd9f4ecSchristos 	int i, r;
1230cd9f4ecSchristos 
1240cd9f4ecSchristos 	if (!tree) return 0;
1250cd9f4ecSchristos 	if (!tree->root) return 1;
1260cd9f4ecSchristos 
1270cd9f4ecSchristos 	for (i = 0; i<2; i++) {
1280cd9f4ecSchristos 		edge = tree->root->edge[i];
1290cd9f4ecSchristos 		if (!edge) continue;
1300cd9f4ecSchristos 		if (!edge->node) return 3;
1310cd9f4ecSchristos 		if (!edge->str) return 4;
1320cd9f4ecSchristos 		if ((r = addrtree_inconsistent_subtree(tree, edge, 1)) != 0)
1330cd9f4ecSchristos 			return r;
1340cd9f4ecSchristos 	}
1350cd9f4ecSchristos 	return 0;
1360cd9f4ecSchristos }
1370cd9f4ecSchristos 
randomkey(addrkey_t ** k,int maxlen)1380cd9f4ecSchristos static addrlen_t randomkey(addrkey_t **k, int maxlen)
1390cd9f4ecSchristos {
1400cd9f4ecSchristos 	int byte;
1410cd9f4ecSchristos 	int bits = rand() % maxlen;
1420cd9f4ecSchristos 	int bytes = bits/8 + (bits%8>0); /*ceil*/
1430cd9f4ecSchristos 	*k = (addrkey_t *) malloc(bytes * sizeof(addrkey_t));
1440cd9f4ecSchristos 	for (byte = 0; byte < bytes; byte++) {
1450cd9f4ecSchristos 		(*k)[byte] = (addrkey_t)(rand() & 0xFF);
1460cd9f4ecSchristos 	}
1470cd9f4ecSchristos 	return (addrlen_t)bits;
1480cd9f4ecSchristos }
1490cd9f4ecSchristos 
elemfree(void * envptr,void * elemptr)1500cd9f4ecSchristos static void elemfree(void *envptr, void *elemptr)
1510cd9f4ecSchristos {
1520cd9f4ecSchristos 	struct reply_info *elem = (struct reply_info *)elemptr;
1530cd9f4ecSchristos 	(void)envptr;
1540cd9f4ecSchristos 	free(elem);
1550cd9f4ecSchristos }
1560cd9f4ecSchristos 
consistency_test(void)1570cd9f4ecSchristos static void consistency_test(void)
1580cd9f4ecSchristos {
1590cd9f4ecSchristos 	addrlen_t l;
1600cd9f4ecSchristos 	time_t i;
161f42d8de7Schristos 	uint32_t count;
1620cd9f4ecSchristos 	addrkey_t *k;
1630cd9f4ecSchristos 	struct addrtree* t;
1640cd9f4ecSchristos 	struct module_env env;
1650cd9f4ecSchristos 	struct reply_info *elem;
1660cd9f4ecSchristos 	time_t timenow = 0;
1670cd9f4ecSchristos 	unit_show_func("edns-subnet/addrtree.h", "Tree consistency check");
1680cd9f4ecSchristos 	srand(9195); /* just some value for reproducibility */
1690cd9f4ecSchristos 
1700cd9f4ecSchristos 	t = addrtree_create(100, &elemfree, &unittest_wrapper_subnetmod_sizefunc, &env, 0);
1710cd9f4ecSchristos 	count = t->node_count;
1720cd9f4ecSchristos 	unit_assert(count == 0);
1730cd9f4ecSchristos 	for (i = 0; i < 1000; i++) {
1740cd9f4ecSchristos 		l = randomkey(&k, 128);
1750cd9f4ecSchristos 		elem = (struct reply_info *) calloc(1, sizeof(struct reply_info));
176*91f7d55fSchristos 		addrtree_insert(t, k, l, 64, elem, timenow + 10, timenow, 0);
1770cd9f4ecSchristos 		/* This should always hold because no items ever expire. They
1780cd9f4ecSchristos 		 * could be overwritten, though. */
1790cd9f4ecSchristos 		unit_assert( count <= t->node_count );
1800cd9f4ecSchristos 		count = t->node_count;
1810cd9f4ecSchristos 		free(k);
1820cd9f4ecSchristos 		unit_assert( !addrtree_inconsistent(t) );
1830cd9f4ecSchristos 	}
1840cd9f4ecSchristos 	addrtree_delete(t);
1850cd9f4ecSchristos 
1860cd9f4ecSchristos 	unit_show_func("edns-subnet/addrtree.h", "Tree consistency with purge");
1870cd9f4ecSchristos 	t = addrtree_create(8, &elemfree, &unittest_wrapper_subnetmod_sizefunc, &env, 0);
1880cd9f4ecSchristos 	unit_assert(t->node_count == 0);
1890cd9f4ecSchristos 	for (i = 0; i < 1000; i++) {
1900cd9f4ecSchristos 		l = randomkey(&k, 128);
1910cd9f4ecSchristos 		elem = (struct reply_info *) calloc(1, sizeof(struct reply_info));
192*91f7d55fSchristos 		addrtree_insert(t, k, l, 64, elem, i + 10, i, 0);
1930cd9f4ecSchristos 		free(k);
1940cd9f4ecSchristos 		unit_assert( !addrtree_inconsistent(t) );
1950cd9f4ecSchristos 	}
1960cd9f4ecSchristos 	addrtree_delete(t);
1970cd9f4ecSchristos 
1980cd9f4ecSchristos 	unit_show_func("edns-subnet/addrtree.h", "Tree consistency with limit");
1990cd9f4ecSchristos 	t = addrtree_create(8, &elemfree, &unittest_wrapper_subnetmod_sizefunc, &env, 27);
2000cd9f4ecSchristos 	unit_assert(t->node_count == 0);
2010cd9f4ecSchristos 	for (i = 0; i < 1000; i++) {
2020cd9f4ecSchristos 		l = randomkey(&k, 128);
2030cd9f4ecSchristos 		elem = (struct reply_info *) calloc(1, sizeof(struct reply_info));
204*91f7d55fSchristos 		addrtree_insert(t, k, l, 64, elem, i + 10, i, 0);
2050cd9f4ecSchristos 		unit_assert( t->node_count <= 27);
2060cd9f4ecSchristos 		free(k);
2070cd9f4ecSchristos 		unit_assert( !addrtree_inconsistent(t) );
2080cd9f4ecSchristos 	}
2090cd9f4ecSchristos 	addrtree_delete(t);
2100cd9f4ecSchristos }
2110cd9f4ecSchristos 
issub_test(void)2120cd9f4ecSchristos static void issub_test(void)
2130cd9f4ecSchristos {
2140cd9f4ecSchristos 	addrkey_t k1[] = {0x55, 0x55, 0x5A};
2150cd9f4ecSchristos 	addrkey_t k2[] = {0x55, 0x5D, 0x5A};
2160cd9f4ecSchristos 	unit_show_func("edns-subnet/addrtree.h", "issub");
2170cd9f4ecSchristos 	unit_assert( !unittest_wrapper_addrtree_issub(k1, 24, k2, 24,  0) );
2180cd9f4ecSchristos 	unit_assert(  unittest_wrapper_addrtree_issub(k1,  8, k2, 16,  0) );
2190cd9f4ecSchristos 	unit_assert(  unittest_wrapper_addrtree_issub(k2, 12, k1, 13,  0) );
2200cd9f4ecSchristos 	unit_assert( !unittest_wrapper_addrtree_issub(k1, 16, k2, 12,  0) );
2210cd9f4ecSchristos 	unit_assert(  unittest_wrapper_addrtree_issub(k1, 12, k2, 12,  0) );
2220cd9f4ecSchristos 	unit_assert( !unittest_wrapper_addrtree_issub(k1, 13, k2, 13,  0) );
2230cd9f4ecSchristos 	unit_assert(  unittest_wrapper_addrtree_issub(k1, 24, k2, 24, 13) );
2240cd9f4ecSchristos 	unit_assert( !unittest_wrapper_addrtree_issub(k1, 24, k2, 20, 13) );
2250cd9f4ecSchristos 	unit_assert(  unittest_wrapper_addrtree_issub(k1, 20, k2, 24, 13) );
2260cd9f4ecSchristos }
2270cd9f4ecSchristos 
getbit_test(void)2280cd9f4ecSchristos static void getbit_test(void)
2290cd9f4ecSchristos {
2300cd9f4ecSchristos 	addrkey_t k1[] = {0x55, 0x55, 0x5A};
2310cd9f4ecSchristos 	int i;
2320cd9f4ecSchristos 	unit_show_func("edns-subnet/addrtree.h", "getbit");
2330cd9f4ecSchristos 	for(i = 0; i<20; i++) {
2340cd9f4ecSchristos 		unit_assert( unittest_wrapper_addrtree_getbit(k1, 20, (addrlen_t)i) == (i&1) );
2350cd9f4ecSchristos 	}
2360cd9f4ecSchristos }
2370cd9f4ecSchristos 
bits_common_test(void)2380cd9f4ecSchristos static void bits_common_test(void)
2390cd9f4ecSchristos {
2400cd9f4ecSchristos 	addrkey_t k1[] = {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0};
2410cd9f4ecSchristos 	addrkey_t k2[] = {0,0,0,0,0,0,0,0};
2420cd9f4ecSchristos 	addrlen_t i;
2430cd9f4ecSchristos 
2440cd9f4ecSchristos 	unit_show_func("edns-subnet/addrtree.h", "bits_common");
2450cd9f4ecSchristos 	for(i = 0; i<64; i++) {
2460cd9f4ecSchristos 		unit_assert( unittest_wrapper_addrtree_bits_common(k1, 64, k1, 64, i) == 64 );
2470cd9f4ecSchristos 	}
2480cd9f4ecSchristos 	for(i = 0; i<8; i++) {
2490cd9f4ecSchristos 		k2[i] = k1[i]^(1<<i);
2500cd9f4ecSchristos 	}
2510cd9f4ecSchristos 	unit_assert( unittest_wrapper_addrtree_bits_common(k1, 64, k2, 64,  0) == 0*8+7 );
2520cd9f4ecSchristos 	unit_assert( unittest_wrapper_addrtree_bits_common(k1, 64, k2, 64,  8) == 1*8+6 );
2530cd9f4ecSchristos 	unit_assert( unittest_wrapper_addrtree_bits_common(k1, 64, k2, 64, 16) == 2*8+5 );
2540cd9f4ecSchristos 	unit_assert( unittest_wrapper_addrtree_bits_common(k1, 64, k2, 64, 24) == 3*8+4 );
2550cd9f4ecSchristos 	unit_assert( unittest_wrapper_addrtree_bits_common(k1, 64, k2, 64, 32) == 4*8+3 );
2560cd9f4ecSchristos 	unit_assert( unittest_wrapper_addrtree_bits_common(k1, 64, k2, 64, 40) == 5*8+2 );
2570cd9f4ecSchristos 	unit_assert( unittest_wrapper_addrtree_bits_common(k1, 64, k2, 64, 48) == 6*8+1 );
2580cd9f4ecSchristos 	unit_assert( unittest_wrapper_addrtree_bits_common(k1, 64, k2, 64, 56) == 7*8+0 );
2590cd9f4ecSchristos }
2600cd9f4ecSchristos 
cmpbit_test(void)2610cd9f4ecSchristos static void cmpbit_test(void)
2620cd9f4ecSchristos {
2630cd9f4ecSchristos 	addrkey_t k1[] = {0xA5, 0x0F};
2640cd9f4ecSchristos 	addrkey_t k2[] = {0x5A, 0xF0};
2650cd9f4ecSchristos 	addrlen_t i;
2660cd9f4ecSchristos 
2670cd9f4ecSchristos 	unit_show_func("edns-subnet/addrtree.h", "cmpbit");
2680cd9f4ecSchristos 	for(i = 0; i<16; i++) {
2690cd9f4ecSchristos 		unit_assert( !unittest_wrapper_addrtree_cmpbit(k1,k1,i) );
2700cd9f4ecSchristos 		unit_assert(  unittest_wrapper_addrtree_cmpbit(k1,k2,i) );
2710cd9f4ecSchristos 	}
2720cd9f4ecSchristos }
2730cd9f4ecSchristos 
ecs_test(void)2740cd9f4ecSchristos void ecs_test(void)
2750cd9f4ecSchristos {
2760cd9f4ecSchristos 	unit_show_feature("ecs");
2770cd9f4ecSchristos 	cmpbit_test();
2780cd9f4ecSchristos 	bits_common_test();
2790cd9f4ecSchristos 	getbit_test();
2800cd9f4ecSchristos 	issub_test();
2810cd9f4ecSchristos 	consistency_test();
2820cd9f4ecSchristos }
2830cd9f4ecSchristos #endif /* CLIENT_SUBNET */
2840cd9f4ecSchristos 
285