]>
git.saurik.com Git - apple/network_cmds.git/blob - unbound/testcode/unitneg.c
d3968409519ec341557813c99e57a89c3ba75e17
2 * testcode/unitneg.c - unit test for negative cache routines.
4 * Copyright (c) 2008, NLnet Labs. All rights reserved.
6 * This software is open source.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
15 * Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
19 * Neither the name of the NLNET LABS nor the names of its contributors may
20 * be used to endorse or promote products derived from this software without
21 * specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 * Calls negative cache unit tests. Exits with code 1 on a failure.
43 #include "util/net_help.h"
44 #include "util/data/packed_rrset.h"
45 #include "util/data/dname.h"
46 #include "testcode/unitmain.h"
47 #include "validator/val_neg.h"
48 #include "ldns/rrdef.h"
50 /** verbose unit test for negative cache */
51 static int negverbose
= 0;
53 /** debug printout of neg cache */
54 static void print_neg_cache(struct val_neg_cache
* neg
)
57 struct val_neg_zone
* z
;
58 struct val_neg_data
* d
;
59 printf("neg_cache print\n");
60 printf("memuse %d of %d\n", (int)neg
->use
, (int)neg
->max
);
61 printf("maxiter %d\n", (int)neg
->nsec3_max_iter
);
62 printf("%d zones\n", (int)neg
->tree
.count
);
63 RBTREE_FOR(z
, struct val_neg_zone
*, &neg
->tree
) {
64 dname_str(z
->name
, buf
);
66 printf(" len=%2.2d labs=%d inuse=%d count=%d tree.count=%d\n",
67 (int)z
->len
, z
->labs
, (int)z
->in_use
, z
->count
,
70 RBTREE_FOR(z
, struct val_neg_zone
*, &neg
->tree
) {
72 dname_print(stdout
, NULL
, z
->name
);
73 printf(" zone details\n");
74 printf("len=%2.2d labs=%d inuse=%d count=%d tree.count=%d\n",
75 (int)z
->len
, z
->labs
, (int)z
->in_use
, z
->count
,
79 dname_print(stdout
, NULL
, z
->parent
->name
);
82 printf("parent=NULL\n");
85 RBTREE_FOR(d
, struct val_neg_data
*, &z
->tree
) {
86 dname_str(d
->name
, buf
);
88 printf(" len=%2.2d labs=%d inuse=%d count=%d\n",
89 (int)d
->len
, d
->labs
, (int)d
->in_use
, d
->count
);
94 /** get static pointer to random zone name */
95 static char* get_random_zone(void)
97 static char zname
[256];
98 int labels
= random() % 3;
103 for(i
=0; i
<labels
; i
++) {
104 labnum
= random()%10
;
105 snprintf(p
, 256-(p
-zname
), "\003%3.3d", labnum
);
108 snprintf(p
, 256-(p
-zname
), "\007example\003com");
112 /** get static pointer to random data names from and to */
113 static void get_random_data(char** fromp
, char** top
, char* zname
)
115 static char buf1
[256], buf2
[256];
118 int labnum1
[10], labnum2
[10];
128 lab1
= random() %3
+ 1;
129 lab2
= lab1
+ random()%3
+ 1;
130 for(i
=0; i
<lab1
; i
++) {
131 labnum1
[i
] = random()%100
;
132 labnum2
[i
] = labnum1
[i
];
134 for(i
=lab1
; i
<lab2
; i
++) {
135 labnum2
[i
] = random()%100
;
137 } else if(type
== 1) {
140 lab1
= random()%3
+ 1;
141 for(i
=0; i
<lab1
; i
++) {
142 labnum1
[i
] = random()%100
;
144 } else if(type
== 2) {
147 lab2
= random()%3
+ 1;
148 for(i
=0; i
<lab2
; i
++) {
149 labnum2
[i
] = random()%100
;
153 int common
= random()%3
;
154 lab1
= random() %3
+ 1;
155 lab2
= random() %3
+ 1;
156 for(i
=0; i
<common
; i
++) {
157 labnum1
[i
] = random()%100
;
158 labnum2
[i
] = labnum1
[i
];
160 labnum1
[common
] = random()%100
;
161 labnum2
[common
] = labnum1
[common
] + random()%20
;
162 for(i
=common
; i
<lab1
; i
++)
163 labnum1
[i
] = random()%100
;
164 for(i
=common
; i
<lab2
; i
++)
165 labnum2
[i
] = random()%100
;
168 /* construct first */
170 for(i
=0; i
<lab1
; i
++) {
171 snprintf(p
, 256-(p
-buf1
), "\003%3.3d", labnum1
[i
]);
174 snprintf(p
, 256-(p
-buf1
), "%s", zname
);
178 for(i
=0; i
<lab2
; i
++) {
179 snprintf(p
, 256-(p
-buf2
)-3, "\003%3.3d", labnum2
[i
]);
182 snprintf(p
, 256-(p
-buf2
)-3, "%s", zname
);
183 buf2
[0] = (char)(strlen(buf2
+2)+1);
187 log_nametypeclass(0, "add from", (uint8_t*)buf1
, 0, 0);
188 log_nametypeclass(0, "add to ", (uint8_t*)buf2
+2, 0, 0);
192 /** add a random item */
193 static void add_item(struct val_neg_cache
* neg
)
195 struct val_neg_zone
* z
;
196 struct packed_rrset_data rd
;
197 struct ub_packed_rrset_key nsec
;
201 char* zname
= get_random_zone();
204 lock_basic_lock(&neg
->lock
);
206 log_nametypeclass(0, "add to zone", (uint8_t*)zname
, 0, 0);
207 z
= neg_find_zone(neg
, (uint8_t*)zname
, strlen(zname
)+1,
210 z
= neg_create_zone(neg
, (uint8_t*)zname
, strlen(zname
)+1,
214 val_neg_zone_take_inuse(z
);
216 /* construct random NSEC item */
217 get_random_data(&from
, &to
, zname
);
219 /* create nsec and insert it */
220 memset(&rd
, 0, sizeof(rd
));
221 memset(&nsec
, 0, sizeof(nsec
));
222 nsec
.rk
.dname
= (uint8_t*)from
;
223 nsec
.rk
.dname_len
= strlen(from
)+1;
224 nsec
.rk
.type
= htons(LDNS_RR_TYPE_NSEC
);
225 nsec
.rk
.rrset_class
= htons(LDNS_RR_CLASS_IN
);
226 nsec
.entry
.data
= &rd
;
227 rd
.security
= sec_status_secure
;
233 rd
.rr_data
= &rr_data
;
234 rr_data
= (uint8_t*)to
;
236 neg_insert_data(neg
, z
, &nsec
);
237 lock_basic_unlock(&neg
->lock
);
240 /** remove a random item */
241 static void remove_item(struct val_neg_cache
* neg
)
244 struct val_neg_data
* d
;
246 struct val_neg_zone
* z
;
248 lock_basic_lock(&neg
->lock
);
249 if(neg
->tree
.count
== 0) {
250 lock_basic_unlock(&neg
->lock
);
251 return; /* nothing to delete */
254 /* pick a random zone */
255 walk
= rbtree_first(&neg
->tree
); /* first highest parent, big count */
256 z
= (struct val_neg_zone
*)walk
;
257 n
= random() % (int)(z
->count
);
259 printf("neg stress delete zone %d\n", n
);
261 walk
= rbtree_first(&neg
->tree
);
262 z
= (struct val_neg_zone
*)walk
;
263 while(i
!=n
+1 && walk
&& walk
!= RBTREE_NULL
&& !z
->in_use
) {
264 walk
= rbtree_next(walk
);
265 z
= (struct val_neg_zone
*)walk
;
269 if(!walk
|| walk
== RBTREE_NULL
) {
270 lock_basic_unlock(&neg
->lock
);
274 lock_basic_unlock(&neg
->lock
);
278 log_nametypeclass(0, "delete zone", z
->name
, 0, 0);
280 /* pick a random nsec item. - that is in use */
281 walk
= rbtree_first(&z
->tree
); /* first is highest parent */
282 d
= (struct val_neg_data
*)walk
;
283 n
= random() % (int)(d
->count
);
285 printf("neg stress delete item %d\n", n
);
287 walk
= rbtree_first(&z
->tree
);
288 d
= (struct val_neg_data
*)walk
;
289 while(i
!=n
+1 && walk
&& walk
!= RBTREE_NULL
&& !d
->in_use
) {
290 walk
= rbtree_next(walk
);
291 d
= (struct val_neg_data
*)walk
;
295 if(!walk
|| walk
== RBTREE_NULL
) {
296 lock_basic_unlock(&neg
->lock
);
301 log_nametypeclass(0, "neg delete item:", d
->name
, 0, 0);
302 neg_delete_data(neg
, d
);
304 lock_basic_unlock(&neg
->lock
);
307 /** sum up the zone trees */
308 static size_t sumtrees_all(struct val_neg_cache
* neg
)
311 struct val_neg_zone
* z
;
312 RBTREE_FOR(z
, struct val_neg_zone
*, &neg
->tree
) {
313 res
+= z
->tree
.count
;
318 /** sum up the zone trees, in_use only */
319 static size_t sumtrees_inuse(struct val_neg_cache
* neg
)
322 struct val_neg_zone
* z
;
323 struct val_neg_data
* d
;
324 RBTREE_FOR(z
, struct val_neg_zone
*, &neg
->tree
) {
325 /* get count of highest parent for num in use */
326 d
= (struct val_neg_data
*)rbtree_first(&z
->tree
);
327 if(d
&& (rbnode_t
*)d
!=RBTREE_NULL
)
333 /** check if lru is still valid */
334 static void check_lru(struct val_neg_cache
* neg
)
336 struct val_neg_data
* p
, *np
;
342 unit_assert(neg
->first
== p
);
346 unit_assert(np
->prev
== p
);
348 unit_assert(neg
->last
== p
);
353 inuse
= sumtrees_inuse(neg
);
355 printf("num lru %d, inuse %d, all %d\n",
356 (int)num
, (int)sumtrees_inuse(neg
),
357 (int)sumtrees_all(neg
));
358 unit_assert( num
== inuse
);
359 unit_assert( inuse
<= sumtrees_all(neg
));
362 /** sum up number of items inuse in subtree */
363 static int sum_subtree_inuse(struct val_neg_zone
* zone
,
364 struct val_neg_data
* data
)
366 struct val_neg_data
* d
;
368 RBTREE_FOR(d
, struct val_neg_data
*, &zone
->tree
) {
369 if(dname_subdomain_c(d
->name
, data
->name
)) {
377 /** sum up number of items inuse in subtree */
378 static int sum_zone_subtree_inuse(struct val_neg_cache
* neg
,
379 struct val_neg_zone
* zone
)
381 struct val_neg_zone
* z
;
383 RBTREE_FOR(z
, struct val_neg_zone
*, &neg
->tree
) {
384 if(dname_subdomain_c(z
->name
, zone
->name
)) {
392 /** check point in data tree */
393 static void check_data(struct val_neg_zone
* zone
, struct val_neg_data
* data
)
395 unit_assert(data
->count
> 0);
397 unit_assert(data
->parent
->count
>= data
->count
);
398 if(data
->parent
->in_use
) {
399 unit_assert(data
->parent
->count
> data
->count
);
401 unit_assert(data
->parent
->labs
== data
->labs
-1);
402 /* and parent must be one label shorter */
403 unit_assert(data
->name
[0] == (data
->len
-data
->parent
->len
-1));
404 unit_assert(query_dname_compare(data
->name
+ data
->name
[0]+1,
405 data
->parent
->name
) == 0);
408 unit_assert(dname_is_root(data
->name
));
411 unit_assert(data
->count
== sum_subtree_inuse(zone
, data
));
414 /** check if tree of data in zone is valid */
415 static void checkzonetree(struct val_neg_zone
* zone
)
417 struct val_neg_data
* d
;
419 /* check all data in tree */
420 RBTREE_FOR(d
, struct val_neg_data
*, &zone
->tree
) {
425 /** check if negative cache is still valid */
426 static void check_zone_invariants(struct val_neg_cache
* neg
,
427 struct val_neg_zone
* zone
)
429 unit_assert(zone
->nsec3_hash
== 0);
430 unit_assert(zone
->tree
.cmp
== &val_neg_data_compare
);
431 unit_assert(zone
->count
!= 0);
433 if(zone
->tree
.count
== 0)
434 unit_assert(!zone
->in_use
);
437 /* details on error */
438 log_nametypeclass(0, "zone", zone
->name
, 0, 0);
439 log_err("inuse %d count=%d tree.count=%d",
440 zone
->in_use
, zone
->count
,
441 (int)zone
->tree
.count
);
443 print_neg_cache(neg
);
445 unit_assert(zone
->in_use
);
449 unit_assert(zone
->parent
->count
>= zone
->count
);
450 if(zone
->parent
->in_use
) {
451 unit_assert(zone
->parent
->count
> zone
->count
);
453 unit_assert(zone
->parent
->labs
== zone
->labs
-1);
454 /* and parent must be one label shorter */
455 unit_assert(zone
->name
[0] == (zone
->len
-zone
->parent
->len
-1));
456 unit_assert(query_dname_compare(zone
->name
+ zone
->name
[0]+1,
457 zone
->parent
->name
) == 0);
460 unit_assert(dname_is_root(zone
->name
));
463 unit_assert(zone
->count
== sum_zone_subtree_inuse(neg
, zone
));
465 /* check structure of zone data tree */
469 /** check if negative cache is still valid */
470 static void check_neg_invariants(struct val_neg_cache
* neg
)
472 struct val_neg_zone
* z
;
473 /* check structure of LRU list */
474 lock_basic_lock(&neg
->lock
);
476 unit_assert(neg
->max
== 1024*1024);
477 unit_assert(neg
->nsec3_max_iter
== 1500);
478 unit_assert(neg
->tree
.cmp
== &val_neg_zone_compare
);
480 if(neg
->tree
.count
== 0) {
482 unit_assert(neg
->tree
.count
== 0);
483 unit_assert(neg
->first
== NULL
);
484 unit_assert(neg
->last
== NULL
);
485 unit_assert(neg
->use
== 0);
486 lock_basic_unlock(&neg
->lock
);
490 unit_assert(neg
->first
!= NULL
);
491 unit_assert(neg
->last
!= NULL
);
493 RBTREE_FOR(z
, struct val_neg_zone
*, &neg
->tree
) {
494 check_zone_invariants(neg
, z
);
496 lock_basic_unlock(&neg
->lock
);
499 /** perform stress test on insert and delete in neg cache */
500 static void stress_test(struct val_neg_cache
* neg
)
504 printf("negcache test\n");
505 for(i
=0; i
<100; i
++) {
506 if(random() % 10 < 8)
508 else remove_item(neg
);
509 check_neg_invariants(neg
);
513 printf("neg stress empty\n");
516 check_neg_invariants(neg
);
519 printf("neg stress emptied\n");
520 unit_assert(neg
->first
== NULL
);
522 for(i
=0; i
<100; i
++) {
523 if(random() % 10 < 8)
525 else remove_item(neg
);
526 check_neg_invariants(neg
);
532 struct val_neg_cache
* neg
;
534 unit_show_feature("negative cache");
536 /* create with defaults */
537 neg
= val_neg_create(NULL
, 1500);
542 neg_cache_delete(neg
);