Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / bsd / bind / dist / lib / tests / t_api.c
bloba5bdaa50a08c6aaa93b24634b8f0d1747af178b8
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: t_api.c,v 1.65 2009/03/02 23:47:43 tbox Exp */
22 /*! \file */
24 #include <config.h>
26 #include <ctype.h>
27 #include <errno.h>
28 #include <limits.h>
29 #include <signal.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <time.h>
34 #include <unistd.h>
36 #include <sys/wait.h>
38 #include <isc/boolean.h>
39 #include <isc/commandline.h>
40 #include <isc/print.h>
41 #include <isc/string.h>
42 #include <isc/mem.h>
44 #include <dns/compress.h>
45 #include <dns/result.h>
47 #include "include/tests/t_api.h"
49 static const char *Usage =
50 "\t-a : run all tests\n"
51 "\t-b <dir> : chdir to dir before running tests"
52 "\t-c <config_file> : use specified config file\n"
53 "\t-d <debug_level> : set debug level to debug_level\n"
54 "\t-h : print test info\n"
55 "\t-u : print usage info\n"
56 "\t-n <test_name> : run specified test name\n"
57 "\t-t <test_number> : run specified test number\n"
58 "\t-x : don't execute tests in a subproc\n"
59 "\t-q <timeout> : use 'timeout' as the timeout value\n";
60 /*!<
61 * -a --> run all tests
62 * -b dir --> chdir to dir before running tests
63 * -c config --> use config file 'config'
64 * -d --> turn on api debugging
65 * -h --> print out available test names
66 * -u --> print usage info
67 * -n name --> run test named name
68 * -tn --> run test n
69 * -x --> don't execute testcases in a subproc
70 * -q timeout --> use 'timeout' as the timeout value
73 #define T_MAXTESTS 256 /*% must be 0 mod 8 */
74 #define T_MAXENV 256
75 #define T_DEFAULT_CONFIG "t_config"
76 #define T_BUFSIZ 256
77 #define T_BIGBUF 4096
79 #define T_TCTOUT 60
81 int T_debug;
82 int T_timeout;
83 pid_t T_pid;
84 static const char * T_config;
85 static char T_tvec[T_MAXTESTS / 8];
86 static char * T_env[T_MAXENV + 1];
87 static char T_buf[T_BIGBUF];
88 static char * T_dir;
90 static int
91 t_initconf(const char *path);
93 static int
94 t_dumpconf(const char *path);
96 static int
97 t_putinfo(const char *key, const char *info);
99 static char *
100 t_getdate(char *buf, size_t buflen);
102 static void
103 printhelp(void);
105 static void
106 printusage(void);
108 static int T_int;
110 static void
111 t_sighandler(int sig) {
112 T_int = sig;
116 main(int argc, char **argv) {
117 int c;
118 int tnum;
119 int subprocs;
120 pid_t deadpid;
121 int status;
122 int len;
123 isc_boolean_t first;
124 testspec_t *pts;
125 struct sigaction sa;
127 isc_mem_debugging = ISC_MEM_DEBUGRECORD;
128 first = ISC_TRUE;
129 subprocs = 1;
130 T_timeout = T_TCTOUT;
133 * -a option is now default.
135 memset(T_tvec, 0xff, sizeof(T_tvec));
138 * Parse args.
140 while ((c = isc_commandline_parse(argc, argv, ":at:c:d:n:huxq:b:"))
141 != -1) {
142 if (c == 'a') {
144 * Flag all tests to be run.
146 memset(T_tvec, 0xff, sizeof(T_tvec));
148 else if (c == 'b') {
149 T_dir = isc_commandline_argument;
151 else if (c == 't') {
152 tnum = atoi(isc_commandline_argument);
153 if ((tnum > 0) && (tnum < T_MAXTESTS)) {
154 if (first) {
156 * Turn off effect of -a default
157 * and allow multiple -t and -n
158 * options.
160 memset(T_tvec, 0, sizeof(T_tvec));
161 first = ISC_FALSE;
164 * Flag test tnum to be run.
166 tnum -= 1;
167 T_tvec[tnum / 8] |= (0x01 << (tnum % 8));
170 else if (c == 'c') {
171 T_config = isc_commandline_argument;
173 else if (c == 'd') {
174 T_debug = atoi(isc_commandline_argument);
176 else if (c == 'n') {
177 pts = &T_testlist[0];
178 tnum = 0;
179 while (pts->pfv != NULL) {
180 if (! strcmp(pts->func_name,
181 isc_commandline_argument)) {
182 if (first) {
183 memset(T_tvec, 0,
184 sizeof(T_tvec));
185 first = ISC_FALSE;
187 T_tvec[tnum/8] |= (0x01 << (tnum%8));
188 break;
190 ++pts;
191 ++tnum;
193 if (pts->pfv == NULL) {
194 fprintf(stderr, "no such test %s\n",
195 isc_commandline_argument);
196 exit(1);
199 else if (c == 'h') {
200 printhelp();
201 exit(0);
203 else if (c == 'u') {
204 printusage();
205 exit(0);
207 else if (c == 'x') {
208 subprocs = 0;
210 else if (c == 'q') {
211 T_timeout = atoi(isc_commandline_argument);
213 else if (c == ':') {
214 fprintf(stderr, "Option -%c requires an argument\n",
215 isc_commandline_option);
216 exit(1);
218 else if (c == '?') {
219 fprintf(stderr, "Unrecognized option -%c\n",
220 isc_commandline_option);
221 exit(1);
226 * Set cwd.
229 if (T_dir != NULL && chdir(T_dir) != 0) {
230 fprintf(stderr, "chdir %s failed\n", T_dir);
231 exit(1);
235 * We don't want buffered output.
238 (void)setbuf(stdout, NULL);
239 (void)setbuf(stderr, NULL);
242 * Setup signals.
245 sa.sa_flags = 0;
246 sigfillset(&sa.sa_mask);
248 #ifdef SIGCHLD
250 * This is mostly here for NetBSD's pthread implementation, until
251 * people catch up to the latest unproven-pthread package.
253 sa.sa_handler = SIG_DFL;
254 (void)sigaction(SIGCHLD, &sa, NULL);
255 #endif
257 sa.sa_handler = t_sighandler;
258 (void)sigaction(SIGINT, &sa, NULL);
259 (void)sigaction(SIGALRM, &sa, NULL);
262 * Output start stanza to journal.
265 snprintf(T_buf, sizeof(T_buf), "%s:", argv[0]);
266 len = strlen(T_buf);
267 (void) t_getdate(T_buf + len, T_BIGBUF - len);
268 t_putinfo("S", T_buf);
271 * Setup the test environment using the config file.
274 if (T_config == NULL)
275 T_config = T_DEFAULT_CONFIG;
277 t_initconf(T_config);
278 if (T_debug)
279 t_dumpconf(T_config);
282 * Now invoke all the test cases.
285 tnum = 0;
286 pts = &T_testlist[0];
287 while (*pts->pfv != NULL) {
288 if (T_tvec[tnum / 8] & (0x01 << (tnum % 8))) {
289 if (subprocs) {
290 T_pid = fork();
291 if (T_pid == 0) {
292 (*pts->pfv)();
293 exit(0);
294 } else if (T_pid > 0) {
296 T_int = 0;
297 sa.sa_handler = t_sighandler;
298 (void)sigaction(SIGALRM, &sa, NULL);
299 alarm(T_timeout);
301 deadpid = (pid_t) -1;
302 while (deadpid != T_pid) {
303 deadpid =
304 waitpid(T_pid, &status, 0);
305 if (deadpid == T_pid) {
306 if (WIFSIGNALED(status)) {
307 if (WTERMSIG(status) ==
308 SIGTERM)
309 t_info(
310 "the test case timed out\n");
311 else
312 t_info(
313 "the test case caused exception %d\n",
314 WTERMSIG(status));
315 t_result(T_UNRESOLVED);
317 } else if ((deadpid == -1) &&
318 (errno == EINTR) &&
319 T_int) {
320 kill(T_pid, SIGTERM);
321 T_int = 0;
323 else if ((deadpid == -1) &&
324 ((errno == ECHILD) ||
325 (errno == ESRCH)))
326 break;
329 alarm(0);
330 sa.sa_handler = SIG_IGN;
331 (void)sigaction(SIGALRM, &sa, NULL);
332 } else {
333 t_info("fork failed, errno == %d\n",
334 errno);
335 t_result(T_UNRESOLVED);
338 else {
339 (*pts->pfv)();
342 ++pts;
343 ++tnum;
346 snprintf(T_buf, sizeof(T_buf), "%s:", argv[0]);
347 len = strlen(T_buf);
348 (void) t_getdate(T_buf + len, T_BIGBUF - len);
349 t_putinfo("E", T_buf);
351 return(0);
354 void
355 t_assert(const char *component, int anum, int class, const char *what, ...) {
356 va_list args;
358 (void)printf("T:%s:%d:%s\n", component, anum, class == T_REQUIRED ?
359 "A" : "C");
362 * Format text to a buffer.
364 va_start(args, what);
365 (void)vsnprintf(T_buf, sizeof(T_buf), what, args);
366 va_end(args);
368 (void)t_putinfo("A", T_buf);
369 (void)printf("\n");
372 void
373 t_info(const char *format, ...) {
374 va_list args;
376 va_start(args, format);
377 (void) vsnprintf(T_buf, sizeof(T_buf), format, args);
378 va_end(args);
379 (void) t_putinfo("I", T_buf);
382 void
383 t_result(int result) {
384 const char *p;
386 switch (result) {
387 case T_PASS:
388 p = "PASS";
389 break;
390 case T_FAIL:
391 p = "FAIL";
392 break;
393 case T_UNRESOLVED:
394 p = "UNRESOLVED";
395 break;
396 case T_UNSUPPORTED:
397 p = "UNSUPPORTED";
398 break;
399 case T_UNTESTED:
400 p = "UNTESTED";
401 break;
402 case T_THREADONLY:
403 p = "THREADONLY";
404 break;
405 default:
406 p = "UNKNOWN";
407 break;
409 printf("R:%s\n", p);
412 char *
413 t_getenv(const char *name) {
414 char *n;
415 char **p;
416 size_t len;
418 n = NULL;
419 if (name && *name) {
421 p = &T_env[0];
422 len = strlen(name);
424 while (*p != NULL) {
425 if (strncmp(*p, name, len) == 0) {
426 if ( *(*p + len) == '=') {
427 n = *p + len + 1;
428 break;
431 ++p;
434 return(n);
439 * Read in the config file at path, initializing T_env.
441 * note: no format checking for now ...
445 static int
446 t_initconf(const char *path) {
448 int n;
449 int rval;
450 char **p;
451 FILE *fp;
453 rval = -1;
455 fp = fopen(path, "r");
456 if (fp != NULL) {
457 n = 0;
458 p = &T_env[0];
459 while (n < T_MAXENV) {
460 *p = t_fgetbs(fp);
461 if (*p == NULL)
462 break;
463 if ((**p == '#') || (strchr(*p, '=') == NULL)) {
465 * Skip comments and other junk.
467 (void)free(*p);
468 continue;
470 ++p; ++n;
472 (void)fclose(fp);
473 rval = 0;
476 return (rval);
481 * Dump T_env to stdout.
485 static int
486 t_dumpconf(const char *path) {
487 int rval;
488 char **p;
489 FILE *fp;
491 rval = -1;
492 fp = fopen(path, "r");
493 if (fp != NULL) {
494 p = &T_env[0];
495 while (*p != NULL) {
496 printf("C:%s\n", *p);
497 ++p;
499 (void) fclose(fp);
500 rval = 0;
502 return(rval);
507 * Read a newline or EOF terminated string from fp.
508 * On success:
509 * return a malloc'd buf containing the string with
510 * the newline converted to a '\0'.
511 * On error:
512 * return NULL.
514 * Caller is responsible for freeing buf.
518 char *
519 t_fgetbs(FILE *fp) {
520 int c;
521 size_t n;
522 size_t size;
523 char *buf;
524 char *p;
526 n = 0;
527 size = T_BUFSIZ;
528 buf = (char *) malloc(T_BUFSIZ * sizeof(char));
530 if (buf != NULL) {
531 p = buf;
532 while ((c = fgetc(fp)) != EOF) {
534 if (c == '\n')
535 break;
537 *p++ = c;
538 ++n;
539 if ( n >= size ) {
540 size += T_BUFSIZ;
541 buf = (char *)realloc(buf,
542 size * sizeof(char));
543 if (buf == NULL)
544 break;
545 p = buf + n;
548 *p = '\0';
549 if (c == EOF && n == 0U) {
550 free(buf);
551 return (NULL);
553 return (buf);
554 } else {
555 fprintf(stderr, "malloc failed %d", errno);
556 return(NULL);
562 * Put info to log, using key.
563 * For now, just dump it out.
564 * Later format into pretty lines.
568 static int
569 t_putinfo(const char *key, const char *info) {
570 int rval;
573 * For now.
575 rval = printf("%s:%s", key, info);
576 return(rval);
579 static char *
580 t_getdate(char *buf, size_t buflen) {
581 size_t n;
582 time_t t;
583 struct tm *p;
585 t = time(NULL);
586 p = localtime(&t);
587 n = strftime(buf, buflen - 1, "%A %d %B %H:%M:%S %Y\n", p);
588 return(n != 0U ? buf : NULL);
592 * Some generally used utilities.
594 struct dns_errormap {
595 isc_result_t result;
596 const char *text;
597 } dns_errormap[] = {
598 { ISC_R_SUCCESS, "ISC_R_SUCCESS" },
599 { ISC_R_EXISTS, "ISC_R_EXISTS" },
600 { ISC_R_NOTFOUND, "ISC_R_NOTFOUND" },
601 { ISC_R_NOSPACE, "ISC_R_NOSPACE" },
602 { ISC_R_UNEXPECTED, "ISC_R_UNEXPECTED" },
603 { ISC_R_UNEXPECTEDEND, "ISC_R_UNEXPECTEDEND" },
604 { ISC_R_RANGE, "ISC_R_RANGE" },
605 { DNS_R_LABELTOOLONG, "DNS_R_LABELTOOLONG" },
606 { DNS_R_BADESCAPE, "DNS_R_BADESCAPE" },
607 /* { DNS_R_BADBITSTRING, "DNS_R_BADBITSTRING" }, */
608 /* { DNS_R_BITSTRINGTOOLONG, "DNS_R_BITSTRINGTOOLONG"}, */
609 { DNS_R_EMPTYLABEL, "DNS_R_EMPTYLABEL" },
610 { DNS_R_BADDOTTEDQUAD, "DNS_R_BADDOTTEDQUAD" },
611 { DNS_R_UNKNOWN, "DNS_R_UNKNOWN" },
612 { DNS_R_BADLABELTYPE, "DNS_R_BADLABELTYPE" },
613 { DNS_R_BADPOINTER, "DNS_R_BADPOINTER" },
614 { DNS_R_TOOMANYHOPS, "DNS_R_TOOMANYHOPS" },
615 { DNS_R_DISALLOWED, "DNS_R_DISALLOWED" },
616 { DNS_R_EXTRATOKEN, "DNS_R_EXTRATOKEN" },
617 { DNS_R_EXTRADATA, "DNS_R_EXTRADATA" },
618 { DNS_R_TEXTTOOLONG, "DNS_R_TEXTTOOLONG" },
619 { DNS_R_SYNTAX, "DNS_R_SYNTAX" },
620 { DNS_R_BADCKSUM, "DNS_R_BADCKSUM" },
621 { DNS_R_BADAAAA, "DNS_R_BADAAAA" },
622 { DNS_R_NOOWNER, "DNS_R_NOOWNER" },
623 { DNS_R_NOTTL, "DNS_R_NOTTL" },
624 { DNS_R_BADCLASS, "DNS_R_BADCLASS" },
625 { DNS_R_PARTIALMATCH, "DNS_R_PARTIALMATCH" },
626 { DNS_R_NEWORIGIN, "DNS_R_NEWORIGIN" },
627 { DNS_R_UNCHANGED, "DNS_R_UNCHANGED" },
628 { DNS_R_BADTTL, "DNS_R_BADTTL" },
629 { DNS_R_NOREDATA, "DNS_R_NOREDATA" },
630 { DNS_R_CONTINUE, "DNS_R_CONTINUE" },
631 { DNS_R_DELEGATION, "DNS_R_DELEGATION" },
632 { DNS_R_GLUE, "DNS_R_GLUE" },
633 { DNS_R_DNAME, "DNS_R_DNAME" },
634 { DNS_R_CNAME, "DNS_R_CNAME" },
635 { DNS_R_NXDOMAIN, "DNS_R_NXDOMAIN" },
636 { DNS_R_NXRRSET, "DNS_R_NXRRSET" },
637 { DNS_R_BADDB, "DNS_R_BADDB" },
638 { DNS_R_ZONECUT, "DNS_R_ZONECUT" },
639 { DNS_R_NOTZONETOP, "DNS_R_NOTZONETOP" },
640 { DNS_R_SEENINCLUDE, "DNS_R_SEENINCLUDE" },
641 { DNS_R_SINGLETON, "DNS_R_SINGLETON" },
642 { (isc_result_t)0, NULL }
645 isc_result_t
646 t_dns_result_fromtext(char *name) {
648 isc_result_t result;
649 struct dns_errormap *pmap;
651 result = ISC_R_UNEXPECTED;
653 pmap = dns_errormap;
654 while (pmap->text != NULL) {
655 if (strcmp(name, pmap->text) == 0)
656 break;
657 ++pmap;
660 if (pmap->text != NULL)
661 result = pmap->result;
663 return (result);
666 struct dc_method_map {
667 unsigned int dc_method;
668 const char *text;
669 } dc_method_map[] = {
671 { DNS_COMPRESS_NONE, "DNS_COMPRESS_NONE" },
672 { DNS_COMPRESS_GLOBAL14, "DNS_COMPRESS_GLOBAL14" },
673 { DNS_COMPRESS_ALL, "DNS_COMPRESS_ALL" },
674 { 0, NULL }
677 unsigned int
678 t_dc_method_fromtext(char *name) {
679 unsigned int dc_method;
680 struct dc_method_map *pmap;
682 dc_method = DNS_COMPRESS_NONE;
684 pmap = dc_method_map;
685 while (pmap->text != NULL) {
686 if (strcmp(name, pmap->text) == 0)
687 break;
688 ++pmap;
691 if (pmap->text != NULL)
692 dc_method = pmap->dc_method;
694 return(dc_method);
698 t_bustline(char *line, char **toks) {
699 int cnt;
700 char *p;
702 cnt = 0;
703 if (line && *line) {
704 while ((p = strtok(line, "\t")) && (cnt < T_MAXTOKS)) {
705 *toks++ = p;
706 line = NULL;
707 ++cnt;
710 return(cnt);
713 static void
714 printhelp(void) {
715 int cnt;
716 testspec_t *pts;
718 cnt = 1;
719 pts = &T_testlist[0];
721 printf("Available tests:\n");
722 while (pts->func_name) {
723 printf("\t%d\t%s\n", cnt, pts->func_name);
724 ++pts;
725 ++cnt;
729 static void
730 printusage(void) {
731 printf("Usage:\n%s\n", Usage);
735 t_eval(const char *filename, int (*func)(char **), int nargs) {
736 FILE *fp;
737 char *p;
738 int line;
739 int cnt;
740 int result;
741 int nfails;
742 int nprobs;
743 int npass;
744 char *tokens[T_MAXTOKS + 1];
746 npass = 0;
747 nfails = 0;
748 nprobs = 0;
750 fp = fopen(filename, "r");
751 if (fp != NULL) {
752 line = 0;
753 while ((p = t_fgetbs(fp)) != NULL) {
755 ++line;
758 * Skip comment lines.
760 if ((isspace((unsigned char)*p)) || (*p == '#')) {
761 (void)free(p);
762 continue;
765 cnt = t_bustline(p, tokens);
766 if (cnt == nargs) {
767 result = func(tokens);
768 switch (result) {
769 case T_PASS:
770 ++npass;
771 break;
772 case T_FAIL:
773 ++nfails;
774 break;
775 case T_UNTESTED:
776 break;
777 default:
778 ++nprobs;
779 break;
781 } else {
782 t_info("bad format in %s at line %d\n",
783 filename, line);
784 ++nprobs;
787 (void)free(p);
789 (void)fclose(fp);
790 } else {
791 t_info("Missing datafile %s\n", filename);
792 ++nprobs;
795 result = T_UNRESOLVED;
797 if (nfails == 0 && nprobs == 0 && npass > 0)
798 result = T_PASS;
799 else if (nfails > 0)
800 result = T_FAIL;
801 else if (npass == 0)
802 result = T_UNTESTED;
804 return (result);