]>
Commit | Line | Data |
---|---|---|
6e999c3c | 1 | /* |
ae566556 | 2 | * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") |
6e999c3c SK |
3 | * Copyright (C) 1999-2003 Internet Software Consortium. |
4 | * | |
5 | * Permission to use, copy, modify, and/or distribute this software for any | |
6 | * purpose with or without fee is hereby granted, provided that the above | |
7 | * copyright notice and this permission notice appear in all copies. | |
8 | * | |
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH | |
10 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | |
11 | * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, | |
12 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM | |
13 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE | |
14 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | |
15 | * PERFORMANCE OF THIS SOFTWARE. | |
16 | */ | |
17 | ||
ae566556 | 18 | /* $Id: t_api.c,v 1.3 2009/01/22 00:43:58 sar Exp $ */ |
6e999c3c SK |
19 | |
20 | /*! \file */ | |
21 | ||
22 | /* | |
23 | * This test API framework is taken from the BIND 9 code. It has been | |
24 | * modified to remove the DNS-specific parts, and the BIND-specific | |
25 | * parts. | |
26 | * | |
27 | * The DNS-specific parts are now wrapped with the DNS_SUPPORT macro, | |
28 | * and the BIND-specific parts are now wrapped with the BIND_SUPPORT | |
29 | * macro. | |
30 | */ | |
31 | ||
32 | #include <config.h> | |
33 | ||
34 | #include <ctype.h> | |
35 | #include <errno.h> | |
36 | #include <limits.h> | |
37 | #include <signal.h> | |
38 | #include <stdarg.h> | |
39 | #include <stdio.h> | |
40 | #include <stdlib.h> | |
41 | #include <time.h> | |
42 | #include <unistd.h> | |
43 | ||
44 | #include <sys/wait.h> | |
45 | ||
46 | #include <isc-dhcp/boolean.h> | |
47 | #include <isc-dhcp/commandline.h> | |
48 | #include <isc-dhcp/print.h> | |
49 | #include <isc-dhcp/string.h> | |
50 | #include <isc-dhcp/mem.h> | |
51 | ||
52 | #ifdef DNS_SUPPORT | |
53 | #include <dns/compress.h> | |
54 | #include <dns/result.h> | |
55 | #endif /* DNS_SUPPORT */ | |
56 | ||
57 | #ifndef BIND_SUPPORT | |
58 | #define isc_commandline_parse getopt | |
59 | #define isc_commandline_argument optarg | |
60 | #define isc_commandline_option optopt | |
61 | #endif /* BIND_SUPPORT */ | |
62 | ||
63 | #include "t_api.h" | |
ae566556 | 64 | #include "cdefs.h" |
6e999c3c SK |
65 | |
66 | static const char *Usage = | |
67 | "\t-a : run all tests\n" | |
68 | "\t-b <dir> : chdir to dir before running tests" | |
69 | "\t-c <config_file> : use specified config file\n" | |
70 | "\t-d <debug_level> : set debug level to debug_level\n" | |
71 | "\t-h : print test info\n" | |
72 | "\t-u : print usage info\n" | |
73 | "\t-n <test_name> : run specified test name\n" | |
74 | "\t-t <test_number> : run specified test number\n" | |
75 | "\t-x : don't execute tests in a subproc\n" | |
76 | "\t-q <timeout> : use 'timeout' as the timeout value\n"; | |
77 | /*!< | |
78 | * -a --> run all tests | |
79 | * -b dir --> chdir to dir before running tests | |
80 | * -c config --> use config file 'config' | |
81 | * -d --> turn on api debugging | |
82 | * -h --> print out available test names | |
83 | * -u --> print usage info | |
84 | * -n name --> run test named name | |
85 | * -tn --> run test n | |
86 | * -x --> don't execute testcases in a subproc | |
87 | * -q timeout --> use 'timeout' as the timeout value | |
88 | */ | |
89 | ||
90 | #define T_MAXTESTS 256 /*% must be 0 mod 8 */ | |
91 | #define T_MAXENV 256 | |
92 | #define T_DEFAULT_CONFIG "t_config" | |
93 | #define T_BUFSIZ 256 | |
94 | #define T_BIGBUF 4096 | |
95 | ||
96 | #define T_TCTOUT 60 | |
97 | ||
98 | int T_debug; | |
99 | int T_timeout; | |
100 | pid_t T_pid; | |
101 | static const char * T_config; | |
102 | static char T_tvec[T_MAXTESTS / 8]; | |
103 | static char * T_env[T_MAXENV + 1]; | |
104 | static char T_buf[T_BIGBUF]; | |
105 | static char * T_dir; | |
106 | ||
107 | static int | |
108 | t_initconf(const char *path); | |
109 | ||
110 | static int | |
111 | t_dumpconf(const char *path); | |
112 | ||
113 | static int | |
114 | t_putinfo(const char *key, const char *info); | |
115 | ||
116 | static char * | |
117 | t_getdate(char *buf, size_t buflen); | |
118 | ||
119 | static void | |
120 | printhelp(void); | |
121 | ||
122 | static void | |
123 | printusage(void); | |
124 | ||
125 | static int T_int; | |
126 | ||
127 | static void | |
128 | t_sighandler(int sig) { | |
129 | T_int = sig; | |
130 | } | |
131 | ||
132 | int | |
133 | main(int argc, char **argv) { | |
134 | int c; | |
135 | int tnum; | |
136 | int subprocs; | |
137 | pid_t deadpid; | |
138 | int status; | |
139 | int len; | |
140 | isc_boolean_t first; | |
141 | testspec_t *pts; | |
142 | struct sigaction sa; | |
143 | ||
144 | #ifdef BIND_SUPPORT | |
145 | isc_mem_debugging = ISC_MEM_DEBUGRECORD; | |
146 | #endif /* BIND_SUPPORT */ | |
147 | first = ISC_TRUE; | |
148 | subprocs = 1; | |
149 | T_timeout = T_TCTOUT; | |
150 | ||
151 | /* | |
152 | * -a option is now default. | |
153 | */ | |
154 | memset(T_tvec, 0xffff, sizeof(T_tvec)); | |
155 | ||
156 | /* | |
157 | * Parse args. | |
158 | */ | |
159 | while ((c = isc_commandline_parse(argc, argv, ":at:c:d:n:huxq:b:")) | |
160 | != -1) { | |
161 | if (c == 'a') { | |
162 | /* | |
163 | * Flag all tests to be run. | |
164 | */ | |
165 | memset(T_tvec, 0xffff, sizeof(T_tvec)); | |
166 | } | |
167 | else if (c == 'b') { | |
168 | T_dir = isc_commandline_argument; | |
169 | } | |
170 | else if (c == 't') { | |
171 | tnum = atoi(isc_commandline_argument); | |
172 | if ((tnum > 0) && (tnum < T_MAXTESTS)) { | |
173 | if (first) { | |
174 | /* | |
175 | * Turn off effect of -a default | |
176 | * and allow multiple -t and -n | |
177 | * options. | |
178 | */ | |
179 | memset(T_tvec, 0, sizeof(T_tvec)); | |
180 | first = ISC_FALSE; | |
181 | } | |
182 | /* | |
183 | * Flag test tnum to be run. | |
184 | */ | |
185 | tnum -= 1; | |
186 | T_tvec[tnum / 8] |= (0x01 << (tnum % 8)); | |
187 | } | |
188 | } | |
189 | else if (c == 'c') { | |
190 | T_config = isc_commandline_argument; | |
191 | } | |
192 | else if (c == 'd') { | |
193 | T_debug = atoi(isc_commandline_argument); | |
194 | } | |
195 | else if (c == 'n') { | |
196 | pts = &T_testlist[0]; | |
197 | tnum = 0; | |
198 | while (pts->pfv != NULL) { | |
199 | if (! strcmp(pts->func_name, | |
200 | isc_commandline_argument)) { | |
201 | if (first) { | |
202 | memset(T_tvec, 0, | |
203 | sizeof(T_tvec)); | |
204 | first = ISC_FALSE; | |
205 | } | |
206 | T_tvec[tnum/8] |= (0x01 << (tnum%8)); | |
207 | break; | |
208 | } | |
209 | ++pts; | |
210 | ++tnum; | |
211 | } | |
212 | if (pts->pfv == NULL) { | |
213 | fprintf(stderr, "no such test %s\n", | |
214 | isc_commandline_argument); | |
215 | exit(1); | |
216 | } | |
217 | } | |
218 | else if (c == 'h') { | |
219 | printhelp(); | |
220 | exit(0); | |
221 | } | |
222 | else if (c == 'u') { | |
223 | printusage(); | |
224 | exit(0); | |
225 | } | |
226 | else if (c == 'x') { | |
227 | subprocs = 0; | |
228 | } | |
229 | else if (c == 'q') { | |
230 | T_timeout = atoi(isc_commandline_argument); | |
231 | } | |
232 | else if (c == ':') { | |
233 | fprintf(stderr, "Option -%c requires an argument\n", | |
234 | isc_commandline_option); | |
235 | exit(1); | |
236 | } | |
237 | else if (c == '?') { | |
238 | fprintf(stderr, "Unrecognized option -%c\n", | |
239 | isc_commandline_option); | |
240 | exit(1); | |
241 | } | |
242 | } | |
243 | ||
244 | /* | |
245 | * Set cwd. | |
246 | */ | |
247 | ||
248 | if (T_dir != NULL) | |
ae566556 | 249 | IGNORE_RET (chdir(T_dir)); |
6e999c3c SK |
250 | |
251 | /* | |
252 | * We don't want buffered output. | |
253 | */ | |
254 | ||
255 | (void)setbuf(stdout, NULL); | |
256 | (void)setbuf(stderr, NULL); | |
257 | ||
258 | /* | |
259 | * Setup signals. | |
260 | */ | |
261 | ||
262 | sa.sa_flags = 0; | |
263 | sigfillset(&sa.sa_mask); | |
264 | ||
265 | #ifdef SIGCHLD | |
266 | /* | |
267 | * This is mostly here for NetBSD's pthread implementation, until | |
268 | * people catch up to the latest unproven-pthread package. | |
269 | */ | |
270 | sa.sa_handler = SIG_DFL; | |
271 | (void)sigaction(SIGCHLD, &sa, NULL); | |
272 | #endif | |
273 | ||
274 | sa.sa_handler = t_sighandler; | |
275 | (void)sigaction(SIGINT, &sa, NULL); | |
276 | (void)sigaction(SIGALRM, &sa, NULL); | |
277 | ||
278 | /* | |
279 | * Output start stanza to journal. | |
280 | */ | |
281 | ||
282 | snprintf(T_buf, sizeof(T_buf), "%s:", argv[0]); | |
283 | len = strlen(T_buf); | |
284 | (void) t_getdate(T_buf + len, T_BIGBUF - len); | |
285 | t_putinfo("S", T_buf); | |
286 | ||
287 | /* | |
288 | * Setup the test environment using the config file. | |
289 | */ | |
290 | ||
291 | if (T_config == NULL) | |
292 | T_config = T_DEFAULT_CONFIG; | |
293 | ||
294 | t_initconf(T_config); | |
295 | if (T_debug) | |
296 | t_dumpconf(T_config); | |
297 | ||
298 | /* | |
299 | * Now invoke all the test cases. | |
300 | */ | |
301 | ||
302 | tnum = 0; | |
303 | pts = &T_testlist[0]; | |
304 | while (*pts->pfv != NULL) { | |
305 | if (T_tvec[tnum / 8] & (0x01 << (tnum % 8))) { | |
306 | if (subprocs) { | |
307 | T_pid = fork(); | |
308 | if (T_pid == 0) { | |
309 | (*pts->pfv)(); | |
310 | exit(0); | |
311 | } else if (T_pid > 0) { | |
312 | ||
313 | T_int = 0; | |
314 | sa.sa_handler = t_sighandler; | |
315 | (void)sigaction(SIGALRM, &sa, NULL); | |
316 | alarm(T_timeout); | |
317 | ||
318 | deadpid = (pid_t) -1; | |
319 | while (deadpid != T_pid) { | |
320 | deadpid = | |
321 | waitpid(T_pid, &status, 0); | |
322 | if (deadpid == T_pid) { | |
323 | if (WIFSIGNALED(status)) { | |
324 | if (WTERMSIG(status) == | |
325 | SIGTERM) | |
326 | t_info( | |
327 | "the test case timed out\n"); | |
328 | else | |
329 | t_info( | |
330 | "the test case caused exception %d\n", | |
331 | WTERMSIG(status)); | |
332 | t_result(T_UNRESOLVED); | |
333 | } | |
334 | } else if ((deadpid == -1) && | |
335 | (errno == EINTR) && | |
336 | T_int) { | |
337 | kill(T_pid, SIGTERM); | |
338 | T_int = 0; | |
339 | } | |
340 | else if ((deadpid == -1) && | |
341 | ((errno == ECHILD) || | |
342 | (errno == ESRCH))) | |
343 | break; | |
344 | } | |
345 | ||
346 | alarm(0); | |
347 | sa.sa_handler = SIG_IGN; | |
348 | (void)sigaction(SIGALRM, &sa, NULL); | |
349 | } else { | |
350 | t_info("fork failed, errno == %d\n", | |
351 | errno); | |
352 | t_result(T_UNRESOLVED); | |
353 | } | |
354 | } | |
355 | else { | |
356 | (*pts->pfv)(); | |
357 | } | |
358 | } | |
359 | ++pts; | |
360 | ++tnum; | |
361 | } | |
362 | ||
363 | snprintf(T_buf, sizeof(T_buf), "%s:", argv[0]); | |
364 | len = strlen(T_buf); | |
365 | (void) t_getdate(T_buf + len, T_BIGBUF - len); | |
366 | t_putinfo("E", T_buf); | |
367 | ||
368 | return(0); | |
369 | } | |
370 | ||
371 | void | |
372 | t_assert(const char *component, int anum, int class, const char *what, ...) { | |
373 | va_list args; | |
374 | ||
375 | (void)printf("T:%s:%d:%s\n", component, anum, class == T_REQUIRED ? | |
376 | "A" : "C"); | |
377 | ||
378 | /* | |
379 | * Format text to a buffer. | |
380 | */ | |
381 | va_start(args, what); | |
382 | (void)vsnprintf(T_buf, sizeof(T_buf), what, args); | |
383 | va_end(args); | |
384 | ||
385 | (void)t_putinfo("A", T_buf); | |
386 | (void)printf("\n"); | |
387 | } | |
388 | ||
389 | void | |
390 | t_info(const char *format, ...) { | |
391 | va_list args; | |
392 | ||
393 | va_start(args, format); | |
394 | (void) vsnprintf(T_buf, sizeof(T_buf), format, args); | |
395 | va_end(args); | |
396 | (void) t_putinfo("I", T_buf); | |
397 | } | |
398 | ||
399 | void | |
400 | t_result(int result) { | |
401 | const char *p; | |
402 | ||
403 | switch (result) { | |
404 | case T_PASS: | |
405 | p = "PASS"; | |
406 | break; | |
407 | case T_FAIL: | |
408 | p = "FAIL"; | |
409 | break; | |
410 | case T_UNRESOLVED: | |
411 | p = "UNRESOLVED"; | |
412 | break; | |
413 | case T_UNSUPPORTED: | |
414 | p = "UNSUPPORTED"; | |
415 | break; | |
416 | case T_UNTESTED: | |
417 | p = "UNTESTED"; | |
418 | break; | |
419 | case T_THREADONLY: | |
420 | p = "THREADONLY"; | |
421 | break; | |
422 | default: | |
423 | p = "UNKNOWN"; | |
424 | break; | |
425 | } | |
426 | printf("R:%s\n", p); | |
427 | } | |
428 | ||
429 | char * | |
430 | t_getenv(const char *name) { | |
431 | char *n; | |
432 | char **p; | |
433 | size_t len; | |
434 | ||
435 | n = NULL; | |
436 | if (name && *name) { | |
437 | ||
438 | p = &T_env[0]; | |
439 | len = strlen(name); | |
440 | ||
441 | while (*p != NULL) { | |
442 | if (strncmp(*p, name, len) == 0) { | |
443 | if ( *(*p + len) == '=') { | |
444 | n = *p + len + 1; | |
445 | break; | |
446 | } | |
447 | } | |
448 | ++p; | |
449 | } | |
450 | } | |
451 | return(n); | |
452 | } | |
453 | ||
454 | /* | |
455 | * | |
456 | * Read in the config file at path, initializing T_env. | |
457 | * | |
458 | * note: no format checking for now ... | |
459 | * | |
460 | */ | |
461 | ||
462 | static int | |
463 | t_initconf(const char *path) { | |
464 | ||
465 | int n; | |
466 | int rval; | |
467 | char **p; | |
468 | FILE *fp; | |
469 | ||
470 | rval = -1; | |
471 | ||
472 | fp = fopen(path, "r"); | |
473 | if (fp != NULL) { | |
474 | n = 0; | |
475 | p = &T_env[0]; | |
476 | while (n < T_MAXENV) { | |
477 | *p = t_fgetbs(fp); | |
478 | if (*p == NULL) | |
479 | break; | |
480 | if ((**p == '#') || (strchr(*p, '=') == NULL)) { | |
481 | /* | |
482 | * Skip comments and other junk. | |
483 | */ | |
484 | (void)free(*p); | |
485 | continue; | |
486 | } | |
487 | ++p; ++n; | |
488 | } | |
489 | (void)fclose(fp); | |
490 | rval = 0; | |
491 | } | |
492 | ||
493 | return (rval); | |
494 | } | |
495 | ||
496 | /* | |
497 | * | |
498 | * Dump T_env to stdout. | |
499 | * | |
500 | */ | |
501 | ||
502 | static int | |
503 | t_dumpconf(const char *path) { | |
504 | int rval; | |
505 | char **p; | |
506 | FILE *fp; | |
507 | ||
508 | rval = -1; | |
509 | fp = fopen(path, "r"); | |
510 | if (fp != NULL) { | |
511 | p = &T_env[0]; | |
512 | while (*p != NULL) { | |
513 | printf("C:%s\n", *p); | |
514 | ++p; | |
515 | } | |
516 | (void) fclose(fp); | |
517 | rval = 0; | |
518 | } | |
519 | return(rval); | |
520 | } | |
521 | ||
522 | /* | |
523 | * | |
524 | * Read a newline or EOF terminated string from fp. | |
525 | * On success: | |
526 | * return a malloc'd buf containing the string with | |
527 | * the newline converted to a '\0'. | |
528 | * On error: | |
529 | * return NULL. | |
530 | * | |
531 | * Caller is responsible for freeing buf. | |
532 | * | |
533 | */ | |
534 | ||
535 | char * | |
536 | t_fgetbs(FILE *fp) { | |
537 | int c; | |
538 | size_t n; | |
539 | size_t size; | |
540 | char *buf; | |
541 | char *p; | |
542 | ||
543 | n = 0; | |
544 | size = T_BUFSIZ; | |
545 | buf = (char *) malloc(T_BUFSIZ * sizeof(char)); | |
546 | ||
547 | if (buf != NULL) { | |
548 | p = buf; | |
549 | while ((c = fgetc(fp)) != EOF) { | |
550 | ||
551 | if (c == '\n') | |
552 | break; | |
553 | ||
554 | *p++ = c; | |
555 | ++n; | |
556 | if ( n >= size ) { | |
557 | size += T_BUFSIZ; | |
558 | buf = (char *)realloc(buf, | |
559 | size * sizeof(char)); | |
560 | if (buf == NULL) | |
561 | break; | |
562 | p = buf + n; | |
563 | } | |
564 | } | |
565 | *p = '\0'; | |
566 | if (c == EOF && n == 0U) { | |
567 | free(buf); | |
568 | return (NULL); | |
569 | } | |
570 | return (buf); | |
571 | } else { | |
572 | fprintf(stderr, "malloc failed %d", errno); | |
573 | return(NULL); | |
574 | } | |
575 | } | |
576 | ||
577 | /* | |
578 | * | |
579 | * Put info to log, using key. | |
580 | * For now, just dump it out. | |
581 | * Later format into pretty lines. | |
582 | * | |
583 | */ | |
584 | ||
585 | static int | |
586 | t_putinfo(const char *key, const char *info) { | |
587 | int rval; | |
588 | ||
589 | /* | |
590 | * For now. | |
591 | */ | |
592 | rval = printf("%s:%s", key, info); | |
593 | return(rval); | |
594 | } | |
595 | ||
596 | static char * | |
597 | t_getdate(char *buf, size_t buflen) { | |
598 | size_t n; | |
599 | time_t t; | |
600 | struct tm *p; | |
601 | ||
602 | t = time(NULL); | |
603 | p = localtime(&t); | |
604 | n = strftime(buf, buflen - 1, "%A %d %B %H:%M:%S %Y\n", p); | |
605 | return(n != 0U ? buf : NULL); | |
606 | } | |
607 | ||
608 | /* | |
609 | * Some generally used utilities. | |
610 | */ | |
611 | #ifdef DNS_SUPPORT | |
612 | struct dns_errormap { | |
613 | isc_result_t result; | |
614 | const char *text; | |
615 | } dns_errormap[] = { | |
616 | { ISC_R_SUCCESS, "ISC_R_SUCCESS" }, | |
617 | { ISC_R_EXISTS, "ISC_R_EXISTS" }, | |
618 | { ISC_R_NOTFOUND, "ISC_R_NOTFOUND" }, | |
619 | { ISC_R_NOSPACE, "ISC_R_NOSPACE" }, | |
620 | { ISC_R_UNEXPECTED, "ISC_R_UNEXPECTED" }, | |
621 | { ISC_R_UNEXPECTEDEND, "ISC_R_UNEXPECTEDEND" }, | |
622 | { ISC_R_RANGE, "ISC_R_RANGE" }, | |
623 | { DNS_R_LABELTOOLONG, "DNS_R_LABELTOOLONG" }, | |
624 | { DNS_R_BADESCAPE, "DNS_R_BADESCAPE" }, | |
625 | /* { DNS_R_BADBITSTRING, "DNS_R_BADBITSTRING" }, */ | |
626 | /* { DNS_R_BITSTRINGTOOLONG, "DNS_R_BITSTRINGTOOLONG"}, */ | |
627 | { DNS_R_EMPTYLABEL, "DNS_R_EMPTYLABEL" }, | |
628 | { DNS_R_BADDOTTEDQUAD, "DNS_R_BADDOTTEDQUAD" }, | |
629 | { DNS_R_UNKNOWN, "DNS_R_UNKNOWN" }, | |
630 | { DNS_R_BADLABELTYPE, "DNS_R_BADLABELTYPE" }, | |
631 | { DNS_R_BADPOINTER, "DNS_R_BADPOINTER" }, | |
632 | { DNS_R_TOOMANYHOPS, "DNS_R_TOOMANYHOPS" }, | |
633 | { DNS_R_DISALLOWED, "DNS_R_DISALLOWED" }, | |
634 | { DNS_R_EXTRATOKEN, "DNS_R_EXTRATOKEN" }, | |
635 | { DNS_R_EXTRADATA, "DNS_R_EXTRADATA" }, | |
636 | { DNS_R_TEXTTOOLONG, "DNS_R_TEXTTOOLONG" }, | |
637 | { DNS_R_SYNTAX, "DNS_R_SYNTAX" }, | |
638 | { DNS_R_BADCKSUM, "DNS_R_BADCKSUM" }, | |
639 | { DNS_R_BADAAAA, "DNS_R_BADAAAA" }, | |
640 | { DNS_R_NOOWNER, "DNS_R_NOOWNER" }, | |
641 | { DNS_R_NOTTL, "DNS_R_NOTTL" }, | |
642 | { DNS_R_BADCLASS, "DNS_R_BADCLASS" }, | |
643 | { DNS_R_PARTIALMATCH, "DNS_R_PARTIALMATCH" }, | |
644 | { DNS_R_NEWORIGIN, "DNS_R_NEWORIGIN" }, | |
645 | { DNS_R_UNCHANGED, "DNS_R_UNCHANGED" }, | |
646 | { DNS_R_BADTTL, "DNS_R_BADTTL" }, | |
647 | { DNS_R_NOREDATA, "DNS_R_NOREDATA" }, | |
648 | { DNS_R_CONTINUE, "DNS_R_CONTINUE" }, | |
649 | { DNS_R_DELEGATION, "DNS_R_DELEGATION" }, | |
650 | { DNS_R_GLUE, "DNS_R_GLUE" }, | |
651 | { DNS_R_DNAME, "DNS_R_DNAME" }, | |
652 | { DNS_R_CNAME, "DNS_R_CNAME" }, | |
653 | { DNS_R_NXDOMAIN, "DNS_R_NXDOMAIN" }, | |
654 | { DNS_R_NXRRSET, "DNS_R_NXRRSET" }, | |
655 | { DNS_R_BADDB, "DNS_R_BADDB" }, | |
656 | { DNS_R_ZONECUT, "DNS_R_ZONECUT" }, | |
657 | { DNS_R_NOTZONETOP, "DNS_R_NOTZONETOP" }, | |
658 | { DNS_R_SEENINCLUDE, "DNS_R_SEENINCLUDE" }, | |
659 | { DNS_R_SINGLETON, "DNS_R_SINGLETON" }, | |
660 | { (isc_result_t)0, NULL } | |
661 | }; | |
662 | ||
663 | isc_result_t | |
664 | t_dns_result_fromtext(char *name) { | |
665 | ||
666 | isc_result_t result; | |
667 | struct dns_errormap *pmap; | |
668 | ||
669 | result = ISC_R_UNEXPECTED; | |
670 | ||
671 | pmap = dns_errormap; | |
672 | while (pmap->text != NULL) { | |
673 | if (strcmp(name, pmap->text) == 0) | |
674 | break; | |
675 | ++pmap; | |
676 | } | |
677 | ||
678 | if (pmap->text != NULL) | |
679 | result = pmap->result; | |
680 | ||
681 | return (result); | |
682 | } | |
683 | ||
684 | struct dc_method_map { | |
685 | unsigned int dc_method; | |
686 | const char *text; | |
687 | } dc_method_map[] = { | |
688 | ||
689 | { DNS_COMPRESS_NONE, "DNS_COMPRESS_NONE" }, | |
690 | { DNS_COMPRESS_GLOBAL14, "DNS_COMPRESS_GLOBAL14" }, | |
691 | { DNS_COMPRESS_ALL, "DNS_COMPRESS_ALL" }, | |
692 | { 0, NULL } | |
693 | }; | |
694 | ||
695 | unsigned int | |
696 | t_dc_method_fromtext(char *name) { | |
697 | unsigned int dc_method; | |
698 | struct dc_method_map *pmap; | |
699 | ||
700 | dc_method = DNS_COMPRESS_NONE; | |
701 | ||
702 | pmap = dc_method_map; | |
703 | while (pmap->text != NULL) { | |
704 | if (strcmp(name, pmap->text) == 0) | |
705 | break; | |
706 | ++pmap; | |
707 | } | |
708 | ||
709 | if (pmap->text != NULL) | |
710 | dc_method = pmap->dc_method; | |
711 | ||
712 | return(dc_method); | |
713 | } | |
714 | #endif /* DNS_SUPPORT */ | |
715 | ||
716 | int | |
717 | t_bustline(char *line, char **toks) { | |
718 | int cnt; | |
719 | char *p; | |
720 | ||
721 | cnt = 0; | |
722 | if (line && *line) { | |
723 | while ((p = strtok(line, "\t")) && (cnt < T_MAXTOKS)) { | |
724 | *toks++ = p; | |
725 | line = NULL; | |
726 | ++cnt; | |
727 | } | |
728 | } | |
729 | return(cnt); | |
730 | } | |
731 | ||
732 | static void | |
733 | printhelp(void) { | |
734 | int cnt; | |
735 | testspec_t *pts; | |
736 | ||
737 | cnt = 1; | |
738 | pts = &T_testlist[0]; | |
739 | ||
740 | printf("Available tests:\n"); | |
741 | while (pts->func_name) { | |
742 | printf("\t%d\t%s\n", cnt, pts->func_name); | |
743 | ++pts; | |
744 | ++cnt; | |
745 | } | |
746 | } | |
747 | ||
748 | static void | |
749 | printusage(void) { | |
750 | printf("Usage:\n%s\n", Usage); | |
751 | } | |
752 | ||
753 | int | |
754 | t_eval(const char *filename, int (*func)(char **), int nargs) { | |
755 | FILE *fp; | |
756 | char *p; | |
757 | int line; | |
758 | int cnt; | |
759 | int result; | |
760 | int nfails; | |
761 | int nprobs; | |
762 | int npass; | |
763 | char *tokens[T_MAXTOKS + 1]; | |
764 | ||
765 | npass = 0; | |
766 | nfails = 0; | |
767 | nprobs = 0; | |
768 | ||
769 | fp = fopen(filename, "r"); | |
770 | if (fp != NULL) { | |
771 | line = 0; | |
772 | while ((p = t_fgetbs(fp)) != NULL) { | |
773 | ||
774 | ++line; | |
775 | ||
776 | /* | |
777 | * Skip comment lines. | |
778 | */ | |
779 | if ((isspace((unsigned char)*p)) || (*p == '#')) { | |
780 | (void)free(p); | |
781 | continue; | |
782 | } | |
783 | ||
784 | cnt = t_bustline(p, tokens); | |
785 | if (cnt == nargs) { | |
786 | result = func(tokens); | |
787 | switch (result) { | |
788 | case T_PASS: | |
789 | ++npass; | |
790 | break; | |
791 | case T_FAIL: | |
792 | ++nfails; | |
793 | break; | |
794 | case T_UNTESTED: | |
795 | break; | |
796 | default: | |
797 | ++nprobs; | |
798 | break; | |
799 | } | |
800 | } else { | |
801 | t_info("bad format in %s at line %d\n", | |
802 | filename, line); | |
803 | ++nprobs; | |
804 | } | |
805 | ||
806 | (void)free(p); | |
807 | } | |
808 | (void)fclose(fp); | |
809 | } else { | |
810 | t_info("Missing datafile %s\n", filename); | |
811 | ++nprobs; | |
812 | } | |
813 | ||
814 | result = T_UNRESOLVED; | |
815 | ||
816 | if (nfails == 0 && nprobs == 0 && npass > 0) | |
817 | result = T_PASS; | |
818 | else if (nfails > 0) | |
819 | result = T_FAIL; | |
820 | else if (npass == 0) | |
821 | result = T_UNTESTED; | |
822 | ||
823 | return (result); | |
824 | } |