2 * Copyright (c) 2011 Alex Hornung <alex@alexhornung.com>.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/resource.h>
32 #include <sys/types.h>
46 #include <libprop/proplib.h>
52 #include <dfregress.h>
55 testcase_from_struct(struct testcase
*testcase
)
58 prop_dictionary_t dict
, testcase_dict
;
62 testcase_dict
= prop_dictionary_create();
63 if (testcase_dict
== NULL
)
64 err(1, "could not create testcase dict");
65 r
= prop_dictionary_set_cstring(testcase_dict
, "name", testcase
->name
);
67 err(1, "prop_dictionary operation failed");
68 r
= prop_dictionary_set_cstring(testcase_dict
, "type", testcase
->type_str
);
70 err(1, "prop_dictionary operation failed");
72 r
= prop_dictionary_set_int32(testcase_dict
, "argc",
73 (int32_t)testcase
->argc
);
75 err(1, "prop_dictionary operation failed");
77 a
= prop_array_create_with_capacity(testcase
->argc
+1);
79 err(1, "prop_array_create for argv failed");
81 s
= strrchr(testcase
->name
, '/');
82 r
= prop_array_set_cstring(a
, 0, (s
== NULL
) ? testcase
->name
: s
+1);
84 err(1, "prop_array_set_cstring operation failed");
86 for (i
= 1; i
<= testcase
->argc
; i
++) {
87 r
= prop_array_set_cstring(a
, i
, testcase
->argv
[i
-1]);
89 err(1, "prop_array_set_cstring operation failed");
92 r
= prop_dictionary_set(testcase_dict
, "args", a
);
94 err(1, "prop_dictionary_set \"args\" failed");
96 dict
= prop_dictionary_create();
98 err(1, "could not create dict");
100 r
= prop_dictionary_set_int32(dict
, "timeout_in_secs",
101 (int32_t)testcase
->opts
.timeout_in_secs
);
103 err(1, "prop_dictionary operation failed");
105 r
= prop_dictionary_set_int32(dict
, "rc",
106 (int32_t)testcase
->opts
.rc
);
108 err(1, "prop_dictionary operation failed");
110 r
= prop_dictionary_set_uint32(dict
, "flags", testcase
->opts
.flags
);
112 err(1, "prop_dictionary operation failed");
114 if (testcase
->opts
.pre_cmd
!= NULL
) {
115 r
= prop_dictionary_set_cstring(dict
, "pre_cmd",
116 testcase
->opts
.pre_cmd
);
118 err(1, "prop_dictionary operation failed");
121 if (testcase
->opts
.post_cmd
!= NULL
) {
122 r
= prop_dictionary_set_cstring(dict
, "post_cmd",
123 testcase
->opts
.post_cmd
);
125 err(1, "prop_dictionary operation failed");
128 if (testcase
->opts
.interpreter
!= NULL
) {
129 r
= prop_dictionary_set_cstring(dict
, "interpreter",
130 testcase
->opts
.interpreter
);
132 err(1, "prop_dictionary operation failed");
135 r
= prop_dictionary_set_uint32(dict
, "runas_uid",
136 (uint32_t)testcase
->opts
.runas_uid
);
138 err(1, "prop_dictionary operation failed");
140 r
= prop_dictionary_set_cstring(dict
, "make_cmd",
141 (testcase
->opts
.make_cmd
!= NULL
) ? testcase
->opts
.make_cmd
: "make");
143 err(1, "prop_dictionary operation failed");
145 r
= prop_dictionary_set(testcase_dict
, "opts", dict
);
147 err(1, "prop_dictionary operation failed");
149 return testcase_dict
;
153 testcase_get_timeout(prop_dictionary_t testcase
)
155 static struct timeval tv
;
159 r
= prop_dictionary_get_int32(prop_dictionary_get(testcase
, "opts"),
160 "timeout_in_secs", &val
);
162 err(1, "prop_dictionary operation failed");
165 tv
.tv_sec
= (long)val
;
171 testcase_get_type(prop_dictionary_t testcase
)
176 r
= prop_dictionary_get_cstring_nocopy(testcase
, "type", &type
);
178 err(1, "prop_dictionary operation failed");
180 if (strcmp(type
, "userland") == 0)
181 return TESTCASE_TYPE_USERLAND
;
182 else if (strcmp(type
, "kernel") == 0)
183 return TESTCASE_TYPE_KERNEL
;
184 else if (strcmp(type
, "buildonly") == 0)
185 return TESTCASE_TYPE_BUILDONLY
;
191 testcase_get_type_desc(prop_dictionary_t testcase
)
196 r
= prop_dictionary_get_cstring_nocopy(testcase
, "type", &str
);
198 err(1, "prop_dictionary operation failed");
204 testcase_get_name(prop_dictionary_t testcase
)
209 r
= prop_dictionary_get_cstring_nocopy(testcase
, "name", &str
);
211 err(1, "prop_dictionary operation failed");
217 testcase_get_argc(prop_dictionary_t testcase
)
222 r
= prop_dictionary_get_int32(testcase
, "argc", &argc
);
224 err(1, "prop_dictionary operation failed for argc");
230 testcase_get_args(prop_dictionary_t testcase
)
232 /* Sane limit of 63 arguments... who wants more than that? */
233 static const char *argv
[64];
234 unsigned int i
, count
;
238 a
= prop_dictionary_get(testcase
, "args");
240 err(1, "testcase_get_args NULL array");
242 count
= prop_array_count(a
);
244 for (i
= 0; i
< count
; i
++) {
245 r
= prop_array_get_cstring_nocopy(a
, i
, &argv
[i
]);
247 err(1, "error building argv");
256 testcase_get_flags(prop_dictionary_t testcase
)
261 r
= prop_dictionary_get_uint32(prop_dictionary_get(testcase
, "opts"),
264 err(1, "prop_dictionary operation failed");
270 testcase_get_precmd_type(prop_dictionary_t testcase
)
272 uint32_t flags
= testcase_get_flags(testcase
);
274 return (flags
& (TESTCASE_INT_PRE
| TESTCASE_CUSTOM_PRE
));
278 testcase_get_rc(prop_dictionary_t testcase
)
283 r
= prop_dictionary_get_int32(prop_dictionary_get(testcase
, "opts"),
286 err(1, "prop_dictionary operation failed for rc");
292 testcase_get_postcmd_type(prop_dictionary_t testcase
)
294 uint32_t flags
= testcase_get_flags(testcase
);
296 return (flags
& (TESTCASE_INT_POST
| TESTCASE_CUSTOM_POST
));
300 testcase_needs_setuid(prop_dictionary_t testcase
)
302 uint32_t flags
= testcase_get_flags(testcase
);
304 return (flags
& TESTCASE_RUN_AS
);
308 testcase_get_runas_uid(prop_dictionary_t testcase
)
313 r
= prop_dictionary_get_uint32(
314 prop_dictionary_get(testcase
, "opts"), "runas_uid", &uid
);
316 err(1, "prop_dictionary operation failed");
322 testcase_get_custom_precmd(prop_dictionary_t testcase
)
327 r
= prop_dictionary_get_cstring_nocopy(
328 prop_dictionary_get(testcase
, "opts"), "pre_cmd", &str
);
330 err(1, "prop_dictionary operation failed");
336 testcase_get_custom_postcmd(prop_dictionary_t testcase
)
341 r
= prop_dictionary_get_cstring_nocopy(
342 prop_dictionary_get(testcase
, "opts"), "pre_cmd", &str
);
344 err(1, "prop_dictionary operation failed");
350 _testcase_get_interpreter(prop_dictionary_t testcase
, bool fatal
)
355 r
= prop_dictionary_get_cstring_nocopy(
356 prop_dictionary_get(testcase
, "opts"), "interpreter", &str
);
359 err(1, "prop_dictionary operation failed for interpreter");
368 testcase_get_interpreter(prop_dictionary_t testcase
)
370 return _testcase_get_interpreter(testcase
, true);
374 testcase_get_interpreter_noexit(prop_dictionary_t testcase
)
376 return _testcase_get_interpreter(testcase
, false);
380 testcase_get_make_cmd(prop_dictionary_t testcase
)
385 r
= prop_dictionary_get_cstring_nocopy(
386 prop_dictionary_get(testcase
, "opts"), "make_cmd", &str
);
388 err(1, "prop_dictionary operation failed");
394 testcase_get_result_dict(prop_dictionary_t testcase
)
396 prop_dictionary_t result_dict
;
399 result_dict
= prop_dictionary_get(testcase
, "result");
400 if (result_dict
== NULL
) {
401 result_dict
= prop_dictionary_create();
402 if (result_dict
== NULL
)
403 err(1, "could not allocate new result dict");
405 r
= prop_dictionary_set(testcase
, "result", result_dict
);
407 err(1, "prop_dictionary operation failed");
414 testcase_set_build_buf(prop_dictionary_t testcase
, const char *buf
)
416 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
418 return !prop_dictionary_set_cstring(dict
, "build_buf", buf
);
422 testcase_set_cleanup_buf(prop_dictionary_t testcase
, const char *buf
)
424 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
426 return !prop_dictionary_set_cstring(dict
, "cleanup_buf", buf
);
430 testcase_set_sys_buf(prop_dictionary_t testcase
, const char *buf
)
432 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
434 return !prop_dictionary_set_cstring(dict
, "sys_buf", buf
);
438 testcase_set_precmd_buf(prop_dictionary_t testcase
, const char *buf
)
440 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
442 return !prop_dictionary_set_cstring(dict
, "precmd_buf", buf
);
446 testcase_set_postcmd_buf(prop_dictionary_t testcase
, const char *buf
)
448 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
450 return !prop_dictionary_set_cstring(dict
, "postcmd_buf", buf
);
454 testcase_set_stdout_buf(prop_dictionary_t testcase
, const char *buf
)
456 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
458 return !prop_dictionary_set_cstring(dict
, "stdout_buf", buf
);
462 testcase_set_stderr_buf(prop_dictionary_t testcase
, const char *buf
)
464 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
466 return !prop_dictionary_set_cstring(dict
, "stderr_buf", buf
);
470 testcase_set_result(prop_dictionary_t testcase
, int result
)
472 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
474 return !prop_dictionary_set_int32(dict
, "result", result
);
478 testcase_set_exit_value(prop_dictionary_t testcase
, int exitval
)
480 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
482 return !prop_dictionary_set_int32(dict
, "exit_value", exitval
);
486 testcase_set_signal(prop_dictionary_t testcase
, int sig
)
488 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
490 return !prop_dictionary_set_int32(dict
, "signal", sig
);
494 testcase_get_build_buf(prop_dictionary_t testcase
)
496 const char *str
= "";
498 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
499 prop_dictionary_get_cstring_nocopy(dict
, "build_buf", &str
);
505 testcase_get_cleanup_buf(prop_dictionary_t testcase
)
507 const char *str
= "";
509 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
510 prop_dictionary_get_cstring_nocopy(dict
, "cleanup_buf", &str
);
516 testcase_get_sys_buf(prop_dictionary_t testcase
)
518 const char *str
= "";
520 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
521 prop_dictionary_get_cstring_nocopy(dict
, "sys_buf", &str
);
527 testcase_get_precmd_buf(prop_dictionary_t testcase
)
529 const char *str
= "";
531 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
532 prop_dictionary_get_cstring_nocopy(dict
, "precmd_buf", &str
);
538 testcase_get_postcmd_buf(prop_dictionary_t testcase
)
540 const char *str
= "";
542 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
543 prop_dictionary_get_cstring_nocopy(dict
, "postcmd_buf", &str
);
549 testcase_get_stdout_buf(prop_dictionary_t testcase
)
551 const char *str
= "";
553 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
554 prop_dictionary_get_cstring_nocopy(dict
, "stdout_buf", &str
);
560 testcase_get_stderr_buf(prop_dictionary_t testcase
)
562 const char *str
= "";
564 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
565 prop_dictionary_get_cstring_nocopy(dict
, "stderr_buf", &str
);
571 testcase_get_result(prop_dictionary_t testcase
)
573 int32_t result
= RESULT_NOTRUN
;
575 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
576 prop_dictionary_get_int32(dict
, "result", &result
);
582 testcase_get_result_desc(prop_dictionary_t testcase
)
584 int result
= testcase_get_result(testcase
);
587 case RESULT_TIMEOUT
: return "TIMEOUT";
588 case RESULT_SIGNALLED
: return "SIGNALLED";
589 case RESULT_NOTRUN
: return "NOT RUN";
590 case RESULT_FAIL
: return "FAIL";
591 case RESULT_PASS
: return "PASS";
592 case RESULT_PREFAIL
: return "PREFAIL";
593 case RESULT_POSTFAIL
: return "POSTFAIL";
594 case RESULT_BUILDFAIL
: return "BUILDFAIL";
595 default: return "UNKNOWN";
600 testcase_get_exit_value(prop_dictionary_t testcase
)
605 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
606 r
= prop_dictionary_get_int32(dict
, "exit_value", &exitval
);
608 err(1, "prop_dictionary operation failed");
614 testcase_get_signal(prop_dictionary_t testcase
)
619 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
620 r
= prop_dictionary_get_int32(dict
, "signal", &sig
);
622 err(1, "prop_dictionary operation failed");
628 parse_testcase_option(struct testcase_options
*opts
, char *option
)
631 char *parameter
, *endptr
;
635 parameter
= strchr(option
, '=');
636 noparam
= (parameter
== NULL
);
643 if (strcmp(option
, "timeout") == 0) {
645 syntax_error("The option 'timeout' needs a parameter");
648 lval
= strtol(parameter
, &endptr
, 10);
650 syntax_error("The option 'timeout' expects an integer "
651 "parameter, not '%s'", parameter
);
654 opts
->timeout_in_secs
= (long int)lval
;
655 } else if (strcmp(option
, "rc") == 0) {
657 syntax_error("The option 'timeout' needs a parameter");
660 lval
= strtol(parameter
, &endptr
, 10);
662 syntax_error("The option 'timeout' expects an integer "
663 "parameter, not '%s'", parameter
);
666 opts
->rc
= (int)lval
;
667 } else if (strcmp(option
, "intpre") == 0) {
668 opts
->flags
|= TESTCASE_INT_PRE
;
669 } else if (strcmp(option
, "intpost") == 0) {
670 opts
->flags
|= TESTCASE_INT_POST
;
671 } else if (strcmp(option
, "pre") == 0) {
673 syntax_error("The option 'pre' needs a parameter");
676 opts
->flags
|= TESTCASE_CUSTOM_PRE
;
677 opts
->pre_cmd
= strdup(parameter
);
678 } else if (strcmp(option
, "post") == 0) {
680 syntax_error("The option 'post' needs a parameter");
683 opts
->flags
|= TESTCASE_CUSTOM_POST
;
684 opts
->post_cmd
= strdup(parameter
);
685 } else if (strcmp(option
, "runas") == 0) {
687 syntax_error("The option 'runas' needs a parameter");
690 if ((pwd
= getpwnam(parameter
))) {
691 opts
->runas_uid
= pwd
->pw_uid
;
692 opts
->flags
|= TESTCASE_RUN_AS
;
694 syntax_error("invalid user name for 'runas': %s",
697 } else if (strcmp(option
, "nobuild") == 0) {
698 opts
->flags
|= TESTCASE_NOBUILD
;
699 } else if (strcmp(option
, "interpreter") == 0) {
701 syntax_error("The option 'interpreter' needs a parameter");
703 opts
->interpreter
= strdup(parameter
);
704 } else if (strcmp(option
, "make") == 0) {
706 syntax_error("The option 'make' needs a parameter");
709 opts
->make_cmd
= strdup(parameter
);
710 } else if (strcmp(option
, "defaults") == 0) {
711 /* Valid option, does nothing */
713 syntax_error("Unknown option: %s", option
);
721 testcase_entry_parser(void *arg
, char **tokens
)
723 prop_array_t runlist
;
724 prop_dictionary_t testcase_dict
;
725 struct testcase
*testcase
;
729 runlist
= (prop_array_t
)arg
;
731 testcase
= malloc(sizeof(struct testcase
));
732 if (testcase
== NULL
)
733 err(1, "could not malloc testcase memory");
735 bzero(testcase
, sizeof(struct testcase
));
737 entry_check_num_args(tokens
, 3);
739 testcase
->argv
= &tokens
[3];
740 for (testcase
->argc
= 0; testcase
->argv
[testcase
->argc
] != NULL
;
744 nopts
= parse_options(tokens
[2], options
);
746 testcase
->name
= tokens
[0];
748 if (strcmp(tokens
[1], "userland") == 0) {
749 testcase
->type
= TESTCASE_TYPE_USERLAND
;
750 } else if (strcmp(tokens
[1], "kernel") == 0) {
751 testcase
->type
= TESTCASE_TYPE_KERNEL
;
752 } else if (strcmp(tokens
[1], "buildonly") == 0) {
753 testcase
->type
= TESTCASE_TYPE_BUILDONLY
;
755 syntax_error("Unknown type: %s", tokens
[1]);
759 testcase
->type_str
= tokens
[1];
761 config_get_defaults(&testcase
->opts
);
763 for (i
= 0; i
< nopts
; i
++)
764 parse_testcase_option(&testcase
->opts
, options
[i
]);
766 if ((testcase
->type
!= TESTCASE_TYPE_USERLAND
) &&
767 (testcase
->opts
.flags
& (TESTCASE_INT_PRE
| TESTCASE_INT_POST
)))
768 syntax_error("'intpre' and 'intpost' options are only valid "
769 "with testcase type 'userland'");
771 if ((testcase
->type
== TESTCASE_TYPE_BUILDONLY
) &&
772 (testcase
->opts
.flags
& TESTCASE_NOBUILD
))
773 syntax_error("'nobuild' option is incompatible with type "
776 testcase_dict
= testcase_from_struct(testcase
);
777 if (testcase
->opts
.pre_cmd
!= NULL
)
778 free(testcase
->opts
.pre_cmd
);
779 if (testcase
->opts
.post_cmd
!= NULL
)
780 free(testcase
->opts
.post_cmd
);
781 if (testcase
->opts
.interpreter
!= NULL
)
782 free(testcase
->opts
.interpreter
);
783 if (testcase
->opts
.make_cmd
!= NULL
)
784 free(testcase
->opts
.make_cmd
);
787 r
= prop_array_add(runlist
, testcase_dict
);
789 err(1, "prop_array_add failed");