• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <dirent.h>
2 #include <fcntl.h>
3 #include <sys/stat.h>
4 #include <sys/types.h>
5 #include <unistd.h>
6 
7 #include "igt.h"
8 
9 #include "settings.h"
10 #include "job_list.h"
11 #include "executor.h"
12 
13 /*
14  * NOTE: this test is using a lot of variables that are changed in igt_fixture,
15  * igt_subtest_group and igt_subtests blocks but defined outside of them.
16  *
17  * Such variables have to be either non-local or volatile, otherwise their
18  * contents is undefined due to longjmps the framework performs.
19  */
20 
21 static const char testdatadir[] = TESTDATA_DIRECTORY;
22 
igt_assert_eqstr(const char * one,const char * two)23 static void igt_assert_eqstr(const char *one, const char *two)
24 {
25 	if (one == NULL && two == NULL)
26 		return;
27 
28 	igt_assert_f(one != NULL && two != NULL, "Strings differ (one is NULL): %s vs %s\n", one, two);
29 
30 	igt_assert_f(!strcmp(one, two), "Strings differ: '%s' vs '%s'\n", one, two);
31 }
32 
debug_print_executions(struct job_list * list)33 static void debug_print_executions(struct job_list *list)
34 {
35 	size_t i;
36 	int k;
37 
38 	igt_debug("Executions:\n");
39 	for (i = 0; i < list->size; i++) {
40 		struct job_list_entry *entry = &list->entries[i];
41 		igt_debug(" %s\n", entry->binary);
42 		for (k = 0; k < entry->subtest_count; ++k) {
43 			igt_debug("  %s\n", entry->subtests[k]);
44 		}
45 	}
46 
47 }
48 
dump_file(int dirfd,const char * name)49 static char *dump_file(int dirfd, const char *name)
50 {
51 	int fd = openat(dirfd, name, O_RDONLY);
52 	ssize_t s;
53 	char *buf = malloc(256);
54 
55 	if (fd < 0) {
56 		free(buf);
57 		return NULL;
58 	}
59 
60 	s = read(fd, buf, 255);
61 	close(fd);
62 
63 	if (s < 0) {
64 		free(buf);
65 		return NULL;
66 	}
67 
68 	buf[s] = '\0';
69 	return buf;
70 }
71 
job_list_filter_test(const char * name,const char * filterarg1,const char * filterarg2,size_t expected_normal,size_t expected_multiple)72 static void job_list_filter_test(const char *name, const char *filterarg1, const char *filterarg2,
73 				 size_t expected_normal, size_t expected_multiple)
74 {
75 	int multiple;
76 	struct settings *settings = malloc(sizeof(*settings));
77 
78 	igt_fixture
79 		init_settings(settings);
80 
81 	for (multiple = 0; multiple < 2; multiple++) {
82 		igt_subtest_f("job-list-filters-%s-%s", name, multiple ? "multiple" : "normal") {
83 			struct job_list list;
84 			const char *argv[] = { "runner",
85 					       /* Ugly but does the trick */
86 					       multiple ? "--multiple-mode" : "--sync",
87 					       filterarg1, filterarg2,
88 					       testdatadir,
89 					       "path-to-results",
90 			};
91 			bool success = false;
92 			size_t size;
93 
94 			init_job_list(&list);
95 			igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
96 
97 			success = create_job_list(&list, settings);
98 			size = list.size;
99 
100 			if (success)
101 				debug_print_executions(&list);
102 
103 			free_job_list(&list);
104 
105 			igt_assert_f(success, "Job list creation failed\n");
106 			igt_assert_eq(size, multiple ? expected_multiple : expected_normal);
107 		}
108 	}
109 
110 	igt_fixture {
111 		free_settings(settings);
112 		free(settings);
113 	}
114 }
115 
clear_directory_fd(int dirfd)116 static void clear_directory_fd(int dirfd)
117 {
118 	DIR* d;
119 	struct dirent *dirent;
120 
121 	d = fdopendir(dirfd);
122 
123 	if (dirfd < 0 || d == NULL) {
124 		return;
125 	}
126 
127 	while ((dirent = readdir(d)) != NULL) {
128 		if (strcmp(dirent->d_name, ".") &&
129 		    strcmp(dirent->d_name, "..")) {
130 			if (dirent->d_type == DT_REG) {
131 				unlinkat(dirfd, dirent->d_name, 0);
132 			} else if (dirent->d_type == DT_DIR) {
133 				clear_directory_fd(openat(dirfd, dirent->d_name, O_DIRECTORY | O_RDONLY));
134 				unlinkat(dirfd, dirent->d_name, AT_REMOVEDIR);
135 			}
136 		}
137 	}
138 
139 	closedir(d);
140 }
141 
clear_directory(char * name)142 static void clear_directory(char *name)
143 {
144 	int dirfd = open(name, O_DIRECTORY | O_RDONLY);
145 	clear_directory_fd(dirfd);
146 	rmdir(name);
147 }
148 
assert_settings_equal(struct settings * one,struct settings * two)149 static void assert_settings_equal(struct settings *one, struct settings *two)
150 {
151 	/*
152 	 * Regex lists are not serialized, and thus won't be compared
153 	 * here.
154 	 */
155 	igt_assert_eq(one->abort_mask, two->abort_mask);
156 	igt_assert_eqstr(one->test_list, two->test_list);
157 	igt_assert_eqstr(one->name, two->name);
158 	igt_assert_eq(one->dry_run, two->dry_run);
159 	igt_assert_eq(one->sync, two->sync);
160 	igt_assert_eq(one->log_level, two->log_level);
161 	igt_assert_eq(one->overwrite, two->overwrite);
162 	igt_assert_eq(one->multiple_mode, two->multiple_mode);
163 	igt_assert_eq(one->inactivity_timeout, two->inactivity_timeout);
164 	igt_assert_eq(one->use_watchdog, two->use_watchdog);
165 	igt_assert_eqstr(one->test_root, two->test_root);
166 	igt_assert_eqstr(one->results_path, two->results_path);
167 	igt_assert_eq(one->piglit_style_dmesg, two->piglit_style_dmesg);
168 	igt_assert_eq(one->dmesg_warn_level, two->dmesg_warn_level);
169 }
170 
assert_job_list_equal(struct job_list * one,struct job_list * two)171 static void assert_job_list_equal(struct job_list *one, struct job_list *two)
172 {
173 	size_t i, k;
174 
175 	igt_assert_eq(one->size, two->size);
176 
177 	for (i = 0; i < one->size; i++) {
178 		struct job_list_entry *eone = &one->entries[i];
179 		struct job_list_entry *etwo = &two->entries[i];
180 
181 		igt_assert_eqstr(eone->binary, etwo->binary);
182 		igt_assert_eq(eone->subtest_count, etwo->subtest_count);
183 
184 		for (k = 0; k < eone->subtest_count; k++) {
185 			igt_assert_eqstr(eone->subtests[k], etwo->subtests[k]);
186 		}
187 	}
188 }
189 
assert_execution_created(int dirfd,const char * name)190 static void assert_execution_created(int dirfd, const char *name)
191 {
192 	int fd;
193 
194 	igt_assert_f((fd = openat(dirfd, name, O_RDONLY)) >= 0,
195 		     "Execute didn't create %s\n", name);
196 	close(fd);
197 }
198 
assert_execution_results_exist(int dirfd)199 static void assert_execution_results_exist(int dirfd)
200 {
201 	assert_execution_created(dirfd, "journal.txt");
202 	assert_execution_created(dirfd, "out.txt");
203 	assert_execution_created(dirfd, "err.txt");
204 	assert_execution_created(dirfd, "dmesg.txt");
205 }
206 
207 igt_main
208 {
209 	struct settings *settings = malloc(sizeof(*settings));
210 
211 	igt_fixture {
212 		int i;
213 
214 		/*
215 		 * Let's close all the non-standard fds ahead of executing
216 		 * anything, so we can test for descriptor leakage caused by
217 		 * any of the igt_runner code-paths exercised here.
218 		 *
219 		 * See file-descriptor-leakage subtest at the end.
220 		 *
221 		 * Some libraries (looking at you, GnuTLS) may leave fds opened
222 		 * after the implicitly called library constructor. We don't
223 		 * have full control over them as they may be dependencies of
224 		 * our dependencies and may get pulled in if the user's and
225 		 * distribution's compile/configure/USE are just right.
226 		 */
227 		for (i = 3; i < 400; i++)
228 			close(i);
229 
230 		init_settings(settings);
231 	}
232 
233 	igt_subtest("default-settings") {
234 		const char *argv[] = { "runner",
235 				       "test-root-dir",
236 				       "path-to-results",
237 		};
238 
239 		igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
240 
241 		igt_assert_eq(settings->abort_mask, 0);
242 		igt_assert(!settings->test_list);
243 		igt_assert_eqstr(settings->name, "path-to-results");
244 		igt_assert(!settings->dry_run);
245 		igt_assert_eq(settings->include_regexes.size, 0);
246 		igt_assert_eq(settings->exclude_regexes.size, 0);
247 		igt_assert(!settings->sync);
248 		igt_assert_eq(settings->log_level, LOG_LEVEL_NORMAL);
249 		igt_assert(!settings->overwrite);
250 		igt_assert(!settings->multiple_mode);
251 		igt_assert_eq(settings->inactivity_timeout, 0);
252 		igt_assert_eq(settings->overall_timeout, 0);
253 		igt_assert(!settings->use_watchdog);
254 		igt_assert(strstr(settings->test_root, "test-root-dir") != NULL);
255 		igt_assert(strstr(settings->results_path, "path-to-results") != NULL);
256 
257 		igt_assert(!settings->piglit_style_dmesg);
258 		igt_assert_eq(settings->dmesg_warn_level, 4);
259 	}
260 
261 	igt_subtest_group {
262 		char *cwd;
263 		char *path;
264 
265 		igt_fixture {
266 			igt_require((cwd = realpath(".", NULL)) != NULL);
267 			path = NULL;
268 		}
269 
270 		igt_subtest("absolute-path-converter") {
271 			char paths[][15] = { "simple-name", "foo/bar", "." };
272 			size_t i;
273 
274 			for (i = 0; i < ARRAY_SIZE(paths); i++) {
275 				free(path);
276 				path = absolute_path(paths[i]);
277 
278 				igt_assert(path[0] == '/');
279 				igt_debug("Got path %s for %s\n", path, paths[i]);
280 				igt_assert(strstr(path, cwd) == path);
281 				if (strcmp(paths[i], ".")) {
282 					igt_assert(strstr(path, paths[i]) != NULL);
283 				}
284 			}
285 		}
286 
287 		igt_fixture {
288 			free(cwd);
289 			free(path);
290 		}
291 	}
292 
293 	igt_subtest_group {
294 		const char tmptestlist[] = "tmp.testlist";
295 		char dirname[] = "tmpdirXXXXXX";
296 		char pathtotestlist[64];
297 		volatile char *path;
298 
299 		igt_fixture {
300 			int dirfd, fd;
301 
302 			path = NULL;
303 
304 			igt_require(mkdtemp(dirname) != NULL);
305 			igt_require((dirfd = open(dirname, O_DIRECTORY | O_RDONLY)) >= 0);
306 			igt_require((fd = openat(dirfd, tmptestlist, O_CREAT | O_EXCL | O_WRONLY, 0660)) >= 0);
307 			close(fd);
308 			close(dirfd);
309 
310 			strcpy(pathtotestlist, dirname);
311 			strcat(pathtotestlist, "/");
312 			strcat(pathtotestlist, tmptestlist);
313 		}
314 
315 		igt_subtest("absolute-path-usage") {
316 			const char *argv[] = { "runner",
317 					       "--test-list", pathtotestlist,
318 					       testdatadir,
319 					       dirname,
320 			};
321 
322 			igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
323 
324 			path = realpath(testdatadir, NULL);
325 			igt_assert(path != NULL);
326 			igt_assert_eqstr(settings->test_root, (char*)path);
327 			free((void*)path);
328 			path = realpath(dirname, NULL);
329 			igt_assert(path != NULL);
330 			igt_assert_eqstr(settings->results_path, (char*)path);
331 			free((void*)path);
332 			path = realpath(pathtotestlist, NULL);
333 			igt_assert(path != NULL);
334 			igt_assert_eqstr(settings->test_list, (char*)path);
335 		}
336 
337 		igt_fixture {
338 			int dirfd;
339 
340 			igt_require((dirfd = open(dirname, O_DIRECTORY | O_RDONLY)) >= 0);
341 			unlinkat(dirfd, tmptestlist, 0);
342 			close(dirfd);
343 			rmdir(dirname);
344 
345 			free((void*)path);
346 		}
347 	}
348 
349 	igt_subtest("environment-overrides-test-root-flag") {
350 		const char *argv[] = { "runner",
351 				       "test-root-dir",
352 				       "path-to-results",
353 		};
354 
355 		setenv("IGT_TEST_ROOT", testdatadir, 1);
356 		igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
357 
358 		igt_assert_eq(settings->abort_mask, 0);
359 		igt_assert(!settings->test_list);
360 		igt_assert_eqstr(settings->name, "path-to-results");
361 		igt_assert(!settings->dry_run);
362 		igt_assert_eq(settings->include_regexes.size, 0);
363 		igt_assert_eq(settings->exclude_regexes.size, 0);
364 		igt_assert(!settings->sync);
365 		igt_assert_eq(settings->log_level, LOG_LEVEL_NORMAL);
366 		igt_assert(!settings->overwrite);
367 		igt_assert(!settings->multiple_mode);
368 		igt_assert_eq(settings->inactivity_timeout, 0);
369 		igt_assert_eq(settings->overall_timeout, 0);
370 		igt_assert(!settings->use_watchdog);
371 		igt_assert(strstr(settings->test_root, testdatadir) != NULL);
372 		igt_assert(strstr(settings->results_path, "path-to-results") != NULL);
373 		igt_assert(!settings->piglit_style_dmesg);
374 	}
375 
376 	igt_fixture {
377 		unsetenv("IGT_TEST_ROOT");
378 	}
379 
380 	igt_subtest("parse-all-settings") {
381 		char blacklist_name[PATH_MAX], blacklist2_name[PATH_MAX];
382 		const char *argv[] = { "runner",
383 				       "-n", "foo",
384 				       "--abort-on-monitored-error=taint,lockdep",
385 				       "--test-list", "path-to-test-list",
386 				       "--ignore-missing",
387 				       "--dry-run",
388 				       "-t", "pattern1",
389 				       "-t", "pattern2",
390 				       "-x", "xpattern1",
391 				       "-x", "xpattern2",
392 				       "-b", blacklist_name,
393 				       "--blacklist", blacklist2_name,
394 				       "-s",
395 				       "-l", "verbose",
396 				       "--overwrite",
397 				       "--multiple-mode",
398 				       "--inactivity-timeout", "27",
399 				       "--overall-timeout", "360",
400 				       "--use-watchdog",
401 				       "--piglit-style-dmesg",
402 				       "--dmesg-warn-level=3",
403 				       "test-root-dir",
404 				       "path-to-results",
405 		};
406 
407 		sprintf(blacklist_name, "%s/test-blacklist.txt", testdatadir);
408 		sprintf(blacklist2_name, "%s/test-blacklist2.txt", testdatadir);
409 
410 		igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
411 
412 		igt_assert_eq(settings->abort_mask, ABORT_TAINT | ABORT_LOCKDEP);
413 		igt_assert(strstr(settings->test_list, "path-to-test-list") != NULL);
414 		igt_assert_eqstr(settings->name, "foo");
415 		igt_assert(settings->dry_run);
416 		igt_assert_eq(settings->include_regexes.size, 2);
417 		igt_assert_eqstr(settings->include_regexes.regex_strings[0], "pattern1");
418 		igt_assert_eqstr(settings->include_regexes.regex_strings[1], "pattern2");
419 		igt_assert_eq(settings->exclude_regexes.size, 4);
420 		igt_assert_eqstr(settings->exclude_regexes.regex_strings[0], "xpattern1");
421 		igt_assert_eqstr(settings->exclude_regexes.regex_strings[1], "xpattern2");
422 		igt_assert_eqstr(settings->exclude_regexes.regex_strings[2], "xpattern3"); /* From blacklist */
423 		igt_assert_eqstr(settings->exclude_regexes.regex_strings[3], "xpattern4"); /* From blacklist2 */
424 		igt_assert(settings->sync);
425 		igt_assert_eq(settings->log_level, LOG_LEVEL_VERBOSE);
426 		igt_assert(settings->overwrite);
427 		igt_assert(settings->multiple_mode);
428 		igt_assert_eq(settings->inactivity_timeout, 27);
429 		igt_assert_eq(settings->overall_timeout, 360);
430 		igt_assert(settings->use_watchdog);
431 		igt_assert(strstr(settings->test_root, "test-root-dir") != NULL);
432 		igt_assert(strstr(settings->results_path, "path-to-results") != NULL);
433 
434 		igt_assert(settings->piglit_style_dmesg);
435 		igt_assert_eq(settings->dmesg_warn_level, 3);
436 	}
437 	igt_subtest("parse-list-all") {
438 		const char *argv[] = { "runner",
439 				       "--list-all",
440 				       "test-root-dir"};
441 
442 		igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
443 		igt_assert_eq(settings->list_all, 1);
444 	}
445 
446 	igt_subtest("dmesg-warn-level-inferred") {
447 		const char *argv[] = { "runner",
448 				       "test-root-dir",
449 				       "path-to-results",
450 		};
451 
452 		igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
453 
454 		igt_assert(!settings->piglit_style_dmesg);
455 		igt_assert_eq(settings->dmesg_warn_level, 4);
456 	}
457 
458 	igt_subtest("dmesg-warn-level-inferred-with-piglit-style") {
459 		const char *argv[] = { "runner",
460 				       "--piglit-style-dmesg",
461 				       "test-root-dir",
462 				       "path-to-results",
463 		};
464 
465 		igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
466 
467 		igt_assert(settings->piglit_style_dmesg);
468 		igt_assert_eq(settings->dmesg_warn_level, 5);
469 	}
470 
471 	igt_subtest("dmesg-warn-level-overridable-with-piglit-style") {
472 		const char *argv[] = { "runner",
473 				       "--piglit-style-dmesg",
474 				       "--dmesg-warn-level=3",
475 				       "test-root-dir",
476 				       "path-to-results",
477 		};
478 
479 		igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
480 
481 		igt_assert(settings->piglit_style_dmesg);
482 		igt_assert_eq(settings->dmesg_warn_level, 3);
483 	}
484 
485 	igt_subtest("invalid-option") {
486 		const char *argv[] = { "runner",
487 				       "--no-such-option",
488 				       "test-root-dir",
489 				       "results-path",
490 		};
491 
492 		igt_assert(!parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
493 	}
494 
495 	igt_subtest("paths-missing") {
496 		const char *argv[] = { "runner",
497 				       "-o",
498 		};
499 		igt_assert(!parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
500 	}
501 
502 	igt_subtest("log-levels") {
503 		const char *argv[] = { "runner",
504 				       "-l", "normal",
505 				       "test-root-dir",
506 				       "results-path",
507 		};
508 
509 		igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
510 		igt_assert_eq(settings->log_level, LOG_LEVEL_NORMAL);
511 
512 		argv[2] = "quiet";
513 		igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
514 		igt_assert_eq(settings->log_level, LOG_LEVEL_QUIET);
515 
516 		argv[2] = "verbose";
517 		igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
518 		igt_assert_eq(settings->log_level, LOG_LEVEL_VERBOSE);
519 	}
520 
521 	igt_subtest("abort-conditions") {
522 		const char *argv[] = { "runner",
523 				       "--abort-on-monitored-error=taint",
524 				       "test-root-dir",
525 				       "results-path",
526 		};
527 
528 		igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
529 		igt_assert_eq(settings->abort_mask, ABORT_TAINT);
530 
531 		argv[1] = "--abort-on-monitored-error=lockdep";
532 		igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
533 		igt_assert_eq(settings->abort_mask, ABORT_LOCKDEP);
534 
535 		argv[1] = "--abort-on-monitored-error=taint";
536 		igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
537 		igt_assert_eq(settings->abort_mask, ABORT_TAINT);
538 
539 		argv[1] = "--abort-on-monitored-error=lockdep,taint";
540 		igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
541 		igt_assert_eq(settings->abort_mask, ABORT_TAINT | ABORT_LOCKDEP);
542 
543 		argv[1] = "--abort-on-monitored-error=taint,lockdep";
544 		igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
545 		igt_assert_eq(settings->abort_mask, ABORT_TAINT | ABORT_LOCKDEP);
546 
547 		argv[1] = "--abort-on-monitored-error=all";
548 		igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
549 		igt_assert_eq(settings->abort_mask, ABORT_ALL);
550 
551 		argv[1] = "--abort-on-monitored-error=";
552 		igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
553 		igt_assert_eq(settings->abort_mask, 0);
554 
555 		argv[1] = "--abort-on-monitored-error=doesnotexist";
556 		igt_assert(!parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
557 
558 	}
559 
560 	igt_subtest("parse-clears-old-data") {
561 		const char *argv[] = { "runner",
562 				       "-n", "foo",
563 				       "--dry-run",
564 				       "test-root-dir",
565 				       "results-path",
566 		};
567 
568 		igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
569 
570 		igt_assert_eqstr(settings->name, "foo");
571 		igt_assert(settings->dry_run);
572 		igt_assert(!settings->test_list);
573 		igt_assert(!settings->sync);
574 
575 		argv[1] = "--test-list";
576 		argv[3] = "--sync";
577 
578 		igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
579 
580 		igt_assert_eqstr(settings->name, "results-path");
581 		igt_assert(!settings->dry_run);
582 		igt_assert(strstr(settings->test_list, "foo") != NULL);
583 		igt_assert(settings->sync);
584 	}
585 
586 	igt_subtest_group {
587 		char filename[] = "tmplistXXXXXX";
588 
589 		igt_fixture {
590 			int fd;
591 			igt_require((fd = mkstemp(filename)) >= 0);
592 			close(fd);
593 		}
594 
595 		igt_subtest("validate-ok") {
596 			const char *argv[] = { "runner",
597 					       "--test-list", filename,
598 					       testdatadir,
599 					       "path-to-results",
600 			};
601 
602 			igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
603 
604 			igt_assert(validate_settings(settings));
605 		}
606 
607 		igt_fixture {
608 			unlink(filename);
609 		}
610 	}
611 
612 	igt_subtest("validate-no-test-list") {
613 		const char *nosuchfile = "no-such-file";
614 		const char *argv[] = { "runner",
615 				       "--test-list", nosuchfile,
616 				       testdatadir,
617 				       "path-to-results",
618 		};
619 
620 		igt_assert_lt(open(nosuchfile, O_RDONLY), 0);
621 		igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
622 
623 		igt_assert(!validate_settings(settings));
624 	}
625 
626 	igt_subtest_group {
627 		char dirname[] = "tmpdirXXXXXX";
628 		struct job_list *list = malloc(sizeof(*list));
629 
630 		igt_fixture {
631 			igt_require(mkdtemp(dirname) != NULL);
632 			init_job_list(list);
633 		}
634 
635 		igt_subtest("job-list-no-test-list-txt") {
636 			const char *argv[] = { "runner",
637 					       dirname,
638 					       "path-to-results",
639 			};
640 
641 			igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
642 
643 			igt_assert(!create_job_list(list, settings));
644 		}
645 
646 		igt_fixture {
647 			rmdir(dirname);
648 			free_job_list(list);
649 			free(list);
650 		}
651 	}
652 
653 	job_list_filter_test("nofilters", "-n", "placeholderargs", 5, 3);
654 	job_list_filter_test("binary-include", "-t", "successtest", 2, 1);
655 	job_list_filter_test("binary-exclude", "-x", "successtest", 3, 2);
656 	job_list_filter_test("subtest-include", "-t", "first-subtest", 1, 1);
657 	job_list_filter_test("subtest-exclude", "-x", "second-subtest", 4, 3);
658 	job_list_filter_test("piglit-names", "-t", "igt@successtest", 2, 1);
659 	job_list_filter_test("piglit-names-subtest", "-t", "igt@successtest@first", 1, 1);
660 
661 	igt_subtest_group {
662 		char filename[] = "tmplistXXXXXX";
663 		const char testlisttext[] = "igt@successtest@first-subtest\n"
664 			"igt@successtest@second-subtest\n"
665 			"igt@nosubtests\n";
666 		int multiple;
667 		struct job_list *list = malloc(sizeof(*list));
668 
669 		igt_fixture {
670 			int fd;
671 			igt_require((fd = mkstemp(filename)) >= 0);
672 			igt_require(write(fd, testlisttext, strlen(testlisttext)) == strlen(testlisttext));
673 			close(fd);
674 			init_job_list(list);
675 		}
676 
677 		for (multiple = 0; multiple < 2; multiple++) {
678 			igt_subtest_f("job-list-testlist-%s", multiple ? "multiple" : "normal") {
679 				const char *argv[] = { "runner",
680 						       "--test-list", filename,
681 						       multiple ? "--multiple-mode" : "--sync",
682 						       testdatadir,
683 						       "path-to-results",
684 				};
685 
686 				igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
687 				igt_assert(create_job_list(list, settings));
688 
689 				igt_assert_eq(list->size, multiple ? 2 : 3);
690 
691 				igt_assert_eqstr(list->entries[0].binary, "successtest");
692 				if (!multiple) igt_assert_eqstr(list->entries[1].binary, "successtest");
693 				igt_assert_eqstr(list->entries[multiple ? 1 : 2].binary, "nosubtests");
694 
695 				igt_assert_eq(list->entries[0].subtest_count, multiple ? 2 : 1);
696 				igt_assert_eq(list->entries[1].subtest_count, multiple ? 0 : 1);
697 				if (!multiple) igt_assert_eq(list->entries[2].subtest_count, 0);
698 
699 				igt_assert_eqstr(list->entries[0].subtests[0], "first-subtest");
700 				igt_assert_eqstr(list->entries[multiple ? 0 : 1].subtests[multiple ? 1 : 0], "second-subtest");
701 			}
702 
703 			igt_subtest_f("job-list-testlist-filtered-%s", multiple ? "multiple" : "normal") {
704 				const char *argv[] = { "runner",
705 						       "--test-list", filename,
706 						       multiple ? "--multiple-mode" : "--sync",
707 						       "-t", "successtest",
708 						       "-x", "first",
709 						       testdatadir,
710 						       "path-to-results",
711 				};
712 
713 				igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
714 				igt_assert(create_job_list(list, settings));
715 
716 				igt_assert_eq(list->size, 1);
717 				igt_assert_eqstr(list->entries[0].binary, "successtest");
718 
719 				igt_assert_eq(list->entries[0].subtest_count, 1);
720 				igt_assert_eqstr(list->entries[0].subtests[0], "second-subtest");
721 			}
722 		}
723 
724 		igt_fixture {
725 			unlink(filename);
726 			free_job_list(list);
727 			free(list);
728 		}
729 	}
730 
731 	igt_subtest_group {
732 		char dirname[] = "tmpdirXXXXXX";
733 		volatile int dirfd = -1, fd = -1;
734 		struct settings *cmp_settings = malloc(sizeof(*cmp_settings));
735 
736 		igt_fixture {
737 			igt_require(mkdtemp(dirname) != NULL);
738 			rmdir(dirname);
739 			init_settings(cmp_settings);
740 		}
741 
742 		igt_subtest("settings-serialize") {
743 			const char *argv[] = { "runner",
744 					       "-n", "foo",
745 					       "--abort-on-monitored-error",
746 					       "--test-list", "path-to-test-list",
747 					       "--ignore-missing",
748 					       "--dry-run",
749 					       "-t", "pattern1",
750 					       "-t", "pattern2",
751 					       "-x", "xpattern1",
752 					       "-x", "xpattern2",
753 					       "-s",
754 					       "-l", "verbose",
755 					       "--overwrite",
756 					       "--multiple-mode",
757 					       "--inactivity-timeout", "27",
758 					       "--overall-timeout", "360",
759 					       "--use-watchdog",
760 					       "--piglit-style-dmesg",
761 					       testdatadir,
762 					       dirname,
763 			};
764 
765 			igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
766 
767 			igt_assert(serialize_settings(settings));
768 
769 			dirfd = open(dirname, O_DIRECTORY, O_RDONLY);
770 			igt_assert_f(dirfd >= 0, "Serialization did not create the results directory\n");
771 
772 			igt_assert_f((fd = openat(dirfd, "metadata.txt", O_RDONLY)),
773 				     "Opening %s/metadata.txt failed\n", dirname);
774 			close(fd);
775 
776 			igt_assert_f(read_settings_from_dir(cmp_settings, dirfd), "Reading settings failed\n");
777 			assert_settings_equal(settings, cmp_settings);
778 		}
779 
780 		igt_fixture {
781 			close(fd);
782 			close(dirfd);
783 			clear_directory(dirname);
784 			free_settings(cmp_settings);
785 			free(cmp_settings);
786 		}
787 	}
788 
789 	igt_subtest_group {
790 		char dirname[] = "tmpdirXXXXXX";
791 		volatile int dirfd = -1, fd = -1;
792 		struct job_list *list, *cmp_list;
793 		int multiple;
794 
795 		list = malloc(sizeof(*list));
796 		cmp_list = malloc(sizeof(*cmp_list));
797 
798 		igt_fixture {
799 			init_job_list(list);
800 			init_job_list(cmp_list);
801 			igt_require(mkdtemp(dirname) != NULL);
802 			rmdir(dirname);
803 		}
804 
805 		for (multiple = 0; multiple < 2; multiple++) {
806 			igt_subtest_f("job-list-serialize-%s", multiple ? "multiple" : "normal") {
807 				const char *argv[] = { "runner",
808 						       /* Ugly */
809 						       multiple ? "--multiple-mode" : "--sync",
810 						       testdatadir,
811 						       dirname,
812 				};
813 
814 				igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
815 				igt_assert(create_job_list(list, settings));
816 
817 				igt_assert(serialize_settings(settings));
818 				igt_assert(serialize_job_list(list, settings));
819 
820 				dirfd = open(dirname, O_DIRECTORY, O_RDONLY);
821 				igt_assert_f(dirfd >= 0, "Serialization did not create the results directory\n");
822 
823 				igt_assert_f((fd = openat(dirfd, "joblist.txt", O_RDONLY)) >= 0,
824 					     "Opening %s/joblist.txt failed\n", dirname);
825 				close(fd);
826 				fd = -1;
827 
828 				igt_assert_f(read_job_list(cmp_list, dirfd), "Reading job list failed\n");
829 				assert_job_list_equal(list, cmp_list);
830 			}
831 
832 			igt_fixture {
833 				close(fd);
834 				close(dirfd);
835 				clear_directory(dirname);
836 				free_job_list(cmp_list);
837 				free_job_list(list);
838 			}
839 		}
840 
841 		igt_fixture {
842 			free(cmp_list);
843 			free(list);
844 		}
845 	}
846 
847 	igt_subtest_group {
848 		char dirname[] = "tmpdirXXXXXX";
849 		struct job_list *list = malloc(sizeof(*list));
850 		volatile int dirfd = -1, subdirfd = -1, fd = -1;
851 
852 		igt_fixture {
853 			init_job_list(list);
854 			igt_require(mkdtemp(dirname) != NULL);
855 			rmdir(dirname);
856 		}
857 
858 		igt_subtest("dry-run-option") {
859 			struct execute_state state;
860 			const char *argv[] = { "runner",
861 					       "--dry-run",
862 					       testdatadir,
863 					       dirname,
864 			};
865 
866 			igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
867 			igt_assert(create_job_list(list, settings));
868 
869 			igt_assert(initialize_execute_state(&state, settings, list));
870 			igt_assert_eq(state.next, 0);
871 			igt_assert(state.dry);
872 			igt_assert_eq(list->size, 5);
873 
874 			igt_assert_f((dirfd = open(dirname, O_DIRECTORY | O_RDONLY)) >= 0,
875 				     "Dry run initialization didn't create the results directory.\n");
876 
877 			/* Execute from just initialize_execute_state should fail */
878 			igt_assert(execute(&state, settings, list));
879 			igt_assert_f(openat(dirfd, "0", O_DIRECTORY | O_RDONLY) < 0,
880 				     "Dry run executed when it should not have.\n");
881 			igt_assert_f((fd = openat(dirfd, "metadata.txt", O_RDONLY)) >= 0,
882 				     "Dry run initialization didn't serialize settings.\n");
883 			close(fd);
884 			igt_assert_f((fd = openat(dirfd, "joblist.txt", O_RDONLY)) >= 0,
885 				     "Dry run initialization didn't serialize the job list.\n");
886 			close(fd);
887 			igt_assert_f((fd = openat(dirfd, "uname.txt", O_RDONLY)) < 0,
888 				     "Dry run initialization created uname.txt.\n");
889 
890 			igt_assert(initialize_execute_state_from_resume(dirfd, &state, settings, list));
891 			igt_assert_eq(state.next, 0);
892 			igt_assert(!state.dry);
893 			igt_assert_eq(list->size, 5);
894 			/* initialize_execute_state_from_resume() closes the dirfd */
895 			igt_assert_f((dirfd = open(dirname, O_DIRECTORY | O_RDONLY)) >= 0,
896 				     "Dry run resume somehow deleted the results directory.\n");
897 
898 			/* Execute from resume should work */
899 			igt_assert(execute(&state, settings, list));
900 			igt_assert_f((fd = openat(dirfd, "uname.txt", O_RDONLY)) >= 0,
901 				     "Dry run resume didn't create uname.txt.\n");
902 			close(fd);
903 			igt_assert_f((subdirfd = openat(dirfd, "0", O_DIRECTORY | O_RDONLY)) >= 0,
904 				     "Dry run resume didn't create result directory.\n");
905 			igt_assert_f((fd = openat(subdirfd, "journal.txt", O_RDONLY)) >= 0,
906 				     "Dry run resume didn't create a journal.\n");
907 		}
908 
909 		igt_fixture {
910 			close(fd);
911 			close(dirfd);
912 			close(subdirfd);
913 			clear_directory(dirname);
914 			free_job_list(list);
915 			free(list);
916 		}
917 	}
918 
919 	igt_subtest_group {
920 		char dirname[] = "tmpdirXXXXXX";
921 		struct job_list *list = malloc(sizeof(*list));
922 		volatile int dirfd = -1, fd = -1;
923 
924 		igt_fixture {
925 			init_job_list(list);
926 			igt_require(mkdtemp(dirname) != NULL);
927 			rmdir(dirname);
928 		}
929 
930 		igt_subtest("execute-initialize-new-run") {
931 			struct execute_state state;
932 			const char *argv[] = { "runner",
933 					       testdatadir,
934 					       dirname,
935 			};
936 
937 			igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
938 			igt_assert(create_job_list(list, settings));
939 
940 			igt_assert(initialize_execute_state(&state, settings, list));
941 
942 			igt_assert_eq(state.next, 0);
943 			igt_assert_eq(list->size, 5);
944 			igt_assert_f((dirfd = open(dirname, O_DIRECTORY | O_RDONLY)) >= 0,
945 				     "Execute state initialization didn't create the results directory.\n");
946 			igt_assert_f((fd = openat(dirfd, "metadata.txt", O_RDONLY)) >= 0,
947 				     "Execute state initialization didn't serialize settings.\n");
948 			close(fd);
949 			igt_assert_f((fd = openat(dirfd, "joblist.txt", O_RDONLY)) >= 0,
950 				     "Execute state initialization didn't serialize the job list.\n");
951 			close(fd);
952 			igt_assert_f((fd = openat(dirfd, "journal.txt", O_RDONLY)) < 0,
953 				     "Execute state initialization created a journal.\n");
954 			igt_assert_f((fd = openat(dirfd, "uname.txt", O_RDONLY)) < 0,
955 				     "Execute state initialization created uname.txt.\n");
956 		}
957 
958 		igt_fixture {
959 			close(fd);
960 			close(dirfd);
961 			clear_directory(dirname);
962 			free_job_list(list);
963 			free(list);
964 		}
965 	}
966 
967 	igt_subtest_group {
968 		char dirname[] = "tmpdirXXXXXX";
969 		struct job_list *list = malloc(sizeof(*list));
970 		volatile int dirfd = -1, subdirfd = -1, fd = -1;
971 
972 		igt_fixture {
973 			init_job_list(list);
974 			igt_require(mkdtemp(dirname) != NULL);
975 		}
976 
977 		igt_subtest("execute-initialize-subtest-started") {
978 			struct execute_state state;
979 			const char *argv[] = { "runner",
980 					       "--multiple-mode",
981 					       "-t", "successtest",
982 					       testdatadir,
983 					       dirname,
984 			};
985 			const char journaltext[] = "first-subtest\n";
986 			const char excludestring[] = "!first-subtest";
987 
988 			igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
989 			igt_assert(create_job_list(list, settings));
990 			igt_assert(list->size == 1);
991 			igt_assert(list->entries[0].subtest_count == 0);
992 
993 			igt_assert(serialize_settings(settings));
994 			igt_assert(serialize_job_list(list, settings));
995 
996 			igt_assert((dirfd = open(dirname, O_DIRECTORY | O_RDONLY)) >= 0);
997 			igt_assert(mkdirat(dirfd, "0", 0770) == 0);
998 			igt_assert((subdirfd = openat(dirfd, "0", O_DIRECTORY | O_RDONLY)) >= 0);
999 			igt_assert((fd = openat(subdirfd, "journal.txt", O_CREAT | O_WRONLY | O_EXCL, 0660)) >= 0);
1000 			igt_assert(write(fd, journaltext, strlen(journaltext)) == strlen(journaltext));
1001 
1002 			free_job_list(list);
1003 			free_settings(settings);
1004 			igt_assert(initialize_execute_state_from_resume(dirfd, &state, settings, list));
1005 
1006 			igt_assert_eq(state.next, 0);
1007 			igt_assert_eq(list->size, 1);
1008 			igt_assert_eq(list->entries[0].subtest_count, 2);
1009 			igt_assert_eqstr(list->entries[0].subtests[0], "*");
1010 			igt_assert_eqstr(list->entries[0].subtests[1], excludestring);
1011 		}
1012 
1013 		igt_fixture {
1014 			close(fd);
1015 			close(subdirfd);
1016 			close(dirfd);
1017 			clear_directory(dirname);
1018 			free_job_list(list);
1019 			free(list);
1020 		}
1021 	}
1022 
1023 	igt_subtest_group {
1024 		char dirname[] = "tmpdirXXXXXX";
1025 		struct job_list *list = malloc(sizeof(*list));
1026 		volatile int dirfd = -1, subdirfd = -1, fd = -1;
1027 
1028 		igt_fixture {
1029 			init_job_list(list);
1030 			igt_require(mkdtemp(dirname) != NULL);
1031 		}
1032 
1033 		igt_subtest("execute-initialize-all-subtests-started") {
1034 			struct execute_state state;
1035 			const char *argv[] = { "runner",
1036 					       "--multiple-mode",
1037 					       "-t", "successtest@first-subtest",
1038 					       "-t", "successtest@second-subtest",
1039 					       testdatadir,
1040 					       dirname,
1041 			};
1042 			const char journaltext[] = "first-subtest\nsecond-subtest\n";
1043 
1044 			igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
1045 			igt_assert(create_job_list(list, settings));
1046 			igt_assert(list->size == 1);
1047 			igt_assert(list->entries[0].subtest_count == 2);
1048 
1049 			igt_assert(serialize_settings(settings));
1050 			igt_assert(serialize_job_list(list, settings));
1051 
1052 			igt_assert((dirfd = open(dirname, O_DIRECTORY | O_RDONLY)) >= 0);
1053 			igt_assert(mkdirat(dirfd, "0", 0770) == 0);
1054 			igt_assert((subdirfd = openat(dirfd, "0", O_DIRECTORY | O_RDONLY)) >= 0);
1055 			igt_assert((fd = openat(subdirfd, "journal.txt", O_CREAT | O_WRONLY | O_EXCL, 0660)) >= 0);
1056 			igt_assert(write(fd, journaltext, strlen(journaltext)) == strlen(journaltext));
1057 
1058 			free_job_list(list);
1059 			free_settings(settings);
1060 			igt_assert(initialize_execute_state_from_resume(dirfd, &state, settings, list));
1061 
1062 			/* All subtests are in journal, the entry should be considered completed */
1063 			igt_assert_eq(state.next, 1);
1064 			igt_assert_eq(list->size, 1);
1065 			igt_assert_eq(list->entries[0].subtest_count, 4);
1066 		}
1067 
1068 		igt_fixture {
1069 			close(fd);
1070 			close(subdirfd);
1071 			close(dirfd);
1072 			clear_directory(dirname);
1073 			free_job_list(list);
1074 			free(list);
1075 		}
1076 	}
1077 
1078 	igt_subtest_group {
1079 		char dirname[] = "tmpdirXXXXXX";
1080 		struct job_list *list = malloc(sizeof(*list));
1081 		volatile int dirfd = -1, subdirfd = -1, fd = -1;
1082 
1083 		igt_fixture {
1084 			init_job_list(list);
1085 			igt_require(mkdtemp(dirname) != NULL);
1086 		}
1087 
1088 		igt_subtest("execute-initialize-subtests-complete") {
1089 			struct execute_state state;
1090 			const char *argv[] = { "runner",
1091 					       "--multiple-mode",
1092 					       testdatadir,
1093 					       dirname,
1094 			};
1095 			const char journaltext[] = "first-subtest\nsecond-subtest\nexit:0\n";
1096 
1097 			igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
1098 			igt_assert(create_job_list(list, settings));
1099 			igt_assert(list->size == 3);
1100 
1101 			if (!strcmp(list->entries[0].binary, "no-subtests")) {
1102 				struct job_list_entry tmp = list->entries[0];
1103 				list->entries[0] = list->entries[1];
1104 				list->entries[1] = tmp;
1105 			}
1106 
1107 			igt_assert(list->entries[0].subtest_count == 0);
1108 
1109 			igt_assert(serialize_settings(settings));
1110 			igt_assert(serialize_job_list(list, settings));
1111 
1112 			igt_assert_lte(0, dirfd = open(dirname, O_DIRECTORY | O_RDONLY));
1113 			igt_assert_eq(mkdirat(dirfd, "0", 0770), 0);
1114 			igt_assert((subdirfd = openat(dirfd, "0", O_DIRECTORY | O_RDONLY)) >= 0);
1115 			igt_assert_lte(0, fd = openat(subdirfd, "journal.txt", O_CREAT | O_WRONLY | O_EXCL, 0660));
1116 			igt_assert_eq(write(fd, journaltext, sizeof(journaltext)), sizeof(journaltext));
1117 
1118 			free_job_list(list);
1119 			free_settings(settings);
1120 			igt_assert(initialize_execute_state_from_resume(dirfd, &state, settings, list));
1121 
1122 			igt_assert_eq(state.next, 1);
1123 			igt_assert_eq(list->size, 3);
1124 		}
1125 
1126 		igt_fixture {
1127 			close(fd);
1128 			close(subdirfd);
1129 			close(dirfd);
1130 			clear_directory(dirname);
1131 			free_job_list(list);
1132 			free(list);
1133 		}
1134 	}
1135 
1136 	igt_subtest_group {
1137 		struct job_list *list = malloc(sizeof(*list));
1138 		volatile int dirfd = -1, subdirfd = -1, fd = -1;
1139 		int multiple;
1140 
1141 		igt_fixture {
1142 			init_job_list(list);
1143 		}
1144 
1145 		for (multiple = 0; multiple < 2; multiple++) {
1146 			char dirname[] = "tmpdirXXXXXX";
1147 
1148 			igt_fixture {
1149 				igt_require(mkdtemp(dirname) != NULL);
1150 				rmdir(dirname);
1151 			}
1152 
1153 			igt_subtest_f("execute-subtests-%s", multiple ? "multiple" : "normal") {
1154 				struct execute_state state;
1155 				const char *argv[] = { "runner",
1156 						       multiple ? "--multiple-mode" : "--sync",
1157 						       "-t", "-subtest",
1158 						       testdatadir,
1159 						       dirname,
1160 				};
1161 				char testdirname[16];
1162 				size_t expected_tests = multiple ? 2 : 3;
1163 				size_t i;
1164 
1165 				igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
1166 				igt_assert(create_job_list(list, settings));
1167 				igt_assert(initialize_execute_state(&state, settings, list));
1168 
1169 				igt_assert(execute(&state, settings, list));
1170 				igt_assert_f((dirfd = open(dirname, O_DIRECTORY | O_RDONLY)) >= 0,
1171 					     "Execute didn't create the results directory\n");
1172 
1173 				igt_assert_f((fd = openat(dirfd, "uname.txt", O_RDONLY)) >= 0,
1174 					     "Execute didn't create uname.txt\n");
1175 				close(fd);
1176 				fd = -1;
1177 
1178 				for (i = 0; i < expected_tests; i++) {
1179 					snprintf(testdirname, 16, "%zd", i);
1180 
1181 					igt_assert_f((subdirfd = openat(dirfd, testdirname, O_DIRECTORY | O_RDONLY)) >= 0,
1182 						     "Execute didn't create result directory '%s'\n", testdirname);
1183 					assert_execution_results_exist(subdirfd);
1184 					close(subdirfd);
1185 				}
1186 
1187 				snprintf(testdirname, 16, "%zd", expected_tests);
1188 				igt_assert_f((subdirfd = openat(dirfd, testdirname, O_DIRECTORY | O_RDONLY)) < 0,
1189 					     "Execute created too many directories\n");
1190 			}
1191 
1192 			igt_fixture {
1193 				close(fd);
1194 				close(subdirfd);
1195 				close(dirfd);
1196 				clear_directory(dirname);
1197 				free_job_list(list);
1198 			}
1199 		}
1200 
1201 		igt_fixture
1202 			free(list);
1203 	}
1204 
1205 	igt_subtest_group {
1206 		igt_subtest("metadata-read-old-style-infer-dmesg-warn-piglit-style") {
1207 			char metadata[] = "piglit_style_dmesg : 1\n";
1208 			FILE *f = fmemopen(metadata, strlen(metadata), "r");
1209 			igt_assert(f);
1210 
1211 			igt_assert(read_settings_from_file(settings, f));
1212 
1213 			igt_assert(settings->piglit_style_dmesg);
1214 			igt_assert_eq(settings->dmesg_warn_level, 5);
1215 
1216 			fclose(f);
1217 		}
1218 
1219 		igt_subtest("metadata-read-overrides-dmesg-warn-piglit-style") {
1220 			char metadata[] = "piglit_style_dmesg : 1\ndmesg_warn_level : 3";
1221 			FILE *f = fmemopen(metadata, strlen(metadata), "r");
1222 			igt_assert(f);
1223 
1224 			igt_assert(read_settings_from_file(settings, f));
1225 
1226 			igt_assert(settings->piglit_style_dmesg);
1227 			igt_assert_eq(settings->dmesg_warn_level, 3);
1228 
1229 			fclose(f);
1230 		}
1231 
1232 		igt_subtest("metadata-read-old-style-infer-dmesg-warn-default") {
1233 			char metadata[] = "piglit_style_dmesg : 0\n";
1234 			FILE *f = fmemopen(metadata, strlen(metadata), "r");
1235 			igt_assert(f);
1236 
1237 			igt_assert(read_settings_from_file(settings, f));
1238 
1239 			igt_assert(!settings->piglit_style_dmesg);
1240 			igt_assert_eq(settings->dmesg_warn_level, 4);
1241 
1242 			fclose(f);
1243 		}
1244 
1245 		igt_subtest("metadata-read-overrides-dmesg-warn-default") {
1246 			char metadata[] = "piglit_style_dmesg : 0\ndmesg_warn_level : 3";
1247 			FILE *f = fmemopen(metadata, strlen(metadata), "r");
1248 			igt_assert(f);
1249 
1250 			igt_assert(read_settings_from_file(settings, f));
1251 
1252 			igt_assert(!settings->piglit_style_dmesg);
1253 			igt_assert_eq(settings->dmesg_warn_level, 3);
1254 
1255 			fclose(f);
1256 		}
1257 	}
1258 
1259 	igt_subtest_group {
1260 		struct job_list *list = malloc(sizeof(*list));
1261 		volatile int dirfd = -1, subdirfd = -1, fd = -1;
1262 		int multiple;
1263 
1264 		igt_fixture {
1265 			init_job_list(list);
1266 		}
1267 
1268 		for (multiple = 0; multiple < 2; multiple++) {
1269 			char dirname[] = "tmpdirXXXXXX";
1270 
1271 			igt_fixture {
1272 				igt_require(mkdtemp(dirname) != NULL);
1273 				rmdir(dirname);
1274 			}
1275 
1276 			igt_subtest_f("execute-skipper-journal-%s", multiple ? "multiple" : "normal") {
1277 				struct execute_state state;
1278 				const char *argv[] = { "runner",
1279 						       multiple ? "--multiple-mode" : "--sync",
1280 						       "-t", "skippers",
1281 						       testdatadir,
1282 						       dirname,
1283 				};
1284 				char *dump;
1285 				const char *expected_0 = multiple ?
1286 					"skip-one\nskip-two\nexit:77 (" :
1287 					"skip-one\nexit:77 (";
1288 				const char *expected_1 = "skip-two\nexit:77 (";
1289 
1290 				igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
1291 				igt_assert(create_job_list(list, settings));
1292 				igt_assert(initialize_execute_state(&state, settings, list));
1293 
1294 				igt_assert(execute(&state, settings, list));
1295 				igt_assert_f((dirfd = open(dirname, O_DIRECTORY | O_RDONLY)) >= 0,
1296 					     "Execute didn't create the results directory\n");
1297 
1298 				igt_assert_f((fd = openat(dirfd, "uname.txt", O_RDONLY)) >= 0,
1299 					     "Execute didn't create uname.txt\n");
1300 				close(fd);
1301 				fd = -1;
1302 
1303 				igt_assert_f((subdirfd = openat(dirfd, "0", O_DIRECTORY | O_RDONLY)) >= 0,
1304 					     "Execute didn't create result directory '0'\n");
1305 				dump = dump_file(subdirfd, "journal.txt");
1306 				igt_assert_f(dump != NULL,
1307 					     "Execute didn't create the journal\n");
1308 				/* Trim out the runtime */
1309 				dump[strlen(expected_0)] = '\0';
1310 				igt_assert_eqstr(dump, expected_0);
1311 				free(dump);
1312 				close(subdirfd);
1313 				subdirfd = -1;
1314 
1315 				if (!multiple) {
1316 					igt_assert_f((subdirfd = openat(dirfd, "1", O_DIRECTORY | O_RDONLY)) >= 0,
1317 						     "Execute didn't create result directory '1'\n");
1318 					dump = dump_file(subdirfd, "journal.txt");
1319 					igt_assert_f(dump != NULL,
1320 						     "Execute didn't create the journal\n");
1321 					dump[strlen(expected_1)] = '\0';
1322 					igt_assert_eqstr(dump, expected_1);
1323 					free(dump);
1324 					close(subdirfd);
1325 					subdirfd = -1;
1326 				}
1327 			}
1328 
1329 			igt_fixture {
1330 				close(fd);
1331 				close(subdirfd);
1332 				close(dirfd);
1333 				clear_directory(dirname);
1334 				free_job_list(list);
1335 			}
1336 		}
1337 
1338 		igt_fixture
1339 			free(list);
1340 	}
1341 
1342 	igt_subtest("file-descriptor-leakage") {
1343 		int i;
1344 
1345 		/*
1346 		 * This is a build-time test, and it's expected that
1347 		 * all subtests are normally run. Keep this one at the
1348 		 * end.
1349 		 *
1350 		 * Try to close some number of fds after stderr and
1351 		 * expect EBADF for each one.
1352 		 */
1353 		for (i = 3; i < 400; i++) {
1354 			errno = 0;
1355 			igt_assert_neq(close(i), 0);
1356 			igt_assert_eq(errno, EBADF);
1357 		}
1358 	}
1359 
1360 	igt_fixture {
1361 		free_settings(settings);
1362 		free(settings);
1363 	}
1364 }
1365