1a563ca70SAlex Hornung /*
2a563ca70SAlex Hornung * Copyright (c) 2011 Alex Hornung <alex@alexhornung.com>.
3a563ca70SAlex Hornung * All rights reserved.
4a563ca70SAlex Hornung *
5a563ca70SAlex Hornung * Redistribution and use in source and binary forms, with or without
6a563ca70SAlex Hornung * modification, are permitted provided that the following conditions
7a563ca70SAlex Hornung * are met:
8a563ca70SAlex Hornung *
9a563ca70SAlex Hornung * 1. Redistributions of source code must retain the above copyright
10a563ca70SAlex Hornung * notice, this list of conditions and the following disclaimer.
11a563ca70SAlex Hornung * 2. Redistributions in binary form must reproduce the above copyright
12a563ca70SAlex Hornung * notice, this list of conditions and the following disclaimer in
13a563ca70SAlex Hornung * the documentation and/or other materials provided with the
14a563ca70SAlex Hornung * distribution.
15a563ca70SAlex Hornung *
16a563ca70SAlex Hornung * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17a563ca70SAlex Hornung * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18a563ca70SAlex Hornung * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19a563ca70SAlex Hornung * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20a563ca70SAlex Hornung * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21a563ca70SAlex Hornung * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
22a563ca70SAlex Hornung * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23a563ca70SAlex Hornung * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24a563ca70SAlex Hornung * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25a563ca70SAlex Hornung * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26a563ca70SAlex Hornung * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27a563ca70SAlex Hornung * SUCH DAMAGE.
28a563ca70SAlex Hornung */
29a563ca70SAlex Hornung
30a563ca70SAlex Hornung #include <sys/resource.h>
31a563ca70SAlex Hornung #include <sys/time.h>
32a563ca70SAlex Hornung #include <sys/types.h>
33a563ca70SAlex Hornung #include <sys/wait.h>
34a563ca70SAlex Hornung
35a563ca70SAlex Hornung #include <errno.h>
368135efafSAlex Hornung #include <limits.h>
37a563ca70SAlex Hornung #include <fcntl.h>
38a563ca70SAlex Hornung #include <signal.h>
39a563ca70SAlex Hornung #include <stdio.h>
40a563ca70SAlex Hornung #include <stdlib.h>
41a563ca70SAlex Hornung #include <stdint.h>
42a563ca70SAlex Hornung #include <string.h>
43a563ca70SAlex Hornung #include <unistd.h>
44a563ca70SAlex Hornung #include <pwd.h>
45a563ca70SAlex Hornung
46a563ca70SAlex Hornung #include <err.h>
47a563ca70SAlex Hornung
48a563ca70SAlex Hornung #include <libprop/proplib.h>
49a563ca70SAlex Hornung
50a563ca70SAlex Hornung #include "parser.h"
51a563ca70SAlex Hornung #include "testcase.h"
52a563ca70SAlex Hornung #include "runlist.h"
53a563ca70SAlex Hornung #include "userland.h"
54a563ca70SAlex Hornung #include "kernel.h"
55a563ca70SAlex Hornung #include <dfregress.h>
56a563ca70SAlex Hornung
578135efafSAlex Hornung char output_file[PATH_MAX+1];
588135efafSAlex Hornung char testcase_dir[PATH_MAX+1];
598135efafSAlex Hornung char prepost_dir[PATH_MAX+1];
60a563ca70SAlex Hornung
61a563ca70SAlex Hornung prop_array_t
runlist_load_from_text(const char * runlist_file)62a563ca70SAlex Hornung runlist_load_from_text(const char *runlist_file)
63a563ca70SAlex Hornung {
64a563ca70SAlex Hornung prop_array_t runlist;
65a563ca70SAlex Hornung
66a563ca70SAlex Hornung runlist = prop_array_create_with_capacity(2048);
67a563ca70SAlex Hornung
68a563ca70SAlex Hornung process_file(runlist_file, testcase_entry_parser, runlist, NULL);
69a563ca70SAlex Hornung
70a563ca70SAlex Hornung return runlist;
71a563ca70SAlex Hornung }
72a563ca70SAlex Hornung
73a563ca70SAlex Hornung prop_array_t
runlist_load(const char * runlist_file)74a563ca70SAlex Hornung runlist_load(const char *runlist_file)
75a563ca70SAlex Hornung {
76a563ca70SAlex Hornung return prop_array_internalize_from_file(runlist_file);
77a563ca70SAlex Hornung }
78a563ca70SAlex Hornung
79a563ca70SAlex Hornung int
runlist_save(const char * runlist_file,prop_array_t runlist)80a563ca70SAlex Hornung runlist_save(const char *runlist_file, prop_array_t runlist)
81a563ca70SAlex Hornung {
82a563ca70SAlex Hornung return !prop_array_externalize_to_file(runlist, runlist_file);
83a563ca70SAlex Hornung }
84a563ca70SAlex Hornung
85a563ca70SAlex Hornung int
runlist_iterate(prop_array_t runlist,runlist_iterator_t iterator,void * arg)86a563ca70SAlex Hornung runlist_iterate(prop_array_t runlist, runlist_iterator_t iterator, void *arg)
87a563ca70SAlex Hornung {
88a563ca70SAlex Hornung prop_object_iterator_t it;
89a563ca70SAlex Hornung prop_dictionary_t testcase;
90a563ca70SAlex Hornung int r = 0;
91a563ca70SAlex Hornung
92a563ca70SAlex Hornung it = prop_array_iterator(runlist);
93a563ca70SAlex Hornung if (it == NULL)
94a563ca70SAlex Hornung err(1, "could not get runlist iterator");
95a563ca70SAlex Hornung
96a563ca70SAlex Hornung while ((testcase = prop_object_iterator_next(it)) != NULL) {
97a563ca70SAlex Hornung r = iterator(arg, testcase);
98a563ca70SAlex Hornung if (r != 0)
99a563ca70SAlex Hornung break;
100a563ca70SAlex Hornung }
101a563ca70SAlex Hornung
102a563ca70SAlex Hornung prop_object_iterator_release(it);
103a563ca70SAlex Hornung return r;
104a563ca70SAlex Hornung }
105a563ca70SAlex Hornung
106a563ca70SAlex Hornung int
runlist_run_test(void * arg,prop_dictionary_t testcase)107a563ca70SAlex Hornung runlist_run_test(void *arg, prop_dictionary_t testcase)
108a563ca70SAlex Hornung {
109a563ca70SAlex Hornung prop_array_t runlist = (prop_array_t)arg;
110a563ca70SAlex Hornung struct testcase_result tr;
111f9bb9655Szrj char testcase_path[FILENAME_MAX+2];
112a563ca70SAlex Hornung char testcase_dir_only[FILENAME_MAX];
113f9bb9655Szrj char prepost_path[FILENAME_MAX+2];
114a563ca70SAlex Hornung char errbuf[FILENAME_MAX*2];
115a563ca70SAlex Hornung int r, nopre, nopost;
116a563ca70SAlex Hornung char *str;
117a563ca70SAlex Hornung
118a563ca70SAlex Hornung sprintf(testcase_path, "%s/%s", testcase_dir,
119a563ca70SAlex Hornung testcase_get_name(testcase));
120a563ca70SAlex Hornung strcpy(testcase_dir_only, testcase_path);
121a563ca70SAlex Hornung str = strrchr(testcase_dir_only, '/');
122a563ca70SAlex Hornung if (str != NULL)
123a563ca70SAlex Hornung *str = '\0';
124a563ca70SAlex Hornung
1258135efafSAlex Hornung printf("Running testcase %s... ", testcase_get_name(testcase));
1268135efafSAlex Hornung fflush(stdout);
1278135efafSAlex Hornung
128a563ca70SAlex Hornung /* Switch to testcase directory */
129a563ca70SAlex Hornung r = chdir(testcase_dir_only);
130a563ca70SAlex Hornung if (r < 0) {
131a563ca70SAlex Hornung sprintf(errbuf, "could not switch working directory to %s: %s\n",
132a563ca70SAlex Hornung testcase_dir_only, strerror(errno));
133a563ca70SAlex Hornung testcase_set_result(testcase, RESULT_PREFAIL);
134a563ca70SAlex Hornung testcase_set_sys_buf(testcase, errbuf);
135a563ca70SAlex Hornung goto out;
136a563ca70SAlex Hornung }
137a563ca70SAlex Hornung
138a563ca70SAlex Hornung /* build unless nobuild flag is set */
139a563ca70SAlex Hornung if ((testcase_get_flags(testcase) & TESTCASE_NOBUILD) == 0) {
140a563ca70SAlex Hornung r = run_simple_cmd(testcase_get_make_cmd(testcase), NULL,
141a563ca70SAlex Hornung errbuf, sizeof(errbuf), &tr);
142a563ca70SAlex Hornung if (r != 0) {
143a563ca70SAlex Hornung testcase_set_sys_buf(testcase, errbuf);
144a563ca70SAlex Hornung testcase_set_result(testcase, RESULT_PREFAIL);
145a563ca70SAlex Hornung goto out;
146a563ca70SAlex Hornung }
147a563ca70SAlex Hornung
148a563ca70SAlex Hornung if (tr.stdout_buf != NULL) {
149a563ca70SAlex Hornung testcase_set_build_buf(testcase, tr.stdout_buf);
150a563ca70SAlex Hornung free(tr.stdout_buf);
151a563ca70SAlex Hornung }
152a563ca70SAlex Hornung
153a563ca70SAlex Hornung if (tr.result != RESULT_PASS) {
154a563ca70SAlex Hornung if (testcase_get_type(testcase)
155a563ca70SAlex Hornung == TESTCASE_TYPE_BUILDONLY)
156a563ca70SAlex Hornung testcase_set_result(testcase, tr.result);
157a563ca70SAlex Hornung else
158a563ca70SAlex Hornung testcase_set_result(testcase, RESULT_BUILDFAIL);
159a563ca70SAlex Hornung
160a563ca70SAlex Hornung testcase_set_exit_value(testcase, tr.exit_value);
161a563ca70SAlex Hornung testcase_set_signal(testcase, tr.signal);
162a563ca70SAlex Hornung
163a563ca70SAlex Hornung goto out;
164a563ca70SAlex Hornung }
165a563ca70SAlex Hornung }
166a563ca70SAlex Hornung
167a563ca70SAlex Hornung
168a563ca70SAlex Hornung /* Pre-execution run */
169a563ca70SAlex Hornung switch (testcase_get_precmd_type(testcase)) {
170a563ca70SAlex Hornung case TESTCASE_INT_PRE:
171a563ca70SAlex Hornung /* Test case has internal but explicit PRE - code */
172a563ca70SAlex Hornung r = run_simple_cmd(testcase_path, "pre", errbuf,
173a563ca70SAlex Hornung sizeof(errbuf), &tr);
174a563ca70SAlex Hornung nopre = 0;
175a563ca70SAlex Hornung break;
176a563ca70SAlex Hornung
177a563ca70SAlex Hornung case TESTCASE_CUSTOM_PRE:
178a563ca70SAlex Hornung /* Test case uses external and explicit PRE command */
179a563ca70SAlex Hornung sprintf(prepost_path, "%s/%s", prepost_dir,
180a563ca70SAlex Hornung testcase_get_custom_precmd(testcase));
181a563ca70SAlex Hornung
182a563ca70SAlex Hornung r = run_simple_cmd(prepost_path, NULL, errbuf, sizeof(errbuf),
183a563ca70SAlex Hornung &tr);
184a563ca70SAlex Hornung nopre = 0;
185a563ca70SAlex Hornung break;
186a563ca70SAlex Hornung
187a563ca70SAlex Hornung default:
188a563ca70SAlex Hornung nopre = 1;
189a563ca70SAlex Hornung r = 0;
190a563ca70SAlex Hornung break;
191a563ca70SAlex Hornung }
192a563ca70SAlex Hornung
193a563ca70SAlex Hornung if (!nopre) {
194a563ca70SAlex Hornung if (r != 0) {
195a563ca70SAlex Hornung testcase_set_sys_buf(testcase, errbuf);
196a563ca70SAlex Hornung testcase_set_result(testcase, RESULT_PREFAIL);
197a563ca70SAlex Hornung goto out;
198a563ca70SAlex Hornung }
199a563ca70SAlex Hornung
200a563ca70SAlex Hornung if (tr.stdout_buf != NULL) {
201a563ca70SAlex Hornung testcase_set_precmd_buf(testcase, tr.stdout_buf);
202a563ca70SAlex Hornung free(tr.stdout_buf);
203a563ca70SAlex Hornung }
204a563ca70SAlex Hornung
205a563ca70SAlex Hornung if (tr.result != RESULT_PASS) {
206a563ca70SAlex Hornung testcase_set_result(testcase, RESULT_PREFAIL);
207a563ca70SAlex Hornung goto out;
208a563ca70SAlex Hornung }
209a563ca70SAlex Hornung }
210a563ca70SAlex Hornung
211a563ca70SAlex Hornung switch (testcase_get_type(testcase)) {
212a563ca70SAlex Hornung case TESTCASE_TYPE_BUILDONLY:
213a563ca70SAlex Hornung testcase_set_result(testcase, RESULT_PASS);
214a563ca70SAlex Hornung testcase_set_exit_value(testcase, 0);
215a563ca70SAlex Hornung break;
216a563ca70SAlex Hornung
217a563ca70SAlex Hornung case TESTCASE_TYPE_USERLAND:
218a563ca70SAlex Hornung /* Main testcase execution */
2190d575305SAntonio Huete Jimenez r = run_userland(testcase_path,
2200d575305SAntonio Huete Jimenez testcase_get_argc(testcase),
2210d575305SAntonio Huete Jimenez testcase_get_args(testcase),
2220d575305SAntonio Huete Jimenez testcase_get_interpreter_noexit(testcase),
223a563ca70SAlex Hornung testcase_needs_setuid(testcase),
224a563ca70SAlex Hornung testcase_get_runas_uid(testcase),
225*039caa27SAntonio Huete Jimenez testcase_get_timeout(testcase),
226*039caa27SAntonio Huete Jimenez testcase_get_rc(testcase),
227*039caa27SAntonio Huete Jimenez 0, errbuf, sizeof(errbuf), &tr);
228a563ca70SAlex Hornung
229a563ca70SAlex Hornung if (r == 0) {
230a563ca70SAlex Hornung testcase_set_result(testcase, tr.result);
231a563ca70SAlex Hornung testcase_set_exit_value(testcase, tr.exit_value);
232a563ca70SAlex Hornung testcase_set_signal(testcase, tr.signal);
233a563ca70SAlex Hornung
234a563ca70SAlex Hornung if (tr.stdout_buf != NULL) {
235a563ca70SAlex Hornung testcase_set_stdout_buf(testcase, tr.stdout_buf);
236a563ca70SAlex Hornung free(tr.stdout_buf);
237a563ca70SAlex Hornung }
238a563ca70SAlex Hornung
239a563ca70SAlex Hornung if (tr.stderr_buf != NULL) {
240a563ca70SAlex Hornung testcase_set_stderr_buf(testcase, tr.stderr_buf);
241a563ca70SAlex Hornung free(tr.stderr_buf);
242a563ca70SAlex Hornung }
243a563ca70SAlex Hornung } else {
244a563ca70SAlex Hornung /* driver/monitor error */
245a563ca70SAlex Hornung testcase_set_sys_buf(testcase, errbuf);
246a563ca70SAlex Hornung }
247a563ca70SAlex Hornung
248a563ca70SAlex Hornung break;
249a563ca70SAlex Hornung
250a563ca70SAlex Hornung case TESTCASE_TYPE_KERNEL:
251a563ca70SAlex Hornung run_kernel(testcase_path, testcase);
252a563ca70SAlex Hornung break;
253a563ca70SAlex Hornung }
254a563ca70SAlex Hornung
255a563ca70SAlex Hornung
256a563ca70SAlex Hornung /* Post-execution run */
257a563ca70SAlex Hornung switch (testcase_get_postcmd_type(testcase)) {
258a563ca70SAlex Hornung case TESTCASE_INT_POST:
259a563ca70SAlex Hornung /* Test case has internal but explicit POST - code */
260a563ca70SAlex Hornung r = run_simple_cmd(testcase_path, "post", errbuf,
261a563ca70SAlex Hornung sizeof(errbuf), &tr);
262a563ca70SAlex Hornung nopost = 0;
263a563ca70SAlex Hornung break;
264a563ca70SAlex Hornung
265a563ca70SAlex Hornung case TESTCASE_CUSTOM_POST:
266a563ca70SAlex Hornung /* Test case uses external and explicit POST command */
267a563ca70SAlex Hornung sprintf(prepost_path, "%s/%s", prepost_dir,
268a563ca70SAlex Hornung testcase_get_custom_postcmd(testcase));
269a563ca70SAlex Hornung
270a563ca70SAlex Hornung r = run_simple_cmd(prepost_path, NULL, errbuf, sizeof(errbuf),
271a563ca70SAlex Hornung &tr);
272a563ca70SAlex Hornung nopost = 0;
273a563ca70SAlex Hornung break;
274a563ca70SAlex Hornung
275a563ca70SAlex Hornung default:
276a563ca70SAlex Hornung r = 0;
277a563ca70SAlex Hornung nopost = 1;
278a563ca70SAlex Hornung break;
279a563ca70SAlex Hornung }
280a563ca70SAlex Hornung
281a563ca70SAlex Hornung if (!nopost) {
282a563ca70SAlex Hornung if (r != 0) {
283a563ca70SAlex Hornung testcase_set_sys_buf(testcase, errbuf);
284a563ca70SAlex Hornung testcase_set_result(testcase, RESULT_POSTFAIL);
285a563ca70SAlex Hornung goto out;
286a563ca70SAlex Hornung }
287a563ca70SAlex Hornung
288a563ca70SAlex Hornung if (tr.stdout_buf != NULL) {
289a563ca70SAlex Hornung testcase_set_postcmd_buf(testcase, tr.stdout_buf);
290a563ca70SAlex Hornung free(tr.stdout_buf);
291a563ca70SAlex Hornung }
292a563ca70SAlex Hornung
293a563ca70SAlex Hornung if (tr.result != RESULT_PASS) {
294a563ca70SAlex Hornung testcase_set_result(testcase, RESULT_POSTFAIL);
295a563ca70SAlex Hornung goto out;
296a563ca70SAlex Hornung }
297a563ca70SAlex Hornung }
298a563ca70SAlex Hornung
299a563ca70SAlex Hornung
300a563ca70SAlex Hornung
301a563ca70SAlex Hornung out:
302a563ca70SAlex Hornung /* clean build unless nobuild flag is set */
303a563ca70SAlex Hornung if ((testcase_get_flags(testcase) & TESTCASE_NOBUILD) == 0) {
304a563ca70SAlex Hornung r = run_simple_cmd(testcase_get_make_cmd(testcase), "clean",
305a563ca70SAlex Hornung errbuf, sizeof(errbuf), &tr);
306a563ca70SAlex Hornung
307a563ca70SAlex Hornung if (tr.stdout_buf != NULL) {
308a563ca70SAlex Hornung testcase_set_cleanup_buf(testcase, tr.stdout_buf);
309a563ca70SAlex Hornung free(tr.stdout_buf);
310a563ca70SAlex Hornung }
311a563ca70SAlex Hornung
312a563ca70SAlex Hornung if (r != 0)
313a563ca70SAlex Hornung testcase_set_cleanup_buf(testcase, errbuf);
314a563ca70SAlex Hornung }
315a563ca70SAlex Hornung
316a563ca70SAlex Hornung
317a563ca70SAlex Hornung /* ... and save results */
318a563ca70SAlex Hornung runlist_save(output_file, runlist);
3198135efafSAlex Hornung
3208135efafSAlex Hornung printf("done.\n");
321a563ca70SAlex Hornung return 0;
322a563ca70SAlex Hornung }
323*039caa27SAntonio Huete Jimenez
324