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 */
38 #include <isc/boolean.h>
39 #include <isc/commandline.h>
40 #include <isc/print.h>
41 #include <isc/string.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";
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
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 */
75 #define T_DEFAULT_CONFIG "t_config"
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
];
91 t_initconf(const char *path
);
94 t_dumpconf(const char *path
);
97 t_putinfo(const char *key
, const char *info
);
100 t_getdate(char *buf
, size_t buflen
);
111 t_sighandler(int sig
) {
116 main(int argc
, char **argv
) {
127 isc_mem_debugging
= ISC_MEM_DEBUGRECORD
;
130 T_timeout
= T_TCTOUT
;
133 * -a option is now default.
135 memset(T_tvec
, 0xff, sizeof(T_tvec
));
140 while ((c
= isc_commandline_parse(argc
, argv
, ":at:c:d:n:huxq:b:"))
144 * Flag all tests to be run.
146 memset(T_tvec
, 0xff, sizeof(T_tvec
));
149 T_dir
= isc_commandline_argument
;
152 tnum
= atoi(isc_commandline_argument
);
153 if ((tnum
> 0) && (tnum
< T_MAXTESTS
)) {
156 * Turn off effect of -a default
157 * and allow multiple -t and -n
160 memset(T_tvec
, 0, sizeof(T_tvec
));
164 * Flag test tnum to be run.
167 T_tvec
[tnum
/ 8] |= (0x01 << (tnum
% 8));
171 T_config
= isc_commandline_argument
;
174 T_debug
= atoi(isc_commandline_argument
);
177 pts
= &T_testlist
[0];
179 while (pts
->pfv
!= NULL
) {
180 if (! strcmp(pts
->func_name
,
181 isc_commandline_argument
)) {
187 T_tvec
[tnum
/8] |= (0x01 << (tnum
%8));
193 if (pts
->pfv
== NULL
) {
194 fprintf(stderr
, "no such test %s\n",
195 isc_commandline_argument
);
211 T_timeout
= atoi(isc_commandline_argument
);
214 fprintf(stderr
, "Option -%c requires an argument\n",
215 isc_commandline_option
);
219 fprintf(stderr
, "Unrecognized option -%c\n",
220 isc_commandline_option
);
229 if (T_dir
!= NULL
&& chdir(T_dir
) != 0) {
230 fprintf(stderr
, "chdir %s failed\n", T_dir
);
235 * We don't want buffered output.
238 (void)setbuf(stdout
, NULL
);
239 (void)setbuf(stderr
, NULL
);
246 sigfillset(&sa
.sa_mask
);
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
);
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]);
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
);
279 t_dumpconf(T_config
);
282 * Now invoke all the test cases.
286 pts
= &T_testlist
[0];
287 while (*pts
->pfv
!= NULL
) {
288 if (T_tvec
[tnum
/ 8] & (0x01 << (tnum
% 8))) {
294 } else if (T_pid
> 0) {
297 sa
.sa_handler
= t_sighandler
;
298 (void)sigaction(SIGALRM
, &sa
, NULL
);
301 deadpid
= (pid_t
) -1;
302 while (deadpid
!= T_pid
) {
304 waitpid(T_pid
, &status
, 0);
305 if (deadpid
== T_pid
) {
306 if (WIFSIGNALED(status
)) {
307 if (WTERMSIG(status
) ==
310 "the test case timed out\n");
313 "the test case caused exception %d\n",
315 t_result(T_UNRESOLVED
);
317 } else if ((deadpid
== -1) &&
320 kill(T_pid
, SIGTERM
);
323 else if ((deadpid
== -1) &&
324 ((errno
== ECHILD
) ||
330 sa
.sa_handler
= SIG_IGN
;
331 (void)sigaction(SIGALRM
, &sa
, NULL
);
333 t_info("fork failed, errno == %d\n",
335 t_result(T_UNRESOLVED
);
346 snprintf(T_buf
, sizeof(T_buf
), "%s:", argv
[0]);
348 (void) t_getdate(T_buf
+ len
, T_BIGBUF
- len
);
349 t_putinfo("E", T_buf
);
355 t_assert(const char *component
, int anum
, int class, const char *what
, ...) {
358 (void)printf("T:%s:%d:%s\n", component
, anum
, class == T_REQUIRED
?
362 * Format text to a buffer.
364 va_start(args
, what
);
365 (void)vsnprintf(T_buf
, sizeof(T_buf
), what
, args
);
368 (void)t_putinfo("A", T_buf
);
373 t_info(const char *format
, ...) {
376 va_start(args
, format
);
377 (void) vsnprintf(T_buf
, sizeof(T_buf
), format
, args
);
379 (void) t_putinfo("I", T_buf
);
383 t_result(int result
) {
413 t_getenv(const char *name
) {
425 if (strncmp(*p
, name
, len
) == 0) {
426 if ( *(*p
+ len
) == '=') {
439 * Read in the config file at path, initializing T_env.
441 * note: no format checking for now ...
446 t_initconf(const char *path
) {
455 fp
= fopen(path
, "r");
459 while (n
< T_MAXENV
) {
463 if ((**p
== '#') || (strchr(*p
, '=') == NULL
)) {
465 * Skip comments and other junk.
481 * Dump T_env to stdout.
486 t_dumpconf(const char *path
) {
492 fp
= fopen(path
, "r");
496 printf("C:%s\n", *p
);
507 * Read a newline or EOF terminated string from fp.
509 * return a malloc'd buf containing the string with
510 * the newline converted to a '\0'.
514 * Caller is responsible for freeing buf.
528 buf
= (char *) malloc(T_BUFSIZ
* sizeof(char));
532 while ((c
= fgetc(fp
)) != EOF
) {
541 buf
= (char *)realloc(buf
,
542 size
* sizeof(char));
549 if (c
== EOF
&& n
== 0U) {
555 fprintf(stderr
, "malloc failed %d", errno
);
562 * Put info to log, using key.
563 * For now, just dump it out.
564 * Later format into pretty lines.
569 t_putinfo(const char *key
, const char *info
) {
575 rval
= printf("%s:%s", key
, info
);
580 t_getdate(char *buf
, size_t buflen
) {
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
{
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
}
646 t_dns_result_fromtext(char *name
) {
649 struct dns_errormap
*pmap
;
651 result
= ISC_R_UNEXPECTED
;
654 while (pmap
->text
!= NULL
) {
655 if (strcmp(name
, pmap
->text
) == 0)
660 if (pmap
->text
!= NULL
)
661 result
= pmap
->result
;
666 struct dc_method_map
{
667 unsigned int dc_method
;
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" },
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)
691 if (pmap
->text
!= NULL
)
692 dc_method
= pmap
->dc_method
;
698 t_bustline(char *line
, char **toks
) {
704 while ((p
= strtok(line
, "\t")) && (cnt
< T_MAXTOKS
)) {
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
);
731 printf("Usage:\n%s\n", Usage
);
735 t_eval(const char *filename
, int (*func
)(char **), int nargs
) {
744 char *tokens
[T_MAXTOKS
+ 1];
750 fp
= fopen(filename
, "r");
753 while ((p
= t_fgetbs(fp
)) != NULL
) {
758 * Skip comment lines.
760 if ((isspace((unsigned char)*p
)) || (*p
== '#')) {
765 cnt
= t_bustline(p
, tokens
);
767 result
= func(tokens
);
782 t_info("bad format in %s at line %d\n",
791 t_info("Missing datafile %s\n", filename
);
795 result
= T_UNRESOLVED
;
797 if (nfails
== 0 && nprobs
== 0 && npass
> 0)