]> git.ipfire.org Git - thirdparty/dhcp.git/blame - tests/t_api.c
Merged rt43246a (fix --enable-threads)
[thirdparty/dhcp.git] / tests / t_api.c
CommitLineData
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
98bf1607 18/* $Id: t_api.c,v 1.4 2009/10/28 04:12:30 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
98bf1607
SR
46#include <isc/boolean.h>
47#include <isc/commandline.h>
48#include <isc/print.h>
49#include <isc/string.h>
50#include <isc/mem.h>
6e999c3c
SK
51
52#ifdef DNS_SUPPORT
53#include <dns/compress.h>
98bf1607 54#include <omapip/result.h>
6e999c3c
SK
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
66static 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
98int T_debug;
99int T_timeout;
100pid_t T_pid;
101static const char * T_config;
102static char T_tvec[T_MAXTESTS / 8];
103static char * T_env[T_MAXENV + 1];
104static char T_buf[T_BIGBUF];
105static char * T_dir;
106
107static int
108t_initconf(const char *path);
109
110static int
111t_dumpconf(const char *path);
112
113static int
114t_putinfo(const char *key, const char *info);
115
116static char *
117t_getdate(char *buf, size_t buflen);
118
119static void
120printhelp(void);
121
122static void
123printusage(void);
124
125static int T_int;
126
127static void
128t_sighandler(int sig) {
129 T_int = sig;
130}
131
132int
133main(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
371void
372t_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
389void
390t_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
399void
400t_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
429char *
430t_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
462static int
463t_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
502static int
503t_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
535char *
536t_fgetbs(FILE *fp) {
537 int c;
538 size_t n;
539 size_t size;
6d210be2 540 char *buf, *old;
6e999c3c
SK
541 char *p;
542
6d210be2
MA
543 n = 0;
544 size = T_BUFSIZ;
545 old = buf = (char *) malloc(T_BUFSIZ * sizeof(char));
6e999c3c
SK
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)
6d210be2
MA
561 goto err;
562 old = buf;
6e999c3c
SK
563 p = buf + n;
564 }
565 }
566 *p = '\0';
567 if (c == EOF && n == 0U) {
568 free(buf);
569 return (NULL);
570 }
571 return (buf);
572 } else {
6d210be2
MA
573 err:
574 if (old != NULL)
575 free(old);
576 fprintf(stderr, "malloc/realloc failed %d", errno);
6e999c3c
SK
577 return(NULL);
578 }
579}
580
581/*
582 *
583 * Put info to log, using key.
584 * For now, just dump it out.
585 * Later format into pretty lines.
586 *
587 */
588
589static int
590t_putinfo(const char *key, const char *info) {
591 int rval;
592
593 /*
594 * For now.
595 */
596 rval = printf("%s:%s", key, info);
597 return(rval);
598}
599
600static char *
601t_getdate(char *buf, size_t buflen) {
602 size_t n;
603 time_t t;
604 struct tm *p;
605
606 t = time(NULL);
607 p = localtime(&t);
608 n = strftime(buf, buflen - 1, "%A %d %B %H:%M:%S %Y\n", p);
609 return(n != 0U ? buf : NULL);
610}
611
612/*
613 * Some generally used utilities.
614 */
615#ifdef DNS_SUPPORT
616struct dns_errormap {
617 isc_result_t result;
618 const char *text;
619} dns_errormap[] = {
620 { ISC_R_SUCCESS, "ISC_R_SUCCESS" },
621 { ISC_R_EXISTS, "ISC_R_EXISTS" },
622 { ISC_R_NOTFOUND, "ISC_R_NOTFOUND" },
623 { ISC_R_NOSPACE, "ISC_R_NOSPACE" },
624 { ISC_R_UNEXPECTED, "ISC_R_UNEXPECTED" },
625 { ISC_R_UNEXPECTEDEND, "ISC_R_UNEXPECTEDEND" },
626 { ISC_R_RANGE, "ISC_R_RANGE" },
627 { DNS_R_LABELTOOLONG, "DNS_R_LABELTOOLONG" },
628 { DNS_R_BADESCAPE, "DNS_R_BADESCAPE" },
629 /* { DNS_R_BADBITSTRING, "DNS_R_BADBITSTRING" }, */
630 /* { DNS_R_BITSTRINGTOOLONG, "DNS_R_BITSTRINGTOOLONG"}, */
631 { DNS_R_EMPTYLABEL, "DNS_R_EMPTYLABEL" },
632 { DNS_R_BADDOTTEDQUAD, "DNS_R_BADDOTTEDQUAD" },
633 { DNS_R_UNKNOWN, "DNS_R_UNKNOWN" },
634 { DNS_R_BADLABELTYPE, "DNS_R_BADLABELTYPE" },
635 { DNS_R_BADPOINTER, "DNS_R_BADPOINTER" },
636 { DNS_R_TOOMANYHOPS, "DNS_R_TOOMANYHOPS" },
637 { DNS_R_DISALLOWED, "DNS_R_DISALLOWED" },
638 { DNS_R_EXTRATOKEN, "DNS_R_EXTRATOKEN" },
639 { DNS_R_EXTRADATA, "DNS_R_EXTRADATA" },
640 { DNS_R_TEXTTOOLONG, "DNS_R_TEXTTOOLONG" },
641 { DNS_R_SYNTAX, "DNS_R_SYNTAX" },
642 { DNS_R_BADCKSUM, "DNS_R_BADCKSUM" },
643 { DNS_R_BADAAAA, "DNS_R_BADAAAA" },
644 { DNS_R_NOOWNER, "DNS_R_NOOWNER" },
645 { DNS_R_NOTTL, "DNS_R_NOTTL" },
646 { DNS_R_BADCLASS, "DNS_R_BADCLASS" },
647 { DNS_R_PARTIALMATCH, "DNS_R_PARTIALMATCH" },
648 { DNS_R_NEWORIGIN, "DNS_R_NEWORIGIN" },
649 { DNS_R_UNCHANGED, "DNS_R_UNCHANGED" },
650 { DNS_R_BADTTL, "DNS_R_BADTTL" },
651 { DNS_R_NOREDATA, "DNS_R_NOREDATA" },
652 { DNS_R_CONTINUE, "DNS_R_CONTINUE" },
653 { DNS_R_DELEGATION, "DNS_R_DELEGATION" },
654 { DNS_R_GLUE, "DNS_R_GLUE" },
655 { DNS_R_DNAME, "DNS_R_DNAME" },
656 { DNS_R_CNAME, "DNS_R_CNAME" },
657 { DNS_R_NXDOMAIN, "DNS_R_NXDOMAIN" },
658 { DNS_R_NXRRSET, "DNS_R_NXRRSET" },
659 { DNS_R_BADDB, "DNS_R_BADDB" },
660 { DNS_R_ZONECUT, "DNS_R_ZONECUT" },
661 { DNS_R_NOTZONETOP, "DNS_R_NOTZONETOP" },
662 { DNS_R_SEENINCLUDE, "DNS_R_SEENINCLUDE" },
663 { DNS_R_SINGLETON, "DNS_R_SINGLETON" },
664 { (isc_result_t)0, NULL }
665};
666
667isc_result_t
668t_dns_result_fromtext(char *name) {
669
670 isc_result_t result;
671 struct dns_errormap *pmap;
672
673 result = ISC_R_UNEXPECTED;
674
675 pmap = dns_errormap;
676 while (pmap->text != NULL) {
677 if (strcmp(name, pmap->text) == 0)
678 break;
679 ++pmap;
680 }
681
682 if (pmap->text != NULL)
683 result = pmap->result;
684
685 return (result);
686}
687
688struct dc_method_map {
689 unsigned int dc_method;
690 const char *text;
691} dc_method_map[] = {
692
693 { DNS_COMPRESS_NONE, "DNS_COMPRESS_NONE" },
694 { DNS_COMPRESS_GLOBAL14, "DNS_COMPRESS_GLOBAL14" },
695 { DNS_COMPRESS_ALL, "DNS_COMPRESS_ALL" },
696 { 0, NULL }
697};
698
699unsigned int
700t_dc_method_fromtext(char *name) {
701 unsigned int dc_method;
702 struct dc_method_map *pmap;
703
704 dc_method = DNS_COMPRESS_NONE;
705
706 pmap = dc_method_map;
707 while (pmap->text != NULL) {
708 if (strcmp(name, pmap->text) == 0)
709 break;
710 ++pmap;
711 }
712
713 if (pmap->text != NULL)
714 dc_method = pmap->dc_method;
715
716 return(dc_method);
717}
718#endif /* DNS_SUPPORT */
719
720int
721t_bustline(char *line, char **toks) {
722 int cnt;
723 char *p;
724
725 cnt = 0;
726 if (line && *line) {
727 while ((p = strtok(line, "\t")) && (cnt < T_MAXTOKS)) {
728 *toks++ = p;
729 line = NULL;
730 ++cnt;
731 }
732 }
733 return(cnt);
734}
735
736static void
737printhelp(void) {
738 int cnt;
739 testspec_t *pts;
740
741 cnt = 1;
742 pts = &T_testlist[0];
743
744 printf("Available tests:\n");
745 while (pts->func_name) {
746 printf("\t%d\t%s\n", cnt, pts->func_name);
747 ++pts;
748 ++cnt;
749 }
750}
751
752static void
753printusage(void) {
754 printf("Usage:\n%s\n", Usage);
755}
756
757int
758t_eval(const char *filename, int (*func)(char **), int nargs) {
759 FILE *fp;
760 char *p;
761 int line;
762 int cnt;
763 int result;
764 int nfails;
765 int nprobs;
766 int npass;
767 char *tokens[T_MAXTOKS + 1];
768
769 npass = 0;
770 nfails = 0;
771 nprobs = 0;
772
773 fp = fopen(filename, "r");
774 if (fp != NULL) {
775 line = 0;
776 while ((p = t_fgetbs(fp)) != NULL) {
777
778 ++line;
779
780 /*
781 * Skip comment lines.
782 */
783 if ((isspace((unsigned char)*p)) || (*p == '#')) {
784 (void)free(p);
785 continue;
786 }
787
788 cnt = t_bustline(p, tokens);
789 if (cnt == nargs) {
790 result = func(tokens);
791 switch (result) {
792 case T_PASS:
793 ++npass;
794 break;
795 case T_FAIL:
796 ++nfails;
797 break;
798 case T_UNTESTED:
799 break;
800 default:
801 ++nprobs;
802 break;
803 }
804 } else {
805 t_info("bad format in %s at line %d\n",
806 filename, line);
807 ++nprobs;
808 }
809
810 (void)free(p);
811 }
812 (void)fclose(fp);
813 } else {
814 t_info("Missing datafile %s\n", filename);
815 ++nprobs;
816 }
817
818 result = T_UNRESOLVED;
819
820 if (nfails == 0 && nprobs == 0 && npass > 0)
821 result = T_PASS;
822 else if (nfails > 0)
823 result = T_FAIL;
824 else if (npass == 0)
825 result = T_UNTESTED;
826
827 return (result);
828}