xref: /dragonfly/usr.bin/dfregress/runlist.c (revision 039caa2712bab592ce22f44947164503333880a1)
1 /*
2  * Copyright (c) 2011 Alex Hornung <alex@alexhornung.com>.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
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
14  *    distribution.
15  *
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
27  * SUCH DAMAGE.
28  */
29 
30 #include <sys/resource.h>
31 #include <sys/time.h>
32 #include <sys/types.h>
33 #include <sys/wait.h>
34 
35 #include <errno.h>
36 #include <limits.h>
37 #include <fcntl.h>
38 #include <signal.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <stdint.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <pwd.h>
45 
46 #include <err.h>
47 
48 #include <libprop/proplib.h>
49 
50 #include "parser.h"
51 #include "testcase.h"
52 #include "runlist.h"
53 #include "userland.h"
54 #include "kernel.h"
55 #include <dfregress.h>
56 
57 char output_file[PATH_MAX+1];
58 char testcase_dir[PATH_MAX+1];
59 char prepost_dir[PATH_MAX+1];
60 
61 prop_array_t
runlist_load_from_text(const char * runlist_file)62 runlist_load_from_text(const char *runlist_file)
63 {
64           prop_array_t runlist;
65 
66           runlist = prop_array_create_with_capacity(2048);
67 
68           process_file(runlist_file, testcase_entry_parser, runlist, NULL);
69 
70           return runlist;
71 }
72 
73 prop_array_t
runlist_load(const char * runlist_file)74 runlist_load(const char *runlist_file)
75 {
76           return prop_array_internalize_from_file(runlist_file);
77 }
78 
79 int
runlist_save(const char * runlist_file,prop_array_t runlist)80 runlist_save(const char *runlist_file, prop_array_t runlist)
81 {
82           return !prop_array_externalize_to_file(runlist, runlist_file);
83 }
84 
85 int
runlist_iterate(prop_array_t runlist,runlist_iterator_t iterator,void * arg)86 runlist_iterate(prop_array_t runlist, runlist_iterator_t iterator, void *arg)
87 {
88           prop_object_iterator_t it;
89           prop_dictionary_t testcase;
90           int r = 0;
91 
92           it = prop_array_iterator(runlist);
93           if (it == NULL)
94                     err(1, "could not get runlist iterator");
95 
96           while ((testcase = prop_object_iterator_next(it)) != NULL) {
97                     r = iterator(arg, testcase);
98                     if (r != 0)
99                               break;
100           }
101 
102           prop_object_iterator_release(it);
103           return r;
104 }
105 
106 int
runlist_run_test(void * arg,prop_dictionary_t testcase)107 runlist_run_test(void *arg, prop_dictionary_t testcase)
108 {
109           prop_array_t runlist = (prop_array_t)arg;
110           struct testcase_result tr;
111           char testcase_path[FILENAME_MAX+2];
112           char testcase_dir_only[FILENAME_MAX];
113           char prepost_path[FILENAME_MAX+2];
114           char errbuf[FILENAME_MAX*2];
115           int r, nopre, nopost;
116           char *str;
117 
118           sprintf(testcase_path, "%s/%s", testcase_dir,
119               testcase_get_name(testcase));
120           strcpy(testcase_dir_only, testcase_path);
121           str = strrchr(testcase_dir_only, '/');
122           if (str != NULL)
123                     *str = '\0';
124 
125           printf("Running testcase %s... ", testcase_get_name(testcase));
126           fflush(stdout);
127 
128           /* Switch to testcase directory */
129           r = chdir(testcase_dir_only);
130           if (r < 0) {
131                     sprintf(errbuf, "could not switch working directory to %s: %s\n",
132                         testcase_dir_only, strerror(errno));
133                     testcase_set_result(testcase, RESULT_PREFAIL);
134                     testcase_set_sys_buf(testcase, errbuf);
135                     goto out;
136           }
137 
138           /* build unless nobuild flag is set */
139           if ((testcase_get_flags(testcase) & TESTCASE_NOBUILD) == 0) {
140                     r = run_simple_cmd(testcase_get_make_cmd(testcase), NULL,
141                         errbuf, sizeof(errbuf), &tr);
142                     if (r != 0) {
143                               testcase_set_sys_buf(testcase, errbuf);
144                               testcase_set_result(testcase, RESULT_PREFAIL);
145                               goto out;
146                     }
147 
148                     if (tr.stdout_buf != NULL) {
149                               testcase_set_build_buf(testcase, tr.stdout_buf);
150                               free(tr.stdout_buf);
151                     }
152 
153                     if (tr.result != RESULT_PASS) {
154                               if (testcase_get_type(testcase)
155                                   == TESTCASE_TYPE_BUILDONLY)
156                                         testcase_set_result(testcase, tr.result);
157                               else
158                                         testcase_set_result(testcase, RESULT_BUILDFAIL);
159 
160                               testcase_set_exit_value(testcase, tr.exit_value);
161                               testcase_set_signal(testcase, tr.signal);
162 
163                               goto out;
164                     }
165           }
166 
167 
168           /* Pre-execution run */
169           switch (testcase_get_precmd_type(testcase)) {
170           case TESTCASE_INT_PRE:
171                     /* Test case has internal but explicit PRE - code */
172                     r = run_simple_cmd(testcase_path, "pre", errbuf,
173                         sizeof(errbuf), &tr);
174                     nopre = 0;
175                     break;
176 
177           case TESTCASE_CUSTOM_PRE:
178                     /* Test case uses external and explicit PRE command */
179                     sprintf(prepost_path, "%s/%s", prepost_dir,
180                         testcase_get_custom_precmd(testcase));
181 
182                     r = run_simple_cmd(prepost_path, NULL, errbuf, sizeof(errbuf),
183                         &tr);
184                     nopre = 0;
185                     break;
186 
187           default:
188                     nopre = 1;
189                     r = 0;
190                     break;
191           }
192 
193           if (!nopre) {
194                     if (r != 0) {
195                               testcase_set_sys_buf(testcase, errbuf);
196                               testcase_set_result(testcase, RESULT_PREFAIL);
197                               goto out;
198                     }
199 
200                     if (tr.stdout_buf != NULL) {
201                               testcase_set_precmd_buf(testcase, tr.stdout_buf);
202                               free(tr.stdout_buf);
203                     }
204 
205                     if (tr.result != RESULT_PASS) {
206                               testcase_set_result(testcase, RESULT_PREFAIL);
207                               goto out;
208                     }
209           }
210 
211           switch (testcase_get_type(testcase)) {
212           case TESTCASE_TYPE_BUILDONLY:
213                     testcase_set_result(testcase, RESULT_PASS);
214                     testcase_set_exit_value(testcase, 0);
215                     break;
216 
217           case TESTCASE_TYPE_USERLAND:
218                     /* Main testcase execution */
219                     r = run_userland(testcase_path,
220                         testcase_get_argc(testcase),
221                         testcase_get_args(testcase),
222                         testcase_get_interpreter_noexit(testcase),
223                         testcase_needs_setuid(testcase),
224                         testcase_get_runas_uid(testcase),
225                         testcase_get_timeout(testcase),
226                         testcase_get_rc(testcase),
227                         0, errbuf, sizeof(errbuf), &tr);
228 
229                     if (r == 0) {
230                               testcase_set_result(testcase, tr.result);
231                               testcase_set_exit_value(testcase, tr.exit_value);
232                               testcase_set_signal(testcase, tr.signal);
233 
234                               if (tr.stdout_buf != NULL) {
235                                         testcase_set_stdout_buf(testcase, tr.stdout_buf);
236                                         free(tr.stdout_buf);
237                               }
238 
239                               if (tr.stderr_buf != NULL) {
240                                         testcase_set_stderr_buf(testcase, tr.stderr_buf);
241                                         free(tr.stderr_buf);
242                               }
243                     } else {
244                               /* driver/monitor error */
245                               testcase_set_sys_buf(testcase, errbuf);
246                     }
247 
248                     break;
249 
250           case TESTCASE_TYPE_KERNEL:
251                     run_kernel(testcase_path, testcase);
252                     break;
253           }
254 
255 
256           /* Post-execution run */
257           switch (testcase_get_postcmd_type(testcase)) {
258           case TESTCASE_INT_POST:
259                     /* Test case has internal but explicit POST - code */
260                     r = run_simple_cmd(testcase_path, "post", errbuf,
261                         sizeof(errbuf), &tr);
262                     nopost = 0;
263                     break;
264 
265           case TESTCASE_CUSTOM_POST:
266                     /* Test case uses external and explicit POST command */
267                     sprintf(prepost_path, "%s/%s", prepost_dir,
268                         testcase_get_custom_postcmd(testcase));
269 
270                     r = run_simple_cmd(prepost_path, NULL, errbuf, sizeof(errbuf),
271                         &tr);
272                     nopost = 0;
273                     break;
274 
275           default:
276                     r = 0;
277                     nopost = 1;
278                     break;
279           }
280 
281           if (!nopost) {
282                     if (r != 0) {
283                               testcase_set_sys_buf(testcase, errbuf);
284                               testcase_set_result(testcase, RESULT_POSTFAIL);
285                               goto out;
286                     }
287 
288                     if (tr.stdout_buf != NULL) {
289                               testcase_set_postcmd_buf(testcase, tr.stdout_buf);
290                               free(tr.stdout_buf);
291                     }
292 
293                     if (tr.result != RESULT_PASS) {
294                               testcase_set_result(testcase, RESULT_POSTFAIL);
295                               goto out;
296                     }
297           }
298 
299 
300 
301 out:
302           /* clean build unless nobuild flag is set */
303           if ((testcase_get_flags(testcase) & TESTCASE_NOBUILD) == 0) {
304                     r = run_simple_cmd(testcase_get_make_cmd(testcase), "clean",
305                         errbuf, sizeof(errbuf), &tr);
306 
307                     if (tr.stdout_buf != NULL) {
308                               testcase_set_cleanup_buf(testcase, tr.stdout_buf);
309                               free(tr.stdout_buf);
310                     }
311 
312                     if (r != 0)
313                               testcase_set_cleanup_buf(testcase, errbuf);
314           }
315 
316 
317           /* ... and save results */
318           runlist_save(output_file, runlist);
319 
320           printf("done.\n");
321           return 0;
322 }
323 
324