etc/protocols - sync with NetBSD-8
[minix.git] / external / bsd / bind / dist / lib / tests / t_api.c
blobf1a824d18c95076b1670fba0987ce3e053aa40d1
1 /* $NetBSD: t_api.c,v 1.7 2014/12/10 04:38:02 christos Exp $ */
3 /*
4 * Copyright (C) 2004, 2005, 2007-2010, 2013, 2014 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.68 2010/12/21 04:20:23 marka 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 #ifndef WIN32
37 #include <sys/wait.h>
38 #else
39 #include <direct.h>
40 #endif
42 #include <isc/boolean.h>
43 #include <isc/commandline.h>
44 #include <isc/print.h>
45 #include <isc/string.h>
46 #include <isc/mem.h>
48 #include <dns/compress.h>
49 #include <dns/result.h>
51 #include "include/tests/t_api.h"
53 static const char *Usage =
54 "\t-a : run all tests\n"
55 "\t-b <dir> : chdir to dir before running tests"
56 "\t-c <config_file> : use specified config file\n"
57 "\t-d <debug_level> : set debug level to debug_level\n"
58 "\t-h : print test info\n"
59 "\t-u : print usage info\n"
60 "\t-n <test_name> : run specified test name\n"
61 "\t-t <test_number> : run specified test number\n"
62 "\t-x : don't execute tests in a subproc\n"
63 "\t-q <timeout> : use 'timeout' as the timeout value\n";
64 /*!<
65 * -a --> run all tests
66 * -b dir --> chdir to dir before running tests
67 * -c config --> use config file 'config'
68 * -d --> turn on api debugging
69 * -h --> print out available test names
70 * -u --> print usage info
71 * -n name --> run test named name
72 * -tn --> run test n
73 * -x --> don't execute testcases in a subproc
74 * -q timeout --> use 'timeout' as the timeout value
77 #define T_MAXTESTS 256 /*% must be 0 mod 8 */
78 #define T_MAXENV 256
79 #define T_DEFAULT_CONFIG "t_config"
80 #define T_BUFSIZ 256
81 #define T_BIGBUF 4096
83 #define T_TCTOUT 60
85 int T_debug;
86 int T_timeout;
87 pid_t T_pid;
88 static const char * T_config;
89 static char T_tvec[T_MAXTESTS / 8];
90 static char * T_env[T_MAXENV + 1];
91 static char T_buf[T_BIGBUF];
92 static char * T_dir;
93 #ifdef WIN32
94 static testspec_t T_testlist[T_MAXTESTS];
95 #endif
97 static int
98 t_initconf(const char *path);
100 static int
101 t_dumpconf(const char *path);
103 static int
104 t_putinfo(const char *key, const char *info);
106 static char *
107 t_getdate(char *buf, size_t buflen);
109 static void
110 printhelp(void);
112 static void
113 printusage(void);
115 static int T_int;
117 static void
118 t_sighandler(int sig) {
119 T_int = sig;
123 #ifndef WIN32
124 main(int argc, char **argv)
125 #else
126 t_main(int argc, char **argv)
127 #endif
129 int c;
130 int tnum;
131 #ifndef WIN32
132 int subprocs;
133 pid_t deadpid;
134 int status;
135 #endif
136 int len;
137 isc_boolean_t first;
138 testspec_t *pts;
139 #ifndef WIN32
140 struct sigaction sa;
141 #endif
143 isc_mem_debugging = ISC_MEM_DEBUGRECORD;
144 first = ISC_TRUE;
145 #ifndef WIN32
146 subprocs = 1;
147 #endif
148 T_timeout = T_TCTOUT;
151 * -a option is now default.
153 memset(T_tvec, 0xff, sizeof(T_tvec));
156 * Parse args.
158 while ((c = isc_commandline_parse(argc, argv, ":at:c:d:n:huxq:b:"))
159 != -1) {
160 if (c == 'a') {
162 * Flag all tests to be run.
164 memset(T_tvec, 0xff, sizeof(T_tvec));
166 else if (c == 'b') {
167 T_dir = isc_commandline_argument;
169 else if (c == 't') {
170 tnum = atoi(isc_commandline_argument);
171 if ((tnum > 0) && (tnum < T_MAXTESTS)) {
172 if (first) {
174 * Turn off effect of -a default
175 * and allow multiple -t and -n
176 * options.
178 memset(T_tvec, 0, sizeof(T_tvec));
179 first = ISC_FALSE;
182 * Flag test tnum to be run.
184 tnum -= 1;
185 T_tvec[tnum / 8] |= (0x01 << (tnum % 8));
188 else if (c == 'c') {
189 T_config = isc_commandline_argument;
191 else if (c == 'd') {
192 T_debug = atoi(isc_commandline_argument);
194 else if (c == 'n') {
195 pts = &T_testlist[0];
196 tnum = 0;
197 while (pts->pfv != NULL) {
198 if (! strcmp(pts->func_name,
199 isc_commandline_argument)) {
200 if (first) {
201 memset(T_tvec, 0,
202 sizeof(T_tvec));
203 first = ISC_FALSE;
205 T_tvec[tnum/8] |= (0x01 << (tnum%8));
206 break;
208 ++pts;
209 ++tnum;
211 if (pts->pfv == NULL) {
212 fprintf(stderr, "no such test %s\n",
213 isc_commandline_argument);
214 exit(1);
217 else if (c == 'h') {
218 printhelp();
219 exit(0);
221 else if (c == 'u') {
222 printusage();
223 exit(0);
225 else if (c == 'x') {
226 #ifndef WIN32
227 subprocs = 0;
228 #endif
230 else if (c == 'q') {
231 T_timeout = atoi(isc_commandline_argument);
233 else if (c == ':') {
234 fprintf(stderr, "Option -%c requires an argument\n",
235 isc_commandline_option);
236 exit(1);
238 else if (c == '?') {
239 fprintf(stderr, "Unrecognized option -%c\n",
240 isc_commandline_option);
241 exit(1);
246 * Set cwd.
249 if (T_dir != NULL && chdir(T_dir) != 0) {
250 fprintf(stderr, "chdir %s failed\n", T_dir);
251 exit(1);
255 * We don't want buffered output.
258 (void)setbuf(stdout, NULL);
259 (void)setbuf(stderr, NULL);
262 * Setup signals.
265 #ifndef WIN32
266 sa.sa_flags = 0;
267 sigfillset(&sa.sa_mask);
269 sa.sa_handler = t_sighandler;
270 (void)sigaction(SIGINT, &sa, NULL);
271 (void)sigaction(SIGALRM, &sa, NULL);
272 #endif
275 * Output start stanza to journal.
278 snprintf(T_buf, sizeof(T_buf), "%s:", argv[0]);
279 len = strlen(T_buf);
280 (void) t_getdate(T_buf + len, T_BIGBUF - len);
281 t_putinfo("S", T_buf);
284 * Setup the test environment using the config file.
287 if (T_config == NULL)
288 T_config = T_DEFAULT_CONFIG;
290 t_initconf(T_config);
291 if (T_debug)
292 t_dumpconf(T_config);
295 * Now invoke all the test cases.
298 tnum = 0;
299 pts = &T_testlist[0];
300 while (*pts->pfv != NULL) {
301 if (T_tvec[tnum / 8] & (0x01 << (tnum % 8))) {
302 #ifndef WIN32
303 if (subprocs) {
304 T_pid = fork();
305 if (T_pid == 0) {
306 (*pts->pfv)();
307 exit(0);
308 } else if (T_pid > 0) {
310 T_int = 0;
311 sa.sa_handler = t_sighandler;
312 (void)sigaction(SIGALRM, &sa, NULL);
313 alarm(T_timeout);
315 deadpid = (pid_t) -1;
316 while (deadpid != T_pid) {
317 deadpid =
318 waitpid(T_pid, &status, 0);
319 if (deadpid == T_pid) {
320 if (WIFSIGNALED(status)) {
321 if (WTERMSIG(status) ==
322 SIGTERM)
323 t_info(
324 "the test case timed out\n");
325 else
326 t_info(
327 "the test case caused exception %d\n",
328 WTERMSIG(status));
329 t_result(T_UNRESOLVED);
331 } else if ((deadpid == -1) &&
332 (errno == EINTR) &&
333 T_int) {
334 kill(T_pid, SIGTERM);
335 T_int = 0;
337 else if ((deadpid == -1) &&
338 ((errno == ECHILD) ||
339 (errno == ESRCH)))
340 break;
343 alarm(0);
344 sa.sa_handler = SIG_IGN;
345 (void)sigaction(SIGALRM, &sa, NULL);
346 } else {
347 t_info("fork failed, errno == %d\n",
348 errno);
349 t_result(T_UNRESOLVED);
352 else {
353 (*pts->pfv)();
355 #else
356 (*pts->pfv)();
357 #endif
359 ++pts;
360 ++tnum;
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);
368 return(0);
371 void
372 t_assert(const char *component, int anum, int class, const char *what, ...) {
373 va_list args;
374 char buf[T_BIGBUF];
376 (void)printf("T:%s:%d:%s\n", component, anum, class == T_REQUIRED ?
377 "A" : "C");
380 * Format text to a buffer.
382 va_start(args, what);
383 (void)vsnprintf(buf, sizeof(buf), what, args);
384 va_end(args);
386 (void)t_putinfo("A", buf);
387 (void)printf("\n");
390 void
391 t_info(const char *format, ...) {
392 va_list args;
393 char buf[T_BIGBUF];
395 va_start(args, format);
396 (void) vsnprintf(buf, sizeof(buf), format, args);
397 va_end(args);
398 (void) t_putinfo("I", buf);
401 void
402 t_result(int result) {
403 const char *p;
405 switch (result) {
406 case T_PASS:
407 p = "PASS";
408 break;
409 case T_FAIL:
410 p = "FAIL";
411 break;
412 case T_UNRESOLVED:
413 p = "UNRESOLVED";
414 break;
415 case T_SKIPPED:
416 p = "SKIPPED";
417 break;
418 case T_UNTESTED:
419 p = "UNTESTED";
420 break;
421 case T_THREADONLY:
422 p = "THREADONLY";
423 break;
424 case T_PKCS11ONLY:
425 p = "PKCS11ONLY";
426 break;
427 default:
428 p = "UNKNOWN";
429 break;
431 printf("R:%s\n", p);
434 char *
435 t_getenv(const char *name) {
436 char *n;
437 char **p;
438 size_t len;
440 n = NULL;
441 if (name && *name) {
443 p = &T_env[0];
444 len = strlen(name);
446 while (*p != NULL) {
447 if (strncmp(*p, name, len) == 0) {
448 if ( *(*p + len) == '=') {
449 n = *p + len + 1;
450 break;
453 ++p;
456 return(n);
461 * Read in the config file at path, initializing T_env.
463 * note: no format checking for now ...
467 static int
468 t_initconf(const char *path) {
470 int n;
471 int rval;
472 char **p;
473 FILE *fp;
475 rval = -1;
477 fp = fopen(path, "r");
478 if (fp != NULL) {
479 n = 0;
480 p = &T_env[0];
481 while (n < T_MAXENV) {
482 *p = t_fgetbs(fp);
483 if (*p == NULL)
484 break;
485 if ((**p == '#') || (strchr(*p, '=') == NULL)) {
487 * Skip comments and other junk.
489 (void)free(*p);
490 continue;
492 ++p; ++n;
494 (void)fclose(fp);
495 rval = 0;
498 return (rval);
503 * Dump T_env to stdout.
507 static int
508 t_dumpconf(const char *path) {
509 int rval;
510 char **p;
511 FILE *fp;
513 rval = -1;
514 fp = fopen(path, "r");
515 if (fp != NULL) {
516 p = &T_env[0];
517 while (*p != NULL) {
518 printf("C:%s\n", *p);
519 ++p;
521 (void) fclose(fp);
522 rval = 0;
524 return(rval);
529 * Read a newline or EOF terminated string from fp.
530 * On success:
531 * return a malloc'd buf containing the string with
532 * the newline converted to a '\0'.
533 * On error:
534 * return NULL.
536 * Caller is responsible for freeing buf.
540 char *
541 t_fgetbs(FILE *fp) {
542 int c;
543 size_t n;
544 size_t size;
545 char *buf, *old;
546 char *p;
548 n = 0;
549 size = T_BUFSIZ;
550 old = buf = (char *) malloc(T_BUFSIZ * sizeof(char));
552 if (buf != NULL) {
553 p = buf;
554 while ((c = fgetc(fp)) != EOF) {
556 if ((c == '\r') || (c == '\n'))
557 break;
559 *p++ = c;
560 ++n;
561 if ( n >= size ) {
562 size += T_BUFSIZ;
563 buf = (char *)realloc(buf,
564 size * sizeof(char));
565 if (buf == NULL)
566 goto err;
567 old = buf;
568 p = buf + n;
571 *p = '\0';
572 if (c == EOF && n == 0U) {
573 free(buf);
574 return (NULL);
576 return (buf);
577 } else {
578 err:
579 if (old != NULL)
580 free(old);
581 fprintf(stderr, "malloc/realloc failed %d", errno);
582 return(NULL);
588 * Put info to log, using key.
589 * For now, just dump it out.
590 * Later format into pretty lines.
594 static int
595 t_putinfo(const char *key, const char *info) {
596 int rval;
599 * For now.
601 rval = printf("%s:%s", key, info);
602 return(rval);
605 static char *
606 t_getdate(char *buf, size_t buflen) {
607 size_t n;
608 time_t t;
609 struct tm *p;
611 t = time(NULL);
612 p = localtime(&t);
613 n = strftime(buf, buflen - 1, "%A %d %B %H:%M:%S %Y\n", p);
614 return(n != 0U ? buf : NULL);
618 * Some generally used utilities.
620 struct dns_errormap {
621 isc_result_t result;
622 const char *text;
623 } dns_errormap[] = {
624 { ISC_R_SUCCESS, "ISC_R_SUCCESS" },
625 { ISC_R_EXISTS, "ISC_R_EXISTS" },
626 { ISC_R_NOTFOUND, "ISC_R_NOTFOUND" },
627 { ISC_R_NOSPACE, "ISC_R_NOSPACE" },
628 { ISC_R_UNEXPECTED, "ISC_R_UNEXPECTED" },
629 { ISC_R_UNEXPECTEDEND, "ISC_R_UNEXPECTEDEND" },
630 { ISC_R_RANGE, "ISC_R_RANGE" },
631 { DNS_R_LABELTOOLONG, "DNS_R_LABELTOOLONG" },
632 { DNS_R_BADESCAPE, "DNS_R_BADESCAPE" },
633 /* { DNS_R_BADBITSTRING, "DNS_R_BADBITSTRING" }, */
634 /* { DNS_R_BITSTRINGTOOLONG, "DNS_R_BITSTRINGTOOLONG"}, */
635 { DNS_R_EMPTYLABEL, "DNS_R_EMPTYLABEL" },
636 { DNS_R_BADDOTTEDQUAD, "DNS_R_BADDOTTEDQUAD" },
637 { DNS_R_UNKNOWN, "DNS_R_UNKNOWN" },
638 { DNS_R_BADLABELTYPE, "DNS_R_BADLABELTYPE" },
639 { DNS_R_BADPOINTER, "DNS_R_BADPOINTER" },
640 { DNS_R_TOOMANYHOPS, "DNS_R_TOOMANYHOPS" },
641 { DNS_R_DISALLOWED, "DNS_R_DISALLOWED" },
642 { DNS_R_EXTRATOKEN, "DNS_R_EXTRATOKEN" },
643 { DNS_R_EXTRADATA, "DNS_R_EXTRADATA" },
644 { DNS_R_TEXTTOOLONG, "DNS_R_TEXTTOOLONG" },
645 { DNS_R_SYNTAX, "DNS_R_SYNTAX" },
646 { DNS_R_BADCKSUM, "DNS_R_BADCKSUM" },
647 { DNS_R_BADAAAA, "DNS_R_BADAAAA" },
648 { DNS_R_NOOWNER, "DNS_R_NOOWNER" },
649 { DNS_R_NOTTL, "DNS_R_NOTTL" },
650 { DNS_R_BADCLASS, "DNS_R_BADCLASS" },
651 { DNS_R_PARTIALMATCH, "DNS_R_PARTIALMATCH" },
652 { DNS_R_NEWORIGIN, "DNS_R_NEWORIGIN" },
653 { DNS_R_UNCHANGED, "DNS_R_UNCHANGED" },
654 { DNS_R_BADTTL, "DNS_R_BADTTL" },
655 { DNS_R_NOREDATA, "DNS_R_NOREDATA" },
656 { DNS_R_CONTINUE, "DNS_R_CONTINUE" },
657 { DNS_R_DELEGATION, "DNS_R_DELEGATION" },
658 { DNS_R_GLUE, "DNS_R_GLUE" },
659 { DNS_R_DNAME, "DNS_R_DNAME" },
660 { DNS_R_CNAME, "DNS_R_CNAME" },
661 { DNS_R_NXDOMAIN, "DNS_R_NXDOMAIN" },
662 { DNS_R_NXRRSET, "DNS_R_NXRRSET" },
663 { DNS_R_BADDB, "DNS_R_BADDB" },
664 { DNS_R_ZONECUT, "DNS_R_ZONECUT" },
665 { DNS_R_NOTZONETOP, "DNS_R_NOTZONETOP" },
666 { DNS_R_SEENINCLUDE, "DNS_R_SEENINCLUDE" },
667 { DNS_R_SINGLETON, "DNS_R_SINGLETON" },
668 { (isc_result_t)0, NULL }
671 isc_result_t
672 t_dns_result_fromtext(char *name) {
674 isc_result_t result;
675 struct dns_errormap *pmap;
677 result = ISC_R_UNEXPECTED;
679 pmap = dns_errormap;
680 while (pmap->text != NULL) {
681 if (strcmp(name, pmap->text) == 0)
682 break;
683 ++pmap;
686 if (pmap->text != NULL)
687 result = pmap->result;
689 return (result);
692 struct dc_method_map {
693 unsigned int dc_method;
694 const char *text;
695 } dc_method_map[] = {
697 { DNS_COMPRESS_NONE, "DNS_COMPRESS_NONE" },
698 { DNS_COMPRESS_GLOBAL14, "DNS_COMPRESS_GLOBAL14" },
699 { DNS_COMPRESS_ALL, "DNS_COMPRESS_ALL" },
700 { 0, NULL }
703 unsigned int
704 t_dc_method_fromtext(char *name) {
705 unsigned int dc_method;
706 struct dc_method_map *pmap;
708 dc_method = DNS_COMPRESS_NONE;
710 pmap = dc_method_map;
711 while (pmap->text != NULL) {
712 if (strcmp(name, pmap->text) == 0)
713 break;
714 ++pmap;
717 if (pmap->text != NULL)
718 dc_method = pmap->dc_method;
720 return(dc_method);
724 t_bustline(char *line, char **toks) {
725 int cnt;
726 char *p;
728 cnt = 0;
729 if (line && *line) {
730 while ((p = strtok(line, "\t")) && (cnt < T_MAXTOKS)) {
731 *toks++ = p;
732 line = NULL;
733 ++cnt;
736 return(cnt);
739 static void
740 printhelp(void) {
741 int cnt;
742 testspec_t *pts;
744 cnt = 1;
745 pts = &T_testlist[0];
747 printf("Available tests:\n");
748 while (pts->func_name) {
749 printf("\t%d\t%s\n", cnt, pts->func_name);
750 ++pts;
751 ++cnt;
755 static void
756 printusage(void) {
757 printf("Usage:\n%s\n", Usage);
761 t_eval(const char *filename, int (*func)(char **), int nargs) {
762 FILE *fp;
763 char *p;
764 int line;
765 int cnt;
766 int result;
767 int tresult;
768 int nfails;
769 int nprobs;
770 int npass;
771 char *tokens[T_MAXTOKS + 1];
773 tresult = T_UNTESTED;
774 npass = 0;
775 nfails = 0;
776 nprobs = 0;
778 fp = fopen(filename, "r");
779 if (fp != NULL) {
780 line = 0;
781 while ((p = t_fgetbs(fp)) != NULL) {
783 ++line;
786 * Skip comment lines.
788 if ((isspace((unsigned char)*p)) || (*p == '#')) {
789 (void)free(p);
790 continue;
793 cnt = t_bustline(p, tokens);
794 if (cnt == nargs) {
795 tresult = func(tokens);
796 switch (tresult) {
797 case T_PASS:
798 ++npass;
799 break;
800 case T_FAIL:
801 ++nfails;
802 break;
803 case T_SKIPPED:
804 case T_UNTESTED:
805 break;
806 default:
807 ++nprobs;
808 break;
810 } else {
811 t_info("bad format in %s at line %d\n",
812 filename, line);
813 ++nprobs;
816 (void)free(p);
818 (void)fclose(fp);
819 } else {
820 t_info("Missing datafile %s\n", filename);
821 ++nprobs;
824 result = T_UNRESOLVED;
826 if (nfails == 0 && nprobs == 0 && npass > 0)
827 result = T_PASS;
828 else if (nfails > 0)
829 result = T_FAIL;
830 else if (npass == 0)
831 result = tresult;
833 return (result);
836 #ifdef WIN32
837 void
838 t_settests(const testspec_t list[]) {
839 int tnum;
840 const testspec_t *pts;
842 memset(T_testlist, 0, sizeof(T_testlist));
844 pts = &list[0];
845 for (tnum = 0; tnum < T_MAXTESTS - 1; pts++, tnum++) {
846 if (*pts->pfv == NULL)
847 break;
848 T_testlist[tnum] = *pts;
851 #endif