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 a
= prop_array_create_with_capacity(testcase
->argc
+1);
74 err(1, "prop_array_create for argv failed");
76 s
= strrchr(testcase
->name
, '/');
77 r
= prop_array_set_cstring(a
, 0, (s
== NULL
) ? testcase
->name
: s
+1);
79 err(1, "prop_array_set_cstring operation failed");
81 for (i
= 1; i
<= testcase
->argc
; i
++) {
82 r
= prop_array_set_cstring(a
, i
, testcase
->argv
[i
-1]);
84 err(1, "prop_array_set_cstring operation failed");
87 r
= prop_dictionary_set(testcase_dict
, "args", a
);
89 err(1, "prop_dictionary_set \"args\" failed");
91 dict
= prop_dictionary_create();
93 err(1, "could not create dict");
95 r
= prop_dictionary_set_int32(dict
, "timeout_in_secs",
96 (int32_t)testcase
->opts
.timeout_in_secs
);
98 err(1, "prop_dictionary operation failed");
100 r
= prop_dictionary_set_uint32(dict
, "flags", testcase
->opts
.flags
);
102 err(1, "prop_dictionary operation failed");
104 if (testcase
->opts
.pre_cmd
!= NULL
) {
105 r
= prop_dictionary_set_cstring(dict
, "pre_cmd",
106 testcase
->opts
.pre_cmd
);
108 err(1, "prop_dictionary operation failed");
111 if (testcase
->opts
.post_cmd
!= NULL
) {
112 r
= prop_dictionary_set_cstring(dict
, "post_cmd",
113 testcase
->opts
.post_cmd
);
115 err(1, "prop_dictionary operation failed");
118 r
= prop_dictionary_set_uint32(dict
, "runas_uid",
119 (uint32_t)testcase
->opts
.runas_uid
);
121 err(1, "prop_dictionary operation failed");
123 r
= prop_dictionary_set_cstring(dict
, "make_cmd",
124 (testcase
->opts
.make_cmd
!= NULL
) ? testcase
->opts
.make_cmd
: "make");
126 err(1, "prop_dictionary operation failed");
128 r
= prop_dictionary_set(testcase_dict
, "opts", dict
);
130 err(1, "prop_dictionary operation failed");
132 return testcase_dict
;
136 testcase_get_timeout(prop_dictionary_t testcase
)
138 static struct timeval tv
;
142 r
= prop_dictionary_get_int32(prop_dictionary_get(testcase
, "opts"),
143 "timeout_in_secs", &val
);
145 err(1, "prop_dictionary operation failed");
148 tv
.tv_sec
= (long)val
;
154 testcase_get_type(prop_dictionary_t testcase
)
159 r
= prop_dictionary_get_cstring_nocopy(testcase
, "type", &type
);
161 err(1, "prop_dictionary operation failed");
163 if (strcmp(type
, "userland") == 0)
164 return TESTCASE_TYPE_USERLAND
;
165 else if (strcmp(type
, "kernel") == 0)
166 return TESTCASE_TYPE_KERNEL
;
167 else if (strcmp(type
, "buildonly") == 0)
168 return TESTCASE_TYPE_BUILDONLY
;
174 testcase_get_type_desc(prop_dictionary_t testcase
)
179 r
= prop_dictionary_get_cstring_nocopy(testcase
, "type", &str
);
181 err(1, "prop_dictionary operation failed");
187 testcase_get_name(prop_dictionary_t testcase
)
192 r
= prop_dictionary_get_cstring_nocopy(testcase
, "name", &str
);
194 err(1, "prop_dictionary operation failed");
200 testcase_get_args(prop_dictionary_t testcase
)
202 /* Sane limit of 63 arguments... who wants more than that? */
203 static const char *argv
[64];
204 unsigned int i
, count
;
208 a
= prop_dictionary_get(testcase
, "args");
210 err(1, "testcase_get_args NULL array");
212 count
= prop_array_count(a
);
214 for (i
= 0; i
< count
; i
++) {
215 r
= prop_array_get_cstring_nocopy(a
, i
, &argv
[i
]);
217 err(1, "error building argv");
226 testcase_get_flags(prop_dictionary_t testcase
)
231 r
= prop_dictionary_get_uint32(prop_dictionary_get(testcase
, "opts"),
234 err(1, "prop_dictionary operation failed");
240 testcase_get_precmd_type(prop_dictionary_t testcase
)
242 uint32_t flags
= testcase_get_flags(testcase
);
244 return (flags
& (TESTCASE_INT_PRE
| TESTCASE_CUSTOM_PRE
));
248 testcase_get_postcmd_type(prop_dictionary_t testcase
)
250 uint32_t flags
= testcase_get_flags(testcase
);
252 return (flags
& (TESTCASE_INT_POST
| TESTCASE_CUSTOM_POST
));
256 testcase_needs_setuid(prop_dictionary_t testcase
)
258 uint32_t flags
= testcase_get_flags(testcase
);
260 return (flags
& TESTCASE_RUN_AS
);
264 testcase_get_runas_uid(prop_dictionary_t testcase
)
269 r
= prop_dictionary_get_uint32(
270 prop_dictionary_get(testcase
, "opts"), "runas_uid", &uid
);
272 err(1, "prop_dictionary operation failed");
278 testcase_get_custom_precmd(prop_dictionary_t testcase
)
283 r
= prop_dictionary_get_cstring_nocopy(
284 prop_dictionary_get(testcase
, "opts"), "pre_cmd", &str
);
286 err(1, "prop_dictionary operation failed");
292 testcase_get_custom_postcmd(prop_dictionary_t testcase
)
297 r
= prop_dictionary_get_cstring_nocopy(
298 prop_dictionary_get(testcase
, "opts"), "pre_cmd", &str
);
300 err(1, "prop_dictionary operation failed");
306 testcase_get_make_cmd(prop_dictionary_t testcase
)
311 r
= prop_dictionary_get_cstring_nocopy(
312 prop_dictionary_get(testcase
, "opts"), "make_cmd", &str
);
314 err(1, "prop_dictionary operation failed");
320 testcase_get_result_dict(prop_dictionary_t testcase
)
322 prop_dictionary_t result_dict
;
325 result_dict
= prop_dictionary_get(testcase
, "result");
326 if (result_dict
== NULL
) {
327 result_dict
= prop_dictionary_create();
328 if (result_dict
== NULL
)
329 err(1, "could not allocate new result dict");
331 r
= prop_dictionary_set(testcase
, "result", result_dict
);
333 err(1, "prop_dictionary operation failed");
340 testcase_set_build_buf(prop_dictionary_t testcase
, const char *buf
)
342 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
344 return !prop_dictionary_set_cstring(dict
, "build_buf", buf
);
348 testcase_set_cleanup_buf(prop_dictionary_t testcase
, const char *buf
)
350 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
352 return !prop_dictionary_set_cstring(dict
, "cleanup_buf", buf
);
356 testcase_set_sys_buf(prop_dictionary_t testcase
, const char *buf
)
358 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
360 return !prop_dictionary_set_cstring(dict
, "sys_buf", buf
);
364 testcase_set_precmd_buf(prop_dictionary_t testcase
, const char *buf
)
366 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
368 return !prop_dictionary_set_cstring(dict
, "precmd_buf", buf
);
372 testcase_set_postcmd_buf(prop_dictionary_t testcase
, const char *buf
)
374 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
376 return !prop_dictionary_set_cstring(dict
, "postcmd_buf", buf
);
380 testcase_set_stdout_buf(prop_dictionary_t testcase
, const char *buf
)
382 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
384 return !prop_dictionary_set_cstring(dict
, "stdout_buf", buf
);
388 testcase_set_stderr_buf(prop_dictionary_t testcase
, const char *buf
)
390 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
392 return !prop_dictionary_set_cstring(dict
, "stderr_buf", buf
);
396 testcase_set_result(prop_dictionary_t testcase
, int result
)
398 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
400 return !prop_dictionary_set_int32(dict
, "result", result
);
404 testcase_set_exit_value(prop_dictionary_t testcase
, int exitval
)
406 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
408 return !prop_dictionary_set_int32(dict
, "exit_value", exitval
);
412 testcase_set_signal(prop_dictionary_t testcase
, int sig
)
414 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
416 return !prop_dictionary_set_int32(dict
, "signal", sig
);
420 testcase_get_build_buf(prop_dictionary_t testcase
)
422 const char *str
= "";
424 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
425 prop_dictionary_get_cstring_nocopy(dict
, "build_buf", &str
);
431 testcase_get_cleanup_buf(prop_dictionary_t testcase
)
433 const char *str
= "";
435 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
436 prop_dictionary_get_cstring_nocopy(dict
, "cleanup_buf", &str
);
442 testcase_get_sys_buf(prop_dictionary_t testcase
)
444 const char *str
= "";
446 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
447 prop_dictionary_get_cstring_nocopy(dict
, "sys_buf", &str
);
453 testcase_get_precmd_buf(prop_dictionary_t testcase
)
455 const char *str
= "";
457 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
458 prop_dictionary_get_cstring_nocopy(dict
, "precmd_buf", &str
);
464 testcase_get_postcmd_buf(prop_dictionary_t testcase
)
466 const char *str
= "";
468 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
469 prop_dictionary_get_cstring_nocopy(dict
, "postcmd_buf", &str
);
475 testcase_get_stdout_buf(prop_dictionary_t testcase
)
477 const char *str
= "";
479 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
480 prop_dictionary_get_cstring_nocopy(dict
, "stdout_buf", &str
);
486 testcase_get_stderr_buf(prop_dictionary_t testcase
)
488 const char *str
= "";
490 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
491 prop_dictionary_get_cstring_nocopy(dict
, "stderr_buf", &str
);
497 testcase_get_result(prop_dictionary_t testcase
)
499 int32_t result
= RESULT_NOTRUN
;
501 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
502 prop_dictionary_get_int32(dict
, "result", &result
);
508 testcase_get_result_desc(prop_dictionary_t testcase
)
510 int result
= testcase_get_result(testcase
);
513 case RESULT_TIMEOUT
: return "TIMEOUT";
514 case RESULT_SIGNALLED
: return "SIGNALLED";
515 case RESULT_NOTRUN
: return "NOT RUN";
516 case RESULT_FAIL
: return "FAIL";
517 case RESULT_PASS
: return "PASS";
518 case RESULT_PREFAIL
: return "PREFAIL";
519 case RESULT_POSTFAIL
: return "POSTFAIL";
520 case RESULT_BUILDFAIL
: return "BUILDFAIL";
521 default: return "UNKNOWN";
526 testcase_get_exit_value(prop_dictionary_t testcase
)
531 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
532 r
= prop_dictionary_get_int32(dict
, "exit_value", &exitval
);
534 err(1, "prop_dictionary operation failed");
540 testcase_get_signal(prop_dictionary_t testcase
)
545 prop_dictionary_t dict
= testcase_get_result_dict(testcase
);
546 r
= prop_dictionary_get_int32(dict
, "signal", &sig
);
548 err(1, "prop_dictionary operation failed");
554 parse_testcase_option(struct testcase_options
*opts
, char *option
)
557 char *parameter
, *endptr
;
561 parameter
= strchr(option
, '=');
562 noparam
= (parameter
== NULL
);
569 if (strcmp(option
, "timeout") == 0) {
571 syntax_error("The option 'timeout' needs a parameter");
574 lval
= strtol(parameter
, &endptr
, 10);
576 syntax_error("The option 'timeout' expects an integer "
577 "parameter, not '%s'", parameter
);
580 opts
->timeout_in_secs
= (long int)lval
;
581 } else if (strcmp(option
, "intpre") == 0) {
582 opts
->flags
|= TESTCASE_INT_PRE
;
583 } else if (strcmp(option
, "intpost") == 0) {
584 opts
->flags
|= TESTCASE_INT_POST
;
585 } else if (strcmp(option
, "pre") == 0) {
587 syntax_error("The option 'pre' needs a parameter");
590 opts
->flags
|= TESTCASE_CUSTOM_PRE
;
591 opts
->pre_cmd
= strdup(parameter
);
592 } else if (strcmp(option
, "post") == 0) {
594 syntax_error("The option 'post' needs a parameter");
597 opts
->flags
|= TESTCASE_CUSTOM_POST
;
598 opts
->post_cmd
= strdup(parameter
);
599 } else if (strcmp(option
, "runas") == 0) {
601 syntax_error("The option 'runas' needs a parameter");
604 if ((pwd
= getpwnam(parameter
))) {
605 opts
->runas_uid
= pwd
->pw_uid
;
606 opts
->flags
|= TESTCASE_RUN_AS
;
608 syntax_error("invalid user name for 'runas': %s",
611 } else if (strcmp(option
, "nobuild") == 0) {
612 opts
->flags
|= TESTCASE_NOBUILD
;
613 } else if (strcmp(option
, "make") == 0) {
615 syntax_error("The option 'make' needs a parameter");
618 opts
->make_cmd
= strdup(parameter
);
619 } else if (strcmp(option
, "defaults") == 0) {
620 /* Valid option, does nothing */
622 syntax_error("Unknown option: %s", option
);
630 testcase_entry_parser(void *arg
, char **tokens
)
632 prop_array_t runlist
;
633 prop_dictionary_t testcase_dict
;
634 struct testcase
*testcase
;
638 runlist
= (prop_array_t
)arg
;
640 testcase
= malloc(sizeof(struct testcase
));
641 if (testcase
== NULL
)
642 err(1, "could not malloc testcase memory");
644 bzero(testcase
, sizeof(struct testcase
));
646 entry_check_num_args(tokens
, 3);
648 testcase
->argv
= &tokens
[3];
649 for (testcase
->argc
= 0; testcase
->argv
[testcase
->argc
] != NULL
;
653 nopts
= parse_options(tokens
[2], options
);
655 testcase
->name
= tokens
[0];
657 if (strcmp(tokens
[1], "userland") == 0) {
658 testcase
->type
= TESTCASE_TYPE_USERLAND
;
659 } else if (strcmp(tokens
[1], "kernel") == 0) {
660 testcase
->type
= TESTCASE_TYPE_KERNEL
;
661 } else if (strcmp(tokens
[1], "buildonly") == 0) {
662 testcase
->type
= TESTCASE_TYPE_BUILDONLY
;
664 syntax_error("Unknown type: %s", tokens
[1]);
668 testcase
->type_str
= tokens
[1];
670 config_get_defaults(&testcase
->opts
);
672 for (i
= 0; i
< nopts
; i
++)
673 parse_testcase_option(&testcase
->opts
, options
[i
]);
675 if ((testcase
->type
!= TESTCASE_TYPE_USERLAND
) &&
676 (testcase
->opts
.flags
& (TESTCASE_INT_PRE
| TESTCASE_INT_POST
)))
677 syntax_error("'intpre' and 'intpost' options are only valid "
678 "with testcase type 'userland'");
680 if ((testcase
->type
== TESTCASE_TYPE_BUILDONLY
) &&
681 (testcase
->opts
.flags
& TESTCASE_NOBUILD
))
682 syntax_error("'nobuild' option is incompatible with type "
685 testcase_dict
= testcase_from_struct(testcase
);
686 if (testcase
->opts
.pre_cmd
!= NULL
)
687 free(testcase
->opts
.pre_cmd
);
688 if (testcase
->opts
.post_cmd
!= NULL
)
689 free(testcase
->opts
.post_cmd
);
690 if (testcase
->opts
.make_cmd
!= NULL
)
691 free(testcase
->opts
.make_cmd
);
694 r
= prop_array_add(runlist
, testcase_dict
);
696 err(1, "prop_array_add failed");