All of lore.kernel.org
 help / color / mirror / Atom feed
* [igt-dev] [PATCH i-g-t 0/9] Abort on Chamelium failure
@ 2020-02-12 13:21 Arkadiusz Hiler
  2020-02-12 13:21 ` [igt-dev] [PATCH i-g-t 1/9] lib/tests: Extract fork helpers Arkadiusz Hiler
                   ` (10 more replies)
  0 siblings, 11 replies; 29+ messages in thread
From: Arkadiusz Hiler @ 2020-02-12 13:21 UTC (permalink / raw)
  To: igt-dev; +Cc: Petri Latvala

This series introduces new mechanism for aborting a run from inside an IGT test.
It is intended to be used when we detect a critical issue with the environment
and further testing makes no sense.

The first user is Chamelium.

Using chamelium as a display for non-chamelium-aware test is challenging. The
board can be left in multiple different states after kms_chamelium tests even
though we have atexit() handlers and other measures which try to assure that all
ports are plugged in. Sadly this is not 100% reliable and causes a lot of
flip-flopping skips.

In an attempt to make connectors state less random igt_display_require() will
try to reset chamelium to a good state. If we fail to do so we abort the
execution because the testing configuration is an unknown.

The introduction of new test state (abort) will need some changes in cibuglog &
igt-viz and can be used to convert runner-injected igt@runner@abort stubs into a
results for a real tests that has a meaningful dmesg attached.

Arkadiusz Hiler (9):
  lib/tests: Extract fork helpers
  lib/tests: Add support for redirecting fork output to /dev/null
  lib: Make it possible to abort the whole execution from inside of a
    test
  runner/runner_tests: Extract helper for inspecting test result
  runner: Abort the run when test exits with IGT_EXIT_ABORT
  lib/chamelium: Clear error after checking if chamelium is reachable
  lib/chamelium: Make it clear that function asserts
  lib/chamelium: Add functions to initialize XMLRPC only
  lib/kms: Try to plug all Chamelium ports, abort if it fails

 lib/igt_chamelium.c                           | 165 +++++++--
 lib/igt_chamelium.h                           |   6 +-
 lib/igt_core.c                                |  46 ++-
 lib/igt_core.h                                |  29 ++
 lib/igt_kms.c                                 |  18 +
 lib/tests/igt_abort.c                         | 227 ++++++++++++
 lib/tests/igt_assert.c                        |  35 +-
 lib/tests/igt_conflicting_args.c              |  25 +-
 lib/tests/igt_describe.c                      | 135 ++-----
 lib/tests/igt_dynamic_subtests.c              |  18 -
 lib/tests/igt_fork.c                          |  71 ++--
 lib/tests/igt_invalid_subtest_name.c          |  18 -
 lib/tests/igt_no_exit.c                       |  18 -
 lib/tests/igt_segfault.c                      |  59 ++--
 lib/tests/igt_simulation.c                    | 101 +++---
 lib/tests/igt_tests_common.h                  | 110 ++++++
 lib/tests/meson.build                         |   1 +
 runner/executor.c                             |   3 +
 .../aborted-after-a-test/reference.json       |   6 +
 .../aborted-on-boot/reference.json            |   6 +
 .../dmesg-escapes/reference.json              |   3 +
 .../dmesg-results/reference.json              |   5 +
 .../reference.json                            |   3 +
 .../reference.json                            |   3 +
 .../dmesg-warn-level/reference.json           |   3 +
 .../reference.json                            |   3 +
 .../dynamic-subtests/reference.json           |   3 +
 .../reference.json                            |   5 +
 .../json_tests_data/normal-run/reference.json |   5 +
 .../reference.json                            |   4 +
 .../notrun-results/reference.json             |   5 +
 .../piglit-style-dmesg/reference.json         |   5 +
 .../unprintable-characters/reference.json     |   5 +-
 .../warnings-with-dmesg-warns/reference.json  |   5 +
 .../json_tests_data/warnings/reference.json   |   5 +
 runner/resultgen.c                            |  25 ++
 runner/runner_tests.c                         | 333 +++++++++++++++++-
 runner/testdata/abort-dynamic.c               |  46 +++
 runner/testdata/abort-fixture.c               |  37 ++
 runner/testdata/abort-simple.c                |  29 ++
 runner/testdata/abort.c                       |  36 ++
 runner/testdata/meson.build                   |   4 +
 tests/kms_chamelium.c                         |  11 +-
 tests/kms_color_chamelium.c                   |   7 +-
 44 files changed, 1287 insertions(+), 400 deletions(-)
 create mode 100644 lib/tests/igt_abort.c
 create mode 100644 runner/testdata/abort-dynamic.c
 create mode 100644 runner/testdata/abort-fixture.c
 create mode 100644 runner/testdata/abort-simple.c
 create mode 100644 runner/testdata/abort.c

-- 
2.24.1

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [igt-dev] [PATCH i-g-t 1/9] lib/tests: Extract fork helpers
  2020-02-12 13:21 [igt-dev] [PATCH i-g-t 0/9] Abort on Chamelium failure Arkadiusz Hiler
@ 2020-02-12 13:21 ` Arkadiusz Hiler
  2020-02-14 11:57   ` Petri Latvala
  2020-02-12 13:21 ` [igt-dev] [PATCH i-g-t 2/9] lib/tests: Add support for redirecting fork output to /dev/null Arkadiusz Hiler
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 29+ messages in thread
From: Arkadiusz Hiler @ 2020-02-12 13:21 UTC (permalink / raw)
  To: igt-dev; +Cc: Petri Latvala

Because of excessive 'copy and paste' we ended up with multiple copies
of almost the same fork helper. This patch extracts the do_fork helper
out and switches all the tests over to it.

Additionally, preemptively I have extracted the more fancy fork helper
that captures stderr/out + related functions out of igt_describe tests.

Signed-off-by: Arkadiusz Hiler <arkadiusz.hiler@intel.com>
---
 lib/tests/igt_assert.c               |  35 +++----
 lib/tests/igt_conflicting_args.c     |  25 ++---
 lib/tests/igt_describe.c             | 135 ++++++---------------------
 lib/tests/igt_dynamic_subtests.c     |  18 ----
 lib/tests/igt_fork.c                 |  71 ++++++--------
 lib/tests/igt_invalid_subtest_name.c |  18 ----
 lib/tests/igt_no_exit.c              |  18 ----
 lib/tests/igt_segfault.c             |  59 +++++-------
 lib/tests/igt_simulation.c           | 101 +++++++++-----------
 lib/tests/igt_tests_common.h         |  91 ++++++++++++++++++
 10 files changed, 232 insertions(+), 339 deletions(-)

diff --git a/lib/tests/igt_assert.c b/lib/tests/igt_assert.c
index 1caf5d88..c94ac698 100644
--- a/lib/tests/igt_assert.c
+++ b/lib/tests/igt_assert.c
@@ -38,8 +38,6 @@
 
 #include "igt_tests_common.h"
 
-char test[] = "test";
-char *argv_run[] = { test };
 void (*test_to_run)(void) = NULL;
 
 /*
@@ -55,26 +53,17 @@ void (*test_to_run)(void) = NULL;
 	exec_total++; \
 }
 
-static int do_fork(void)
+static void fake_test(void)
 {
-	int pid, status;
-	int argc;
-
-	switch (pid = fork()) {
-	case -1:
-		internal_assert(0);
-	case 0:
-		argc = ARRAY_SIZE(argv_run);
-		igt_simple_init(argc, argv_run);
-		test_to_run();
-		igt_exit();
-	default:
-		while (waitpid(pid, &status, 0) == -1 &&
-		       errno == EINTR)
-			;
-
-		return status;
-	}
+	char test[] = "test";
+	char *argv_run[] = { test };
+	int argc = ARRAY_SIZE(argv_run);
+
+	igt_simple_init(argc, argv_run);
+
+	test_to_run();
+
+	igt_exit();
 }
 
 static void test_cmpint_negative(void)
@@ -150,7 +139,7 @@ igt_main
 	 * we inherit the state from the parent, so ...
 	 */
 	test_to_run = test_cmpint_negative;
-	ret = do_fork();
+	ret = do_fork(fake_test);
 	igt_subtest("igt_cmpint_negative")
 		internal_assert_wexited(ret, IGT_EXIT_FAILURE);
 
@@ -158,7 +147,7 @@ igt_main
 		test_fd();
 
 	test_to_run = test_fd_negative;
-	ret = do_fork();
+	ret = do_fork(fake_test);
 	igt_subtest("igt_assert_fd_negative")
 		internal_assert_wexited(ret, IGT_EXIT_FAILURE);
 }
diff --git a/lib/tests/igt_conflicting_args.c b/lib/tests/igt_conflicting_args.c
index f600abd4..b644fd4b 100644
--- a/lib/tests/igt_conflicting_args.c
+++ b/lib/tests/igt_conflicting_args.c
@@ -43,25 +43,12 @@ static int opt_handler(int option, int option_index, void *input)
 	return 0;
 }
 
-static int do_fork(void)
+static void fake_test(void)
 {
 	char test_name[] = "test";
-
 	char *argv[] = { test_name };
 	int argc = ARRAY_SIZE(argv);
 
-	pid_t pid = fork();
-	internal_assert(pid != -1);
-
-	if (pid) {
-		int status;
-		while (waitpid(pid, &status, 0) == -1 && errno == EINTR)
-			;
-
-		return status;
-	}
-
-
 	igt_subtest_init_parse_opts(&argc, argv, short_options, long_options,
 				    "", opt_handler, NULL);
 	igt_subtest("dummy") {}
@@ -73,27 +60,27 @@ int main(int argc, char **argv)
 	/* no conflict */
 	long_options[0] = (struct option) { "iterations", required_argument, NULL, 'i'};
 	short_options = "";
-	internal_assert_wexited(do_fork(), 0);
+	internal_assert_wexited(do_fork(fake_test), 0);
 
 	/* conflict on short option */
 	long_options[0] = (struct option) { "iterations", required_argument, NULL, 'i'};
 	short_options = "h";
-	internal_assert_wsignaled(do_fork(), SIGABRT);
+	internal_assert_wsignaled(do_fork(fake_test), SIGABRT);
 
 	/* conflict on long option name */
 	long_options[0] = (struct option) { "help", required_argument, NULL, 'i'};
 	short_options = "";
-	internal_assert_wsignaled(do_fork(), SIGABRT);
+	internal_assert_wsignaled(do_fork(fake_test), SIGABRT);
 
 	/* conflict on long option 'val' representation vs short option */
 	long_options[0] = (struct option) { "iterations", required_argument, NULL, 'h'};
 	short_options = "";
-	internal_assert_wsignaled(do_fork(), SIGABRT);
+	internal_assert_wsignaled(do_fork(fake_test), SIGABRT);
 
 	/* conflict on long option 'val' representations */
 	long_options[0] = (struct option) { "iterations", required_argument, NULL, 500};
 	short_options = "";
-	internal_assert_wsignaled(do_fork(), SIGABRT);
+	internal_assert_wsignaled(do_fork(fake_test), SIGABRT);
 
 	return 0;
 }
diff --git a/lib/tests/igt_describe.c b/lib/tests/igt_describe.c
index 6f3a4319..7b4fa9af 100644
--- a/lib/tests/igt_describe.c
+++ b/lib/tests/igt_describe.c
@@ -28,9 +28,15 @@
 #include "drmtest.h"
 #include "igt_tests_common.h"
 
+char prog[] = "igt_describe";
+char fake_arg[100];
+char *fake_argv[] = {prog, fake_arg};
+int fake_argc = ARRAY_SIZE(fake_argv);
+
 IGT_TEST_DESCRIPTION("the top level description");
-static void fake_main(int argc, char **argv) {
-	igt_subtest_init(argc, argv);
+static void fake_main(void)
+{
+	igt_subtest_init(fake_argc, fake_argv);
 
 	igt_describe("Basic A");
 	igt_subtest("A")
@@ -101,33 +107,33 @@ static void fake_main(int argc, char **argv) {
 static const char DESCRIBE_ALL_OUTPUT[] = \
 	"the top level description\n"
 	"\n"
-	"SUB A ../lib/tests/igt_describe.c:36:\n"
+	"SUB A ../lib/tests/igt_describe.c:42:\n"
 	"  Basic A\n"
 	"\n"
-	"SUB B ../lib/tests/igt_describe.c:45:\n"
+	"SUB B ../lib/tests/igt_describe.c:51:\n"
 	"  Group with B, C & D\n"
 	"\n"
 	"  Basic B\n"
 	"\n"
-	"SUB C ../lib/tests/igt_describe.c:54:\n"
+	"SUB C ../lib/tests/igt_describe.c:60:\n"
 	"  Group with B, C & D\n"
 	"\n"
 	"  Group with C & D\n"
 	"\n"
 	"  Basic C\n"
 	"\n"
-	"SUB D ../lib/tests/igt_describe.c:58:\n"
+	"SUB D ../lib/tests/igt_describe.c:64:\n"
 	"  Group with B, C & D\n"
 	"\n"
 	"  Group with C & D\n"
 	"\n"
-	"SUB E ../lib/tests/igt_describe.c:66:\n"
+	"SUB E ../lib/tests/igt_describe.c:72:\n"
 	"  NO DOCUMENTATION!\n"
 	"\n"
-	"SUB F ../lib/tests/igt_describe.c:71:\n"
+	"SUB F ../lib/tests/igt_describe.c:77:\n"
 	"  NO DOCUMENTATION!\n"
 	"\n"
-	"SUB G ../lib/tests/igt_describe.c:80:\n"
+	"SUB G ../lib/tests/igt_describe.c:86:\n"
 	"  this description should be so long that it wraps itself nicely in the terminal this\n"
 	"  description should be so long that it wraps itself nicely in the terminal this description\n"
 	"  should be so long that it wraps itself nicely in the terminal this description should be so\n"
@@ -135,17 +141,17 @@ static const char DESCRIBE_ALL_OUTPUT[] = \
 	"  wraps itself nicely in the terminal this description should be so long that it wraps itself\n"
 	"  nicely in the terminal\n"
 	"\n"
-	"SUB F ../lib/tests/igt_describe.c:87:\n"
+	"SUB F ../lib/tests/igt_describe.c:93:\n"
 	"  verylongwordthatshoudlbeprintedeventhoughitspastthewrppinglimitverylongwordthatshoudlbeprintedeventhoughitspastthewrappinglimit\n"
 	"  verylongwordthatshoudlbeprintedeventhoughitspastthewrappinglimitverylongwordthatshoudlbeprintedeventhoughitspastthewrappinglimit\n"
 	"\n"
-	"SUB G ../lib/tests/igt_describe.c:91:\n"
+	"SUB G ../lib/tests/igt_describe.c:97:\n"
 	"  Subtest with dynamic subsubtests\n\n";
 
 static const char JUST_C_OUTPUT[] = \
 	"the top level description\n"
 	"\n"
-	"SUB C ../lib/tests/igt_describe.c:54:\n"
+	"SUB C ../lib/tests/igt_describe.c:60:\n"
 	"  Group with B, C & D\n"
 	"\n"
 	"  Group with C & D\n"
@@ -153,95 +159,22 @@ static const char JUST_C_OUTPUT[] = \
 	"  Basic C\n"
 	"\n";
 
-static void assert_pipe_empty(int fd)
-{
-	char buf[5];
-	internal_assert(0 == read(fd, buf, sizeof(buf)));
-}
-
-static void read_whole_pipe(int fd, char *buf, size_t buflen)
-{
-	ssize_t readlen;
-	off_t offset;
-
-	offset = 0;
-	while ((readlen = read(fd, buf+offset, buflen-offset))) {
-		if (readlen == -1) {
-			if (errno == EINTR) {
-				continue;
-			} else {
-				printf("read failed with %s\n", strerror(errno));
-				exit(1);
-			}
-		}
-		internal_assert(readlen != -1);
-		offset += readlen;
-	}
-}
-
-static pid_t do_fork(int argc, char **argv, int *out, int *err)
-{
-	int outfd[2], errfd[2];
-	pid_t pid;
-
-	internal_assert(pipe(outfd) != -1);
-	internal_assert(pipe(errfd) != -1);
-
-	pid = fork();
-	internal_assert(pid != -1);
-
-	if (pid == 0) {
-		while (dup2(outfd[1], STDOUT_FILENO) == -1 && errno == EINTR) {}
-		while (dup2(errfd[1], STDERR_FILENO) == -1 && errno == EINTR) {}
-
-		close(outfd[0]);
-		close(outfd[1]);
-		close(errfd[0]);
-		close(errfd[1]);
-
-		fake_main(argc, argv);
-
-		exit(-1);
-	} else {
-		/* close the writing ends */
-		close(outfd[1]);
-		close(errfd[1]);
-
-		*out = outfd[0];
-		*err = errfd[0];
-
-		return pid;
-	}
-}
-
-static int _wait(pid_t pid, int *status) {
-	int ret;
-
-	do {
-		ret = waitpid(pid, status, 0);
-	} while (ret == -1 && errno == EINTR);
-
-	return ret;
-}
-
 int main(int argc, char **argv)
 {
-	char prog[] = "igt_describe";
 	int status;
 	int outfd, errfd;
+	pid_t pid;
 
 	/* describe all subtest */ {
 		static char out[4096];
-		char arg[] = "--describe";
-		char *fake_argv[] = {prog, arg};
-		int fake_argc = ARRAY_SIZE(fake_argv);
+		strncpy(fake_arg, "--describe", sizeof(fake_arg));
 
-		pid_t pid = do_fork(fake_argc, fake_argv, &outfd, &errfd);
+		pid = do_fork_bg_with_pipes(fake_main, &outfd, &errfd);
 
 		read_whole_pipe(outfd, out, sizeof(out));
 		assert_pipe_empty(errfd);
 
-		internal_assert(_wait(pid, &status) != -1);
+		internal_assert(safe_wait(pid, &status) != -1);
 		internal_assert(WIFEXITED(status));
 		internal_assert(WEXITSTATUS(status) == IGT_EXIT_SUCCESS);
 		internal_assert(0 == strcmp(DESCRIBE_ALL_OUTPUT, out));
@@ -252,16 +185,14 @@ int main(int argc, char **argv)
 
 	/* describe C using a pattern */ {
 		static char out[4096];
-		char arg[] = "--describe=C";
-		char *fake_argv[] = {prog, arg};
-		int fake_argc = ARRAY_SIZE(fake_argv);
+		strncpy(fake_arg, "--describe=C", sizeof(fake_arg));
 
-		pid_t pid = do_fork(fake_argc, fake_argv, &outfd, &errfd);
+		pid = do_fork_bg_with_pipes(fake_main, &outfd, &errfd);
 
 		read_whole_pipe(outfd, out, sizeof(out));
 		assert_pipe_empty(errfd);
 
-		internal_assert(_wait(pid, &status) != -1);
+		internal_assert(safe_wait(pid, &status) != -1);
 		internal_assert(WIFEXITED(status));
 		internal_assert(WEXITSTATUS(status) == IGT_EXIT_SUCCESS);
 		internal_assert(0 == strcmp(JUST_C_OUTPUT, out));
@@ -272,15 +203,13 @@ int main(int argc, char **argv)
 
 	/* fail describing with a bad pattern */ {
 		static char err[4096];
-		char arg[] = "--describe=Z";
-		char *fake_argv[] = {prog, arg};
-		int fake_argc = ARRAY_SIZE(fake_argv);
+		strncpy(fake_arg, "--describe=Z", sizeof(fake_arg));
 
-		pid_t pid = do_fork(fake_argc, fake_argv, &outfd, &errfd);
+		pid = do_fork_bg_with_pipes(fake_main, &outfd, &errfd);
 
 		read_whole_pipe(errfd, err, sizeof(err));
 
-		internal_assert(_wait(pid, &status) != -1);
+		internal_assert(safe_wait(pid, &status) != -1);
 		internal_assert(WIFEXITED(status));
 		internal_assert(WEXITSTATUS(status) == IGT_EXIT_INVALID);
 		internal_assert(strstr(err, "Unknown subtest: Z"));
@@ -291,15 +220,13 @@ int main(int argc, char **argv)
 
 	/* trying to igt_describe a dynamic subsubtest should assert */ {
 		static char err[4096];
-		char arg[] = "--run-subtest=G";
-		char *fake_argv[] = {prog, arg};
-		int fake_argc = ARRAY_SIZE(fake_argv);
+		strncpy(fake_arg, "--run-subtest=G", sizeof(fake_arg));
 
-		pid_t pid = do_fork(fake_argc, fake_argv, &outfd, &errfd);
+		pid = do_fork_bg_with_pipes(fake_main, &outfd, &errfd);
 
 		read_whole_pipe(errfd, err, sizeof(err));
 
-		internal_assert(_wait(pid, &status) != -1);
+		internal_assert(safe_wait(pid, &status) != -1);
 		internal_assert_wsignaled(status, SIGABRT);
 
 		close(outfd);
diff --git a/lib/tests/igt_dynamic_subtests.c b/lib/tests/igt_dynamic_subtests.c
index 606104c5..bd1e1675 100644
--- a/lib/tests/igt_dynamic_subtests.c
+++ b/lib/tests/igt_dynamic_subtests.c
@@ -29,24 +29,6 @@
 
 #include "igt_tests_common.h"
 
-static int do_fork(void (*test_to_run)(void))
-{
-	int pid, status;
-
-	switch (pid = fork()) {
-	case -1:
-		internal_assert(0);
-	case 0:
-		test_to_run();
-	default:
-		while (waitpid(pid, &status, 0) == -1 &&
-		       errno == EINTR)
-			;
-
-		return status;
-	}
-}
-
 static void dynamic_subtest_in_normal_subtest(void)
 {
 	char prog[] = "igt_no_exit";
diff --git a/lib/tests/igt_fork.c b/lib/tests/igt_fork.c
index e30584fd..4fd0e0c8 100644
--- a/lib/tests/igt_fork.c
+++ b/lib/tests/igt_fork.c
@@ -35,37 +35,52 @@
 #include "igt_tests_common.h"
 
 char test[] = "test";
-char *argv_run[] = { test };
+char *fake_argv[] = { test };
+int fake_argc = ARRAY_SIZE(fake_argv);
 
 static void igt_fork_vs_skip(void)
 {
+	igt_simple_init(fake_argc, fake_argv);
+
 	igt_fork(i, 1) {
 		igt_skip("skipping");
 	}
 
 	igt_waitchildren();
+
+	igt_exit();
 }
 
 static void igt_fork_vs_assert(void)
 {
+	igt_simple_init(fake_argc, fake_argv);
+
 	igt_fork(i, 1) {
 		igt_assert(0);
 	}
 
 	igt_waitchildren();
+
+	igt_exit();
 }
 
 static void igt_fork_leak(void)
 {
+	igt_simple_init(fake_argc, fake_argv);
+
 	igt_fork(i, 1) {
 		sleep(10);
 	}
+
+	igt_exit();
 }
 
 static void plain_fork_leak(void)
 {
 	int pid;
 
+	igt_simple_init(fake_argc, fake_argv);
+
 	switch (pid = fork()) {
 	case -1:
 		internal_assert(0);
@@ -74,59 +89,21 @@ static void plain_fork_leak(void)
 	default:
 		exit(0);
 	}
+
+	igt_exit();
 }
 
 static void igt_fork_timeout_leak(void)
 {
+	igt_simple_init(fake_argc, fake_argv);
+
 	igt_fork(i, 1) {
 		sleep(10);
 	}
 
 	igt_waitchildren_timeout(1, "library test");
-}
-
-static int do_fork(void (*test_to_run)(void))
-{
-	int pid, status;
-	int argc;
-
-	switch (pid = fork()) {
-	case -1:
-		internal_assert(0);
-	case 0:
-		argc = ARRAY_SIZE(argv_run);
-		igt_simple_init(argc, argv_run);
-		test_to_run();
-		igt_exit();
-	default:
-		while (waitpid(pid, &status, 0) == -1 &&
-		       errno == EINTR)
-			;
-
-		return status;
-	}
-}
-
-static int do_subtest(void (*test_to_run)(void))
-{
-	int pid, status;
-	int argc;
-
-	switch (pid = fork()) {
-	case -1:
-		internal_assert(0);
-	case 0:
-		argc = ARRAY_SIZE(argv_run);
-		igt_subtest_init(argc, argv_run);
-		test_to_run();
-		igt_exit();
-	default:
-		while (waitpid(pid, &status, 0) == -1 &&
-		       errno == EINTR)
-			;
 
-		return status;
-	}
+	igt_exit();
 }
 
 static void subtest_leak(void)
@@ -135,6 +112,8 @@ static void subtest_leak(void)
 		mmap(0, 4096, PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
 	const int num_children = 4096 / sizeof(*children);
 
+	igt_subtest_init(fake_argc, fake_argv);
+
 	igt_subtest("fork-leak") {
 		igt_fork(child, num_children)
 			children[child] = getpid();
@@ -148,6 +127,8 @@ static void subtest_leak(void)
 		assert(kill(children[i], 0) == -1 && errno == ESRCH);
 
 	munmap(children, 4096);
+
+	igt_exit();
 }
 
 int main(int argc, char **argv)
@@ -174,6 +155,6 @@ int main(int argc, char **argv)
 	ret = do_fork(plain_fork_leak);
 	internal_assert_wsignaled(ret, SIGABRT);
 
-	ret = do_subtest(subtest_leak);
+	ret = do_fork(subtest_leak);
 	internal_assert_wexited(ret, IGT_EXIT_FAILURE); /* not asserted! */
 }
diff --git a/lib/tests/igt_invalid_subtest_name.c b/lib/tests/igt_invalid_subtest_name.c
index 92e767ab..32c4bcbc 100644
--- a/lib/tests/igt_invalid_subtest_name.c
+++ b/lib/tests/igt_invalid_subtest_name.c
@@ -60,24 +60,6 @@ static void nonexisting_subtest(void)
 	igt_exit();
 }
 
-static int do_fork(void (*test_to_run)(void))
-{
-	int pid, status;
-
-	switch (pid = fork()) {
-	case -1:
-		internal_assert(0);
-	case 0:
-		test_to_run();
-	default:
-		while (waitpid(pid, &status, 0) == -1 &&
-		       errno == EINTR)
-			;
-
-		return status;
-	}
-}
-
 int main(int argc, char **argv)
 {
 	int ret;
diff --git a/lib/tests/igt_no_exit.c b/lib/tests/igt_no_exit.c
index 82f00b52..d303eba7 100644
--- a/lib/tests/igt_no_exit.c
+++ b/lib/tests/igt_no_exit.c
@@ -56,24 +56,6 @@ static void no_exit(void)
 		;
 }
 
-static int do_fork(void (*test_to_run)(void))
-{
-	int pid, status;
-
-	switch (pid = fork()) {
-	case -1:
-		internal_assert(0);
-	case 0:
-		test_to_run();
-	default:
-		while (waitpid(pid, &status, 0) == -1 &&
-		       errno == EINTR)
-			;
-
-		return status;
-	}
-}
-
 int main(int argc, char **argv)
 {
 	int ret;
diff --git a/lib/tests/igt_segfault.c b/lib/tests/igt_segfault.c
index 0d872f67..38c040a6 100644
--- a/lib/tests/igt_segfault.c
+++ b/lib/tests/igt_segfault.c
@@ -48,51 +48,38 @@
 bool simple;
 bool runa;
 bool runc;
-char test[] = "test";
-char *argv_run[] = { test };
 
 static void crashme(void)
 {
 	raise(SIGSEGV);
 }
 
-static int do_fork(void)
+static void fake_test(void)
 {
-	int pid, status;
-	int argc;
-
-	switch (pid = fork()) {
-	case -1:
-		internal_assert(0);
-	case 0:
-		argc = ARRAY_SIZE(argv_run);
-		if (simple) {
-			igt_simple_init(argc, argv_run);
-			crashme();
+	char prog[] = "test";
+	char *fake_argv[] = { prog };
+	int fake_argc = ARRAY_SIZE(fake_argv);
 
-			igt_exit();
-		} else {
-			igt_subtest_init(argc, argv_run);
 
-			if(runa)
-				igt_subtest("A")
-					;
+	if (simple) {
+		igt_simple_init(fake_argc, fake_argv);
+		crashme();
 
-			igt_subtest("B")
-				crashme();
+		igt_exit();
+	} else {
+		igt_subtest_init(fake_argc, fake_argv);
+		if(runa)
+			igt_subtest("A")
+				;
 
-			if(runc)
-				igt_subtest("C")
-					;
+		igt_subtest("B")
+			crashme();
 
-			igt_exit();
-		}
-	default:
-		while (waitpid(pid, &status, 0) == -1 &&
-		       errno == EINTR)
-			;
+		if(runc)
+			igt_subtest("C")
+				;
 
-		return status;
+		igt_exit();
 	}
 }
 
@@ -104,20 +91,20 @@ int main(int argc, char **argv)
 	runc=false;
 	igt_info("Simple test.\n");
 	fflush(stdout);
-	internal_assert_wsignaled(do_fork(), SIGSEGV);
+	internal_assert_wsignaled(do_fork(fake_test), SIGSEGV);
 
 	/* Test crash in a single subtest is reported */
 	simple = false;
 	igt_info("Single subtest.\n");
 	fflush(stdout);
-	internal_assert_wexited(do_fork(), SIGSEGV + 128);
+	internal_assert_wexited(do_fork(fake_test), SIGSEGV + 128);
 
 	/* Test crash in a subtest following a pass is reported */
 	simple = false;
 	runa=true;
 	igt_info("Passing then crashing subtest.\n");
 	fflush(stdout);
-	internal_assert_wexited(do_fork(), SIGSEGV + 128);
+	internal_assert_wexited(do_fork(fake_test), SIGSEGV + 128);
 
 	/* Test crash in a subtest preceeding a pass is reported */
 	simple = false;
@@ -125,7 +112,7 @@ int main(int argc, char **argv)
 	runc=true;
 	igt_info("Crashing then passing subtest.\n");
 	fflush(stdout);
-	internal_assert_wexited(do_fork(), SIGSEGV + 128);
+	internal_assert_wexited(do_fork(fake_test), SIGSEGV + 128);
 
 	return 0;
 }
diff --git a/lib/tests/igt_simulation.c b/lib/tests/igt_simulation.c
index 3f3cd88f..a0ea7000 100644
--- a/lib/tests/igt_simulation.c
+++ b/lib/tests/igt_simulation.c
@@ -40,59 +40,44 @@ bool list_subtests;
 bool in_fixture;
 bool in_subtest;
 
-char test[] = "test";
-char list[] = "--list-subtests";
-char *argv_list[] = { test, list };
-char *argv_run[] = { test };
-
-static int do_fork(void)
+static void fake_test(void)
 {
-	int pid, status;
+	char test[] = "test";
+	char list[] = "--list-subtests";
+	char *argv_list[] = { test, list };
+	char *argv_run[] = { test };
 	int argc;
 
-	switch (pid = fork()) {
-	case -1:
-		internal_assert(0);
-	case 0:
-		if (simple) {
-			argc = 1;
-			igt_simple_init(argc, argv_run);
+	if (simple) {
+		argc = 1;
+		igt_simple_init(argc, argv_run);
 
-			igt_skip_on_simulation();
+		igt_skip_on_simulation();
 
-			igt_exit();
+		igt_exit();
+	} else {
+		if (list_subtests) {
+			argc = 2;
+			igt_subtest_init(argc, argv_list);
 		} else {
-			if (list_subtests) {
-				argc = 2;
-				igt_subtest_init(argc, argv_list);
-			} else {
-				argc = 1;
-				igt_subtest_init(argc, argv_run);
-			}
-
-			if (in_fixture) {
-				igt_fixture
-					igt_skip_on_simulation();
-			} if (in_subtest) {
-				igt_subtest("sim")
-					igt_skip_on_simulation();
-			} else
-				igt_skip_on_simulation();
-
-			if (!in_subtest)
-				igt_subtest("foo")
-					;
-
-			igt_exit();
+			argc = 1;
+			igt_subtest_init(argc, argv_run);
 		}
-	default:
-		while (waitpid(pid, &status, 0) == -1 &&
-		       errno == EINTR)
-			;
 
-		internal_assert(WIFEXITED(status));
+		if (in_fixture) {
+			igt_fixture
+				igt_skip_on_simulation();
+		} if (in_subtest) {
+			igt_subtest("sim")
+				igt_skip_on_simulation();
+		} else
+			igt_skip_on_simulation();
+
+		if (!in_subtest)
+			igt_subtest("foo")
+				;
 
-		return status;
+		igt_exit();
 	}
 }
 
@@ -101,10 +86,10 @@ int main(int argc, char **argv)
 	/* simple tests */
 	simple = true;
 	internal_assert(setenv("INTEL_SIMULATION", "1", 1) == 0);
-	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SKIP);
+	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SKIP);
 
 	internal_assert(setenv("INTEL_SIMULATION", "0", 1) == 0);
-	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SUCCESS);
+	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SUCCESS);
 
 	/* subtests, list mode */
 	simple = false;
@@ -112,28 +97,28 @@ int main(int argc, char **argv)
 
 	in_fixture = false;
 	internal_assert(setenv("INTEL_SIMULATION", "1", 1) == 0);
-	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SUCCESS);
+	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SUCCESS);
 
 	internal_assert(setenv("INTEL_SIMULATION", "0", 1) == 0);
-	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SUCCESS);
+	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SUCCESS);
 
 	in_fixture = true;
 	internal_assert(setenv("INTEL_SIMULATION", "1", 1) == 0);
-	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SUCCESS);
+	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SUCCESS);
 
 
 	internal_assert(setenv("INTEL_SIMULATION", "0", 1) == 0);
-	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SUCCESS);
+	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SUCCESS);
 
 
 	in_fixture = false;
 	in_subtest = true;
 	internal_assert(setenv("INTEL_SIMULATION", "1", 1) == 0);
-	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SUCCESS);
+	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SUCCESS);
 
 
 	internal_assert(setenv("INTEL_SIMULATION", "0", 1) == 0);
-	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SUCCESS);
+	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SUCCESS);
 
 
 	/* subtest, run mode */
@@ -142,29 +127,29 @@ int main(int argc, char **argv)
 
 	in_fixture = false;
 	internal_assert(setenv("INTEL_SIMULATION", "1", 1) == 0);
-	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SKIP);
+	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SKIP);
 
 	internal_assert(setenv("INTEL_SIMULATION", "0", 1) == 0);
-	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SUCCESS);
+	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SUCCESS);
 
 
 	in_fixture = true;
 	internal_assert(setenv("INTEL_SIMULATION", "1", 1) == 0);
-	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SKIP);
+	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SKIP);
 
 
 	internal_assert(setenv("INTEL_SIMULATION", "0", 1) == 0);
-	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SUCCESS);
+	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SUCCESS);
 
 
 	in_fixture = false;
 	in_subtest = true;
 	internal_assert(setenv("INTEL_SIMULATION", "1", 1) == 0);
-	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SKIP);
+	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SKIP);
 
 
 	internal_assert(setenv("INTEL_SIMULATION", "0", 1) == 0);
-	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SUCCESS);
+	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SUCCESS);
 
 
 	return 0;
diff --git a/lib/tests/igt_tests_common.h b/lib/tests/igt_tests_common.h
index e66ee37c..b3da3b34 100644
--- a/lib/tests/igt_tests_common.h
+++ b/lib/tests/igt_tests_common.h
@@ -26,6 +26,8 @@
 #define IGT_LIB_TESTS_COMMON_H
 
 #include <assert.h>
+#include <sys/wait.h>
+#include <errno.h>
 
 /*
  * We need to hide assert from the cocci igt test refactor spatch.
@@ -46,4 +48,93 @@ static inline void internal_assert_wsignaled(int wstatus, int signal)
 	internal_assert(WIFSIGNALED(wstatus) &&
 			WTERMSIG(wstatus) == signal);
 }
+
+static inline int do_fork(void (*test_to_run)(void))
+{
+	int pid, status;
+
+	switch (pid = fork()) {
+	case -1:
+		internal_assert(0);
+	case 0:
+		test_to_run();
+	default:
+		while (waitpid(pid, &status, 0) == -1 &&
+		       errno == EINTR)
+			;
+
+		return status;
+	}
+}
+
+static inline pid_t do_fork_bg_with_pipes(void (*test_to_run)(void), int *out, int *err)
+{
+	int outfd[2], errfd[2];
+	pid_t pid;
+
+	internal_assert(pipe(outfd) != -1);
+	internal_assert(pipe(errfd) != -1);
+
+	pid = fork();
+	internal_assert(pid != -1);
+
+	if (pid == 0) {
+		while (dup2(outfd[1], STDOUT_FILENO) == -1 && errno == EINTR) {}
+		while (dup2(errfd[1], STDERR_FILENO) == -1 && errno == EINTR) {}
+
+		close(outfd[0]);
+		close(outfd[1]);
+		close(errfd[0]);
+		close(errfd[1]);
+
+		test_to_run();
+
+		exit(-1);
+	} else {
+		/* close the writing ends */
+		close(outfd[1]);
+		close(errfd[1]);
+
+		*out = outfd[0];
+		*err = errfd[0];
+
+		return pid;
+	}
+}
+
+static inline int safe_wait(pid_t pid, int *status) {
+	int ret;
+
+	do {
+		ret = waitpid(pid, status, 0);
+	} while (ret == -1 && errno == EINTR);
+
+	return ret;
+}
+
+static inline void assert_pipe_empty(int fd)
+{
+	char buf[5];
+	internal_assert(0 == read(fd, buf, sizeof(buf)));
+}
+
+static inline void read_whole_pipe(int fd, char *buf, size_t buflen)
+{
+	ssize_t readlen;
+	off_t offset;
+
+	offset = 0;
+	while ((readlen = read(fd, buf+offset, buflen-offset))) {
+		if (readlen == -1) {
+			if (errno == EINTR) {
+				continue;
+			} else {
+				printf("read failed with %s\n", strerror(errno));
+				exit(1);
+			}
+		}
+		internal_assert(readlen != -1);
+		offset += readlen;
+	}
+}
 #endif
-- 
2.24.1

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [igt-dev] [PATCH i-g-t 2/9] lib/tests: Add support for redirecting fork output to /dev/null
  2020-02-12 13:21 [igt-dev] [PATCH i-g-t 0/9] Abort on Chamelium failure Arkadiusz Hiler
  2020-02-12 13:21 ` [igt-dev] [PATCH i-g-t 1/9] lib/tests: Extract fork helpers Arkadiusz Hiler
@ 2020-02-12 13:21 ` Arkadiusz Hiler
  2020-02-14 12:01   ` Petri Latvala
  2020-02-12 13:21 ` [igt-dev] [PATCH i-g-t 3/9] lib: Make it possible to abort the whole execution from inside of a test Arkadiusz Hiler
                   ` (8 subsequent siblings)
  10 siblings, 1 reply; 29+ messages in thread
From: Arkadiusz Hiler @ 2020-02-12 13:21 UTC (permalink / raw)
  To: igt-dev; +Cc: Petri Latvala

Trying to read interleaved writes is a bit tricky, so let's just use
/dev/null if we care about contents on only one of those pipes.

Signed-off-by: Arkadiusz Hiler <arkadiusz.hiler@intel.com>
---
 lib/tests/igt_tests_common.h | 35 +++++++++++++++++++++++++++--------
 1 file changed, 27 insertions(+), 8 deletions(-)

diff --git a/lib/tests/igt_tests_common.h b/lib/tests/igt_tests_common.h
index b3da3b34..f285d657 100644
--- a/lib/tests/igt_tests_common.h
+++ b/lib/tests/igt_tests_common.h
@@ -28,6 +28,8 @@
 #include <assert.h>
 #include <sys/wait.h>
 #include <errno.h>
+#include <sys/stat.h>
+#include <fcntl.h>
 
 /*
  * We need to hide assert from the cocci igt test refactor spatch.
@@ -72,19 +74,32 @@ static inline pid_t do_fork_bg_with_pipes(void (*test_to_run)(void), int *out, i
 	int outfd[2], errfd[2];
 	pid_t pid;
 
-	internal_assert(pipe(outfd) != -1);
-	internal_assert(pipe(errfd) != -1);
+	if (out != NULL)
+		internal_assert(pipe(outfd) != -1);
+
+	if (err != NULL)
+		internal_assert(pipe(errfd) != -1);
 
 	pid = fork();
 	internal_assert(pid != -1);
 
 	if (pid == 0) {
+		/* we'll leak the /dev/null fds, let them die with the forked
+		 * process, also close reading ends if they are any */
+		if (out == NULL)
+			outfd[1] = open("/dev/null", O_WRONLY);
+		else
+			close(outfd[0]);
+
+		if (err == NULL)
+			errfd[1] = open("/dev/null", O_WRONLY);
+		else
+			close(errfd[0]);
+
 		while (dup2(outfd[1], STDOUT_FILENO) == -1 && errno == EINTR) {}
 		while (dup2(errfd[1], STDERR_FILENO) == -1 && errno == EINTR) {}
 
-		close(outfd[0]);
 		close(outfd[1]);
-		close(errfd[0]);
 		close(errfd[1]);
 
 		test_to_run();
@@ -92,11 +107,15 @@ static inline pid_t do_fork_bg_with_pipes(void (*test_to_run)(void), int *out, i
 		exit(-1);
 	} else {
 		/* close the writing ends */
-		close(outfd[1]);
-		close(errfd[1]);
+		if (out != NULL) {
+			close(outfd[1]);
+			*out = outfd[0];
+		}
 
-		*out = outfd[0];
-		*err = errfd[0];
+		if (err != NULL) {
+			close(errfd[1]);
+			*err = errfd[0];
+		}
 
 		return pid;
 	}
-- 
2.24.1

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [igt-dev] [PATCH i-g-t 3/9] lib: Make it possible to abort the whole execution from inside of a test
  2020-02-12 13:21 [igt-dev] [PATCH i-g-t 0/9] Abort on Chamelium failure Arkadiusz Hiler
  2020-02-12 13:21 ` [igt-dev] [PATCH i-g-t 1/9] lib/tests: Extract fork helpers Arkadiusz Hiler
  2020-02-12 13:21 ` [igt-dev] [PATCH i-g-t 2/9] lib/tests: Add support for redirecting fork output to /dev/null Arkadiusz Hiler
@ 2020-02-12 13:21 ` Arkadiusz Hiler
  2020-02-14 12:04   ` Petri Latvala
  2020-02-12 13:21 ` [igt-dev] [PATCH i-g-t 4/9] runner/runner_tests: Extract helper for inspecting test result Arkadiusz Hiler
                   ` (7 subsequent siblings)
  10 siblings, 1 reply; 29+ messages in thread
From: Arkadiusz Hiler @ 2020-02-12 13:21 UTC (permalink / raw)
  To: igt-dev; +Cc: Petri Latvala

igt_abort_on_f() is introduced which does very little cleanup and causes
a hard exit() of the test binary with a unique exit code
(IGT_EXIT_ABORT).

The exit code informs the monitoring process that there is a critical
issue with the testing environment which may have an impact on the
results if testing continues.

Signed-off-by: Arkadiusz Hiler <arkadiusz.hiler@intel.com>
---
 lib/igt_core.c        |  46 ++++++++-
 lib/igt_core.h        |  29 ++++++
 lib/tests/igt_abort.c | 227 ++++++++++++++++++++++++++++++++++++++++++
 lib/tests/meson.build |   1 +
 4 files changed, 300 insertions(+), 3 deletions(-)
 create mode 100644 lib/tests/igt_abort.c

diff --git a/lib/igt_core.c b/lib/igt_core.c
index 51041793..8bd1e642 100644
--- a/lib/igt_core.c
+++ b/lib/igt_core.c
@@ -587,6 +587,7 @@ static void ftrace_dump_on_oops(bool enable)
 }
 
 bool igt_exit_called;
+bool igt_is_aborting;
 static void common_exit_handler(int sig)
 {
 	if (!igt_only_list_subtests()) {
@@ -595,7 +596,7 @@ static void common_exit_handler(int sig)
 
 	/* When not killed by a signal check that igt_exit() has been properly
 	 * called. */
-	assert(sig != 0 || igt_exit_called);
+	assert(sig != 0 || igt_exit_called || igt_is_aborting);
 }
 
 static void print_line_wrapping(const char *indent, const char *text)
@@ -1944,6 +1945,46 @@ void __igt_fail_assert(const char *domain, const char *file, const int line,
 	igt_fail(IGT_EXIT_FAILURE);
 }
 
+static void kill_children(void)
+{
+	for (int c = 0; c < num_test_children; c++)
+		kill(test_children[c], SIGKILL);
+}
+
+void __igt_abort(const char *domain, const char *file, const int line,
+		 const char *func, const char *expression,
+		 const char *f, ...)
+{
+	va_list args;
+	int err = errno;
+
+	igt_is_aborting = true;
+
+	igt_log(domain, IGT_LOG_CRITICAL,
+		"Test abort in function %s, file %s:%i:\n", func, file,
+		line);
+	igt_log(domain, IGT_LOG_CRITICAL, "abort condition: %s\n", expression);
+	if (err)
+		igt_log(domain, IGT_LOG_CRITICAL, "Last errno: %i, %s\n", err,
+			strerror(err));
+
+	if (f) {
+		va_start(args, f);
+		igt_vlog(domain, IGT_LOG_CRITICAL, f, args);
+		va_end(args);
+	}
+
+	/* just try our best, we are aborting the execution anyway */
+	kill_children();
+
+	print_backtrace();
+
+	if (running_under_gdb())
+		abort();
+
+	exit(IGT_EXIT_ABORT);
+}
+
 /**
  * igt_exit:
  *
@@ -1993,8 +2034,7 @@ void igt_exit(void)
 			 command_str, igt_exitcode);
 	igt_debug("Exiting with status code %d\n", igt_exitcode);
 
-	for (int c = 0; c < num_test_children; c++)
-		kill(test_children[c], SIGKILL);
+	kill_children();
 	assert(!num_test_children);
 
 	assert(waitpid(-1, &tmp, WNOHANG) == -1 && errno == ECHILD);
diff --git a/lib/igt_core.h b/lib/igt_core.h
index c17a7ba8..a79b41af 100644
--- a/lib/igt_core.h
+++ b/lib/igt_core.h
@@ -123,6 +123,14 @@ struct _GKeyFile *igt_load_igtrc(void);
  */
 #define IGT_EXIT_FAILURE 98
 
+/**
+ * IGT_EXIT_ABORT
+ *
+ * Exit status indicating a severe test/enviroment failure, any continued
+ * testing past this point can yeild unexpected reasults and is not recommended
+ */
+#define IGT_EXIT_ABORT 112
+
 bool __igt_fixture(void);
 void __igt_fixture_complete(void);
 void __igt_fixture_end(void) __attribute__((noreturn));
@@ -499,6 +507,11 @@ void __igt_fail_assert(const char *domain, const char *file,
 		       const int line, const char *func, const char *assertion,
 		       const char *format, ...)
 	__attribute__((noreturn));
+__attribute__((format(printf, 6, 7)))
+void __igt_abort(const char *domain, const char *file, const int line,
+		 const char *func, const char *expression,
+		 const char *f, ...)
+	__attribute__((noreturn));
 void igt_exit(void) __attribute__((noreturn));
 void igt_fatal_error(void) __attribute__((noreturn));
 
@@ -1027,6 +1040,22 @@ void igt_describe_f(const char *fmt, ...);
 	else igt_debug("Test requirement passed: !(%s)\n", #expr); \
 } while (0)
 
+
+/**
+ * igt_abort_on_f:
+ * @expr: condition to test
+ * @...: format string and optional arguments
+ *
+ * Aborts current execution if a condition is met.
+ *
+ * Should be used only when there is a serious issue with the environment and
+ * any further testing may be affected by it.
+ */
+#define igt_abort_on_f(expr, f...) \
+	do { if ((expr)) \
+		__igt_abort(IGT_LOG_DOMAIN, __FILE__, __LINE__, __func__, #expr , f); \
+	} while (0)
+
 /* fork support code */
 bool __igt_fork(void);
 
diff --git a/lib/tests/igt_abort.c b/lib/tests/igt_abort.c
new file mode 100644
index 00000000..53b7d4fd
--- /dev/null
+++ b/lib/tests/igt_abort.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright © 2020 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#include "igt_core.h"
+#include "drmtest.h"
+
+#include "igt_tests_common.h"
+
+char test[] = "test";
+char *fake_argv[] = { test };
+int fake_argc = ARRAY_SIZE(fake_argv);
+
+static void fake_simple_test(void)
+{
+	igt_simple_init(fake_argc, fake_argv);
+
+	igt_abort_on_f(true, "I'm out!\n");
+
+	exit(0); /* unreachable */
+}
+
+static void fake_fixture_test(void)
+{
+	igt_subtest_init(fake_argc, fake_argv);
+
+	igt_fixture {
+		igt_abort_on_f(true, "I'm out!\n");
+	}
+
+	exit(0); /* unreachable */
+}
+
+static void fake_outside_fixture_test(void)
+{
+	igt_subtest_init(fake_argc, fake_argv);
+
+	igt_abort_on_f(true, "I'm out!\n");
+
+	exit(0); /* unreachable */
+}
+
+static void fake_subtest_test(void)
+{
+	igt_subtest_init(fake_argc, fake_argv);
+
+	igt_subtest("A")
+		;
+
+	igt_subtest("B")
+		igt_abort_on_f(true, "I'm out!\n");
+
+	igt_subtest("C")
+		exit(0); /* unreachable */
+
+	exit(0); /* unreachable */
+}
+
+static void fake_dynamic_test(void)
+{
+	igt_subtest_init(fake_argc, fake_argv);
+
+	igt_subtest_with_dynamic("A") {
+		igt_dynamic("AA")
+			;
+		igt_dynamic("AB")
+			igt_abort_on_f(true, "I'm out!\n");
+
+		igt_dynamic("AC")
+			exit(0); /* unreachable */
+
+	}
+
+	igt_subtest("B")
+		exit(0); /* unreachable */
+
+	exit(0); /* unreachable */
+}
+
+static void fake_outside_dynamic_test(void)
+{
+	igt_subtest_init(fake_argc, fake_argv);
+
+	igt_subtest_with_dynamic("A") {
+		igt_dynamic("AA")
+			;
+
+		igt_abort_on_f(true, "I'm out!\n");
+
+		igt_dynamic("AB")
+			exit(0); /* unreachable */
+
+		igt_dynamic("AC")
+			exit(0); /* unreachable */
+
+	}
+
+	igt_subtest("B")
+		exit(0); /* unreachable */
+
+	exit(0); /* unreachable */
+}
+
+int main(int argc, char **argv)
+{
+	int status;
+	pid_t pid;
+
+	/* make sure that we log the message and can abort from a simple test*/ {
+		static char err[4096];
+		int errfd;
+
+		pid = do_fork_bg_with_pipes(fake_simple_test, NULL, &errfd);
+
+		read_whole_pipe(errfd, err, sizeof(err));
+
+		internal_assert(strstr(err, "CRITICAL: Test abort"));
+		internal_assert(strstr(err, "I'm out!"));
+
+		internal_assert(safe_wait(pid, &status) != -1);
+		internal_assert_wexited(status, IGT_EXIT_ABORT);
+	}
+
+	/* make sure that we can abort from a fixture */ {
+		pid = do_fork_bg_with_pipes(fake_fixture_test, NULL, NULL);
+		internal_assert(safe_wait(pid, &status) != -1);
+		internal_assert_wexited(status, IGT_EXIT_ABORT);
+	}
+
+	/* make sure that we can abort from outside fixture/subtest */ {
+		pid = do_fork_bg_with_pipes(fake_outside_fixture_test, NULL, NULL);
+		internal_assert(safe_wait(pid, &status) != -1);
+		internal_assert_wexited(status, IGT_EXIT_ABORT);
+	}
+
+	/* make sure we abort during B and don't see B's end/C start */ {
+		static char out[4096];
+		int outfd;
+
+		pid = do_fork_bg_with_pipes(fake_subtest_test, &outfd, NULL);
+
+		read_whole_pipe(outfd, out, sizeof(out));
+
+		internal_assert(safe_wait(pid, &status) != -1);
+		internal_assert_wexited(status, IGT_EXIT_ABORT);
+
+		internal_assert(strstr(out, "Starting subtest: A"));
+		internal_assert(strstr(out, "Subtest A:"));
+
+		internal_assert(strstr(out, "Starting subtest: B"));
+		internal_assert(!strstr(out, "Subtest B:"));
+
+		internal_assert(!strstr(out, "Starting subtest: C"));
+
+		close(outfd);
+	}
+
+	/* make sure we abort during AB and don't see AC/B */ {
+		static char out[4096];
+		int outfd;
+
+		pid = do_fork_bg_with_pipes(fake_dynamic_test, &outfd, NULL);
+
+		read_whole_pipe(outfd, out, sizeof(out));
+
+		internal_assert(safe_wait(pid, &status) != -1);
+		internal_assert_wexited(status, IGT_EXIT_ABORT);
+
+		internal_assert(strstr(out, "Starting subtest: A"));
+		internal_assert(strstr(out, "Starting dynamic subtest: AA"));
+		internal_assert(strstr(out, "Dynamic subtest AA:"));
+
+		internal_assert(strstr(out, "Starting dynamic subtest: AB"));
+		internal_assert(!strstr(out, "Dynamic subtest AB:"));
+
+		internal_assert(!strstr(out, "Starting subtest: B"));
+
+		close(outfd);
+
+	}
+
+	/* make sure we abort between AA and AB */ {
+		static char out[4096];
+		int outfd;
+
+		pid = do_fork_bg_with_pipes(fake_outside_dynamic_test, &outfd, NULL);
+
+		read_whole_pipe(outfd, out, sizeof(out));
+
+		internal_assert(safe_wait(pid, &status) != -1);
+		internal_assert_wexited(status, IGT_EXIT_ABORT);
+
+		internal_assert(strstr(out, "Starting subtest: A"));
+		internal_assert(strstr(out, "Starting dynamic subtest: AA"));
+		internal_assert(strstr(out, "Dynamic subtest AA:"));
+
+		internal_assert(!strstr(out, "Starting dynamic subtest: AB"));
+		internal_assert(!strstr(out, "Dynamic subtest AB:"));
+
+		internal_assert(!strstr(out, "Starting subtest: B"));
+
+		close(outfd);
+
+	}
+
+	return 0;
+}
diff --git a/lib/tests/meson.build b/lib/tests/meson.build
index e5066665..e75a723a 100644
--- a/lib/tests/meson.build
+++ b/lib/tests/meson.build
@@ -1,5 +1,6 @@
 lib_tests = [
 	'igt_assert',
+	'igt_abort',
 	'igt_can_fail',
 	'igt_can_fail_simple',
 	'igt_conflicting_args',
-- 
2.24.1

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [igt-dev] [PATCH i-g-t 4/9] runner/runner_tests: Extract helper for inspecting test result
  2020-02-12 13:21 [igt-dev] [PATCH i-g-t 0/9] Abort on Chamelium failure Arkadiusz Hiler
                   ` (2 preceding siblings ...)
  2020-02-12 13:21 ` [igt-dev] [PATCH i-g-t 3/9] lib: Make it possible to abort the whole execution from inside of a test Arkadiusz Hiler
@ 2020-02-12 13:21 ` Arkadiusz Hiler
  2020-02-12 13:37   ` Petri Latvala
  2020-02-14 12:05   ` Petri Latvala
  2020-02-12 13:22 ` [igt-dev] [PATCH i-g-t 5/9] runner: Abort the run when test exits with IGT_EXIT_ABORT Arkadiusz Hiler
                   ` (6 subsequent siblings)
  10 siblings, 2 replies; 29+ messages in thread
From: Arkadiusz Hiler @ 2020-02-12 13:21 UTC (permalink / raw)
  To: igt-dev; +Cc: Petri Latvala

to make this bit of code more readable and to reuse it in the following patch

Signed-off-by: Arkadiusz Hiler <arkadiusz.hiler@intel.com>
---
 runner/runner_tests.c | 30 +++++++++++++++++-------------
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/runner/runner_tests.c b/runner/runner_tests.c
index ed30b3f9..dd590f33 100644
--- a/runner/runner_tests.c
+++ b/runner/runner_tests.c
@@ -32,6 +32,16 @@ static const char testdatadir[] = TESTDATA_DIRECTORY;
 /* The total number of test binaries in runner/testdata/ */
 #define NUM_TESTDATA_BINARIES 4
 
+static const char *igt_get_result(struct json_object *tests, const char* testname)
+{
+	struct json_object *obj;
+
+	igt_assert(json_object_object_get_ex(tests, testname, &obj));
+	igt_assert(json_object_object_get_ex(obj, "result", &obj));
+
+	return json_object_get_string(obj);
+}
+
 static void igt_assert_eqstr(const char *one, const char *two)
 {
 	if (one == NULL && two == NULL)
@@ -1432,7 +1442,7 @@ igt_main
 
 		igt_subtest("dynamic-subtests-in-testlist") {
 			struct execute_state state;
-			struct json_object *results, *obj;
+			struct json_object *results, *tests;
 			const char *argv[] = { "runner",
 					       "--test-list", filename,
 					       testdatadir,
@@ -1453,16 +1463,13 @@ igt_main
 			igt_assert_f((results = generate_results_json(dirfd)) != NULL,
 				     "Results parsing failed\n");
 
-			obj = results;
-			igt_assert(json_object_object_get_ex(obj, "tests", &obj));
+			igt_assert(json_object_object_get_ex(results, "tests", &tests));
 
 			/* Check that the dynamic subtest we didn't request is not reported */
-			igt_assert(!json_object_object_get_ex(obj, "igt@dynamic@dynamic-subtest@failing", NULL));
+			igt_assert_no_result_for(tests, "igt@dynamic@dynamic-subtest@failing");
 
 			/* Check that the dynamic subtest we did request is */
-			igt_assert(json_object_object_get_ex(obj, "igt@dynamic@dynamic-subtest@passing", &obj));
-			igt_assert(json_object_object_get_ex(obj, "result", &obj));
-			igt_assert_eqstr(json_object_get_string(obj), "pass");
+			igt_assert_eqstr(igt_get_result(tests, "igt@dynamic@dynamic-subtest@passing"), "pass");
 
 			igt_assert_eq(json_object_put(results), 1);
 		}
@@ -1490,7 +1497,7 @@ igt_main
 
 		igt_subtest("dynamic-subtest-failure-should-not-cause-warn") {
 			struct execute_state state;
-			struct json_object *results, *obj;
+			struct json_object *results, *tests;
 			const char *argv[] = { "runner",
 					       "-t", "dynamic",
 					       testdatadir,
@@ -1507,12 +1514,9 @@ igt_main
 			igt_assert_f((results = generate_results_json(dirfd)) != NULL,
 				     "Results parsing failed\n");
 
-			obj = results;
-			igt_assert(json_object_object_get_ex(obj, "tests", &obj));
-			igt_assert(json_object_object_get_ex(obj, "igt@dynamic@dynamic-subtest@passing", &obj));
-			igt_assert(json_object_object_get_ex(obj, "result", &obj));
+			igt_assert(json_object_object_get_ex(results, "tests", &tests));
 
-			igt_assert_eqstr(json_object_get_string(obj), "pass");
+			igt_assert_eqstr(igt_get_result(tests, "igt@dynamic@dynamic-subtest@passing"), "pass");
 
 			igt_assert_eq(json_object_put(results), 1);
 		}
-- 
2.24.1

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [igt-dev] [PATCH i-g-t 5/9] runner: Abort the run when test exits with IGT_EXIT_ABORT
  2020-02-12 13:21 [igt-dev] [PATCH i-g-t 0/9] Abort on Chamelium failure Arkadiusz Hiler
                   ` (3 preceding siblings ...)
  2020-02-12 13:21 ` [igt-dev] [PATCH i-g-t 4/9] runner/runner_tests: Extract helper for inspecting test result Arkadiusz Hiler
@ 2020-02-12 13:22 ` Arkadiusz Hiler
  2020-02-14 12:16   ` Petri Latvala
  2020-02-12 13:22 ` [igt-dev] [PATCH i-g-t 6/9] lib/chamelium: Clear error after checking if chamelium is reachable Arkadiusz Hiler
                   ` (5 subsequent siblings)
  10 siblings, 1 reply; 29+ messages in thread
From: Arkadiusz Hiler @ 2020-02-12 13:22 UTC (permalink / raw)
  To: igt-dev; +Cc: Petri Latvala

Now that the IGT tests have a mechanism for signaling broken testing
conditions we can stop the run on the first test that has noticed it,
and possibly has triggered that state.

Traditionally run would have continued with that test failing and the
side effects would trickle down into the other tests causing a lot of
skip/fails.

Signed-off-by: Arkadiusz Hiler <arkadiusz.hiler@intel.com>
---
 runner/executor.c                             |   3 +
 .../aborted-after-a-test/reference.json       |   6 +
 .../aborted-on-boot/reference.json            |   6 +
 .../dmesg-escapes/reference.json              |   3 +
 .../dmesg-results/reference.json              |   5 +
 .../reference.json                            |   3 +
 .../reference.json                            |   3 +
 .../dmesg-warn-level/reference.json           |   3 +
 .../reference.json                            |   3 +
 .../dynamic-subtests/reference.json           |   3 +
 .../reference.json                            |   5 +
 .../json_tests_data/normal-run/reference.json |   5 +
 .../reference.json                            |   4 +
 .../notrun-results/reference.json             |   5 +
 .../piglit-style-dmesg/reference.json         |   5 +
 .../unprintable-characters/reference.json     |   5 +-
 .../warnings-with-dmesg-warns/reference.json  |   5 +
 .../json_tests_data/warnings/reference.json   |   5 +
 runner/resultgen.c                            |  25 ++
 runner/runner_tests.c                         | 303 +++++++++++++++++-
 runner/testdata/abort-dynamic.c               |  46 +++
 runner/testdata/abort-fixture.c               |  37 +++
 runner/testdata/abort-simple.c                |  29 ++
 runner/testdata/abort.c                       |  36 +++
 runner/testdata/meson.build                   |   4 +
 25 files changed, 551 insertions(+), 6 deletions(-)
 create mode 100644 runner/testdata/abort-dynamic.c
 create mode 100644 runner/testdata/abort-fixture.c
 create mode 100644 runner/testdata/abort-simple.c
 create mode 100644 runner/testdata/abort.c

diff --git a/runner/executor.c b/runner/executor.c
index 3ea5d167..86b5de80 100644
--- a/runner/executor.c
+++ b/runner/executor.c
@@ -1035,6 +1035,9 @@ static int monitor_output(pid_t child,
 					fdatasync(outputs[_F_JOURNAL]);
 				}
 
+				if (status == IGT_EXIT_ABORT)
+					aborting = true;
+
 				if (time_spent)
 					*time_spent = time;
 			}
diff --git a/runner/json_tests_data/aborted-after-a-test/reference.json b/runner/json_tests_data/aborted-after-a-test/reference.json
index 583242c7..0776f758 100644
--- a/runner/json_tests_data/aborted-after-a-test/reference.json
+++ b/runner/json_tests_data/aborted-after-a-test/reference.json
@@ -60,6 +60,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":4,
       "fail":1,
@@ -72,6 +73,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":4,
       "fail":1,
@@ -84,6 +86,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":1,
       "fail":0,
@@ -96,6 +99,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":1,
       "fail":0,
@@ -108,6 +112,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":2,
       "fail":0,
@@ -120,6 +125,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":1,
diff --git a/runner/json_tests_data/aborted-on-boot/reference.json b/runner/json_tests_data/aborted-on-boot/reference.json
index d354fbac..75f19466 100644
--- a/runner/json_tests_data/aborted-on-boot/reference.json
+++ b/runner/json_tests_data/aborted-on-boot/reference.json
@@ -54,6 +54,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":5,
       "fail":1,
@@ -66,6 +67,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":5,
       "fail":1,
@@ -78,6 +80,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":2,
       "fail":0,
@@ -90,6 +93,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":1,
       "fail":0,
@@ -102,6 +106,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":2,
       "fail":0,
@@ -114,6 +119,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":1,
diff --git a/runner/json_tests_data/dmesg-escapes/reference.json b/runner/json_tests_data/dmesg-escapes/reference.json
index 70d6b366..91c57310 100644
--- a/runner/json_tests_data/dmesg-escapes/reference.json
+++ b/runner/json_tests_data/dmesg-escapes/reference.json
@@ -30,6 +30,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
@@ -42,6 +43,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
@@ -54,6 +56,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
diff --git a/runner/json_tests_data/dmesg-results/reference.json b/runner/json_tests_data/dmesg-results/reference.json
index 0edbae93..e9e01185 100644
--- a/runner/json_tests_data/dmesg-results/reference.json
+++ b/runner/json_tests_data/dmesg-results/reference.json
@@ -81,6 +81,7 @@
       "dmesg-warn":2,
       "skip":2,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
@@ -93,6 +94,7 @@
       "dmesg-warn":2,
       "skip":2,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
@@ -105,6 +107,7 @@
       "dmesg-warn":1,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
@@ -117,6 +120,7 @@
       "dmesg-warn":1,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
@@ -129,6 +133,7 @@
       "dmesg-warn":0,
       "skip":2,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
diff --git a/runner/json_tests_data/dmesg-warn-level-one-piglit-style/reference.json b/runner/json_tests_data/dmesg-warn-level-one-piglit-style/reference.json
index 4ccb18ae..8d266cdf 100644
--- a/runner/json_tests_data/dmesg-warn-level-one-piglit-style/reference.json
+++ b/runner/json_tests_data/dmesg-warn-level-one-piglit-style/reference.json
@@ -31,6 +31,7 @@
       "dmesg-warn":1,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
@@ -43,6 +44,7 @@
       "dmesg-warn":1,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
@@ -55,6 +57,7 @@
       "dmesg-warn":1,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
diff --git a/runner/json_tests_data/dmesg-warn-level-piglit-style/reference.json b/runner/json_tests_data/dmesg-warn-level-piglit-style/reference.json
index d706ee4c..4a1e8b31 100644
--- a/runner/json_tests_data/dmesg-warn-level-piglit-style/reference.json
+++ b/runner/json_tests_data/dmesg-warn-level-piglit-style/reference.json
@@ -31,6 +31,7 @@
       "dmesg-warn":1,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
@@ -43,6 +44,7 @@
       "dmesg-warn":1,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
@@ -55,6 +57,7 @@
       "dmesg-warn":1,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
diff --git a/runner/json_tests_data/dmesg-warn-level/reference.json b/runner/json_tests_data/dmesg-warn-level/reference.json
index 11cc39d9..400e9cfb 100644
--- a/runner/json_tests_data/dmesg-warn-level/reference.json
+++ b/runner/json_tests_data/dmesg-warn-level/reference.json
@@ -31,6 +31,7 @@
       "dmesg-warn":1,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
@@ -43,6 +44,7 @@
       "dmesg-warn":1,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
@@ -55,6 +57,7 @@
       "dmesg-warn":1,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
diff --git a/runner/json_tests_data/dynamic-subtest-name-in-multiple-subtests/reference.json b/runner/json_tests_data/dynamic-subtest-name-in-multiple-subtests/reference.json
index 370fce4d..514de06a 100644
--- a/runner/json_tests_data/dynamic-subtest-name-in-multiple-subtests/reference.json
+++ b/runner/json_tests_data/dynamic-subtest-name-in-multiple-subtests/reference.json
@@ -42,6 +42,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
@@ -54,6 +55,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
@@ -66,6 +68,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
diff --git a/runner/json_tests_data/dynamic-subtests/reference.json b/runner/json_tests_data/dynamic-subtests/reference.json
index ca8f6cd7..c013d282 100644
--- a/runner/json_tests_data/dynamic-subtests/reference.json
+++ b/runner/json_tests_data/dynamic-subtests/reference.json
@@ -90,6 +90,7 @@
       "dmesg-warn":0,
       "skip":1,
       "incomplete":1,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":2,
@@ -102,6 +103,7 @@
       "dmesg-warn":0,
       "skip":1,
       "incomplete":1,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":2,
@@ -114,6 +116,7 @@
       "dmesg-warn":0,
       "skip":1,
       "incomplete":1,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":2,
diff --git a/runner/json_tests_data/incomplete-before-any-subtests/reference.json b/runner/json_tests_data/incomplete-before-any-subtests/reference.json
index b8a76dd7..2a4bd456 100644
--- a/runner/json_tests_data/incomplete-before-any-subtests/reference.json
+++ b/runner/json_tests_data/incomplete-before-any-subtests/reference.json
@@ -49,6 +49,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":1,
+      "abort":0,
       "timeout":0,
       "notrun":4,
       "fail":0,
@@ -61,6 +62,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":1,
+      "abort":0,
       "timeout":0,
       "notrun":4,
       "fail":0,
@@ -73,6 +75,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":1,
+      "abort":0,
       "timeout":0,
       "notrun":1,
       "fail":0,
@@ -85,6 +88,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":1,
       "fail":0,
@@ -97,6 +101,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":2,
       "fail":0,
diff --git a/runner/json_tests_data/normal-run/reference.json b/runner/json_tests_data/normal-run/reference.json
index 982038f9..0a00b1ca 100644
--- a/runner/json_tests_data/normal-run/reference.json
+++ b/runner/json_tests_data/normal-run/reference.json
@@ -78,6 +78,7 @@
       "dmesg-warn":0,
       "skip":2,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":1,
@@ -90,6 +91,7 @@
       "dmesg-warn":0,
       "skip":2,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":1,
@@ -102,6 +104,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":1,
@@ -114,6 +117,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
@@ -126,6 +130,7 @@
       "dmesg-warn":0,
       "skip":2,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
diff --git a/runner/json_tests_data/notrun-results-multiple-mode/reference.json b/runner/json_tests_data/notrun-results-multiple-mode/reference.json
index 492c0a9e..3f8b7fb0 100644
--- a/runner/json_tests_data/notrun-results-multiple-mode/reference.json
+++ b/runner/json_tests_data/notrun-results-multiple-mode/reference.json
@@ -48,6 +48,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":3,
       "fail":0,
@@ -60,6 +61,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":3,
       "fail":0,
@@ -72,6 +74,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":1,
       "fail":0,
@@ -84,6 +87,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":2,
       "fail":0,
diff --git a/runner/json_tests_data/notrun-results/reference.json b/runner/json_tests_data/notrun-results/reference.json
index 49a2f693..800de38c 100644
--- a/runner/json_tests_data/notrun-results/reference.json
+++ b/runner/json_tests_data/notrun-results/reference.json
@@ -54,6 +54,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":4,
       "fail":0,
@@ -66,6 +67,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":4,
       "fail":0,
@@ -78,6 +80,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":1,
       "fail":0,
@@ -90,6 +93,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":1,
       "fail":0,
@@ -102,6 +106,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":2,
       "fail":0,
diff --git a/runner/json_tests_data/piglit-style-dmesg/reference.json b/runner/json_tests_data/piglit-style-dmesg/reference.json
index 45d6108e..bf5d86ee 100644
--- a/runner/json_tests_data/piglit-style-dmesg/reference.json
+++ b/runner/json_tests_data/piglit-style-dmesg/reference.json
@@ -78,6 +78,7 @@
       "dmesg-warn":0,
       "skip":2,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
@@ -90,6 +91,7 @@
       "dmesg-warn":0,
       "skip":2,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
@@ -102,6 +104,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
@@ -114,6 +117,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
@@ -126,6 +130,7 @@
       "dmesg-warn":0,
       "skip":2,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
diff --git a/runner/json_tests_data/unprintable-characters/reference.json b/runner/json_tests_data/unprintable-characters/reference.json
index d3add1eb..88c62c34 100644
--- a/runner/json_tests_data/unprintable-characters/reference.json
+++ b/runner/json_tests_data/unprintable-characters/reference.json
@@ -30,6 +30,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
@@ -42,6 +43,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
@@ -54,6 +56,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
@@ -69,4 +72,4 @@
       }
     }
   }
-}
\ No newline at end of file
+}
diff --git a/runner/json_tests_data/warnings-with-dmesg-warns/reference.json b/runner/json_tests_data/warnings-with-dmesg-warns/reference.json
index fa571703..bd0bb3a3 100644
--- a/runner/json_tests_data/warnings-with-dmesg-warns/reference.json
+++ b/runner/json_tests_data/warnings-with-dmesg-warns/reference.json
@@ -79,6 +79,7 @@
       "dmesg-warn":1,
       "skip":2,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
@@ -91,6 +92,7 @@
       "dmesg-warn":1,
       "skip":2,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
@@ -103,6 +105,7 @@
       "dmesg-warn":1,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
@@ -115,6 +118,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
@@ -127,6 +131,7 @@
       "dmesg-warn":0,
       "skip":2,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
diff --git a/runner/json_tests_data/warnings/reference.json b/runner/json_tests_data/warnings/reference.json
index 53e0c3c7..a2b79da9 100644
--- a/runner/json_tests_data/warnings/reference.json
+++ b/runner/json_tests_data/warnings/reference.json
@@ -78,6 +78,7 @@
       "dmesg-warn":0,
       "skip":2,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
@@ -90,6 +91,7 @@
       "dmesg-warn":0,
       "skip":2,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
@@ -102,6 +104,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
@@ -114,6 +117,7 @@
       "dmesg-warn":0,
       "skip":0,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
@@ -126,6 +130,7 @@
       "dmesg-warn":0,
       "skip":2,
       "incomplete":0,
+      "abort":0,
       "timeout":0,
       "notrun":0,
       "fail":0,
diff --git a/runner/resultgen.c b/runner/resultgen.c
index 105ec887..5e72db9a 100644
--- a/runner/resultgen.c
+++ b/runner/resultgen.c
@@ -645,6 +645,16 @@ static void process_dynamic_subtest_output(const char *piglit_name,
 					     &dynresulttext, &dyntime,
 					     dyn_result_idx < 0 ? NULL : matches.items[dyn_result_idx].where,
 					     dynend);
+
+			if (!strcmp(dynresulttext, "incomplete")) {
+				struct json_object *parent_subtest;
+
+				if (json_object_object_get_ex(tests, piglit_name, &parent_subtest) &&
+				    json_object_object_get_ex(parent_subtest, "result", &parent_subtest) &&
+				    !strcmp(json_object_get_string(parent_subtest), "abort"))
+					dynresulttext = "abort";
+			}
+
 			set_result(current_dynamic_test, dynresulttext);
 			set_runtime(current_dynamic_test, dyntime);
 		}
@@ -1078,6 +1088,8 @@ static const char *result_from_exitcode(int exitcode)
 		return "pass";
 	case IGT_EXIT_INVALID:
 		return "skip";
+	case IGT_EXIT_ABORT:
+		return "abort";
 	case INCOMPLETE_EXITCODE:
 		return "incomplete";
 	default:
@@ -1154,6 +1166,18 @@ static void fill_from_journal(int fd,
 		}
 	}
 
+	if (subtests->size && exitcode == IGT_EXIT_ABORT)
+	{
+		char *last_subtest = subtests->subs[subtests->size - 1].name;
+		char subtest_piglit_name[256];
+		struct json_object *subtest_obj;
+
+		generate_piglit_name(entry->binary, last_subtest, subtest_piglit_name, sizeof(subtest_piglit_name));
+		subtest_obj = get_or_create_json_object(tests, subtest_piglit_name);
+
+		set_result(subtest_obj, "abort");
+	}
+
 	if (subtests->size == 0) {
 		char *subtestname = NULL;
 		char piglit_name[256];
@@ -1297,6 +1321,7 @@ static struct json_object *get_totals_object(struct json_object *totals,
 	json_object_object_add(obj, "dmesg-warn", json_object_new_int(0));
 	json_object_object_add(obj, "skip", json_object_new_int(0));
 	json_object_object_add(obj, "incomplete", json_object_new_int(0));
+	json_object_object_add(obj, "abort", json_object_new_int(0));
 	json_object_object_add(obj, "timeout", json_object_new_int(0));
 	json_object_object_add(obj, "notrun", json_object_new_int(0));
 	json_object_object_add(obj, "fail", json_object_new_int(0));
diff --git a/runner/runner_tests.c b/runner/runner_tests.c
index dd590f33..701da1a5 100644
--- a/runner/runner_tests.c
+++ b/runner/runner_tests.c
@@ -28,9 +28,16 @@ static const char testdatadir[] = TESTDATA_DIRECTORY;
  * that test binaries without subtests should still be counted as one
  * for this macro.
  */
-#define NUM_TESTDATA_SUBTESTS 6
+#define NUM_TESTDATA_SUBTESTS 15
+#define NUM_TESTDATA_ABORT_SUBTESTS 9
 /* The total number of test binaries in runner/testdata/ */
-#define NUM_TESTDATA_BINARIES 4
+#define NUM_TESTDATA_BINARIES 8
+
+static void igt_assert_no_result_for(struct json_object *tests, const char* testname)
+{
+	struct json_object *obj;
+	igt_assert(!json_object_object_get_ex(tests, testname, &obj));
+}
 
 static const char *igt_get_result(struct json_object *tests, const char* testname)
 {
@@ -941,6 +948,7 @@ igt_main
 			struct execute_state state;
 			const char *argv[] = { "runner",
 					       "--dry-run",
+					       "-x", "^abort",
 					       testdatadir,
 					       dirname,
 			};
@@ -951,7 +959,7 @@ igt_main
 			igt_assert(initialize_execute_state(&state, settings, list));
 			igt_assert_eq(state.next, 0);
 			igt_assert(state.dry);
-			igt_assert_eq(list->size, NUM_TESTDATA_SUBTESTS);
+			igt_assert_eq(list->size, NUM_TESTDATA_SUBTESTS - NUM_TESTDATA_ABORT_SUBTESTS);
 
 			igt_assert_f((dirfd = open(dirname, O_DIRECTORY | O_RDONLY)) >= 0,
 				     "Dry run initialization didn't create the results directory.\n");
@@ -972,7 +980,7 @@ igt_main
 			igt_assert(initialize_execute_state_from_resume(dirfd, &state, settings, list));
 			igt_assert_eq(state.next, 0);
 			igt_assert(!state.dry);
-			igt_assert_eq(list->size, NUM_TESTDATA_SUBTESTS);
+			igt_assert_eq(list->size, NUM_TESTDATA_SUBTESTS - NUM_TESTDATA_ABORT_SUBTESTS);
 			/* initialize_execute_state_from_resume() closes the dirfd */
 			igt_assert_f((dirfd = open(dirname, O_DIRECTORY | O_RDONLY)) >= 0,
 				     "Dry run resume somehow deleted the results directory.\n");
@@ -1499,7 +1507,7 @@ igt_main
 			struct execute_state state;
 			struct json_object *results, *tests;
 			const char *argv[] = { "runner",
-					       "-t", "dynamic",
+					       "-t", "^dynamic$",
 					       testdatadir,
 					       dirname,
 			};
@@ -1528,6 +1536,291 @@ igt_main
 		}
 	}
 
+	igt_subtest_group {
+		struct job_list *list = malloc(sizeof(*list));
+		volatile int dirfd = -1;
+		char dirname[] = "tmpdirXXXXXX";
+
+		igt_fixture {
+			igt_require(mkdtemp(dirname) != NULL);
+			rmdir(dirname);
+
+			init_job_list(list);
+		}
+
+		igt_subtest("execute-abort-simple") {
+			struct execute_state state;
+			struct json_object *results, *tests;
+			const char *argv[] = { "runner",
+					       "-t", "^abort-simple$",
+					       testdatadir,
+					       dirname,
+			};
+
+			igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
+			igt_assert(create_job_list(list, settings));
+			igt_assert(initialize_execute_state(&state, settings, list));
+			igt_assert(!execute(&state, settings, list)); /* false = signal abort */
+
+			igt_assert_f((dirfd = open(dirname, O_DIRECTORY | O_RDONLY)) >= 0,
+				     "Execute didn't create the results directory\n");
+			igt_assert_f((results = generate_results_json(dirfd)) != NULL,
+				     "Results parsing failed\n");
+
+			igt_assert(json_object_object_get_ex(results, "tests", &tests));
+
+			igt_assert_eqstr(igt_get_result(tests, "igt@abort-simple"), "abort");
+
+			igt_assert_eq(json_object_put(results), 1);
+		}
+
+		igt_fixture {
+			close(dirfd);
+			clear_directory(dirname);
+			free_job_list(list);
+		}
+	}
+
+	igt_subtest_group {
+		struct job_list *list = malloc(sizeof(*list));
+		volatile int dirfd = -1;
+
+
+		for (int multiple = 0; multiple <= 1; ++multiple) {
+			char dirname[] = "tmpdirXXXXXX";
+
+			igt_fixture {
+				igt_require(mkdtemp(dirname) != NULL);
+				rmdir(dirname);
+
+				init_job_list(list);
+			}
+
+			igt_subtest_f("execute-abort%s", multiple ? "-multiple" : "") {
+				struct execute_state state;
+				struct json_object *results, *tests;
+				const char *argv[] = { "runner",
+						       "-t", "^abort$",
+						       multiple ? "--multiple-mode" : "--sync",
+						       testdatadir,
+						       dirname,
+				};
+
+				igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
+				igt_assert(create_job_list(list, settings));
+				igt_assert(initialize_execute_state(&state, settings, list));
+				igt_assert(!execute(&state, settings, list)); /* false = signal abort */
+
+				igt_assert_f((dirfd = open(dirname, O_DIRECTORY | O_RDONLY)) >= 0,
+					     "Execute didn't create the results directory\n");
+				igt_assert_f((results = generate_results_json(dirfd)) != NULL,
+					     "Results parsing failed\n");
+
+				igt_assert(json_object_object_get_ex(results, "tests", &tests));
+
+				igt_assert_eqstr(igt_get_result(tests, "igt@abort@a-subtest"), "pass");
+				igt_assert_eqstr(igt_get_result(tests, "igt@abort@b-subtest"), "abort");
+
+				if (multiple) /* no notrun injection for multiple mode */
+					igt_assert_no_result_for(tests, "igt@abort@c-subtest");
+				else
+					igt_assert_eqstr(igt_get_result(tests, "igt@abort@c-subtest"), "notrun");
+
+				igt_assert_eq(json_object_put(results), 1);
+			}
+
+			igt_fixture {
+				close(dirfd);
+				clear_directory(dirname);
+				free_job_list(list);
+			}
+		}
+	}
+
+	igt_subtest_group {
+		struct job_list *list = malloc(sizeof(*list));
+		volatile int dirfd = -1;
+
+		for (int multiple = 0; multiple <= 1; ++multiple) {
+			char dirname[] = "tmpdirXXXXXX";
+
+			igt_fixture {
+				igt_require(mkdtemp(dirname) != NULL);
+				rmdir(dirname);
+
+				init_job_list(list);
+			}
+
+			igt_subtest_f("execute-abort-fixture%s", multiple ? "-multiple" : "") {
+				struct execute_state state;
+				struct json_object *results, *tests;
+				const char *argv[] = { "runner", multiple ? "--multiple-mode" : "--sync",
+						       "-t", "^abort-fixture$",
+						       testdatadir,
+						       dirname,
+				};
+
+				igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
+				igt_assert(create_job_list(list, settings));
+				igt_assert(initialize_execute_state(&state, settings, list));
+				igt_assert(!execute(&state, settings, list)); /* false = signal abort */
+
+				igt_assert_f((dirfd = open(dirname, O_DIRECTORY | O_RDONLY)) >= 0,
+					     "Execute didn't create the results directory\n");
+				igt_assert_f((results = generate_results_json(dirfd)) != NULL,
+					     "Results parsing failed\n");
+
+				igt_assert(json_object_object_get_ex(results, "tests", &tests));
+
+				if (multiple) {
+					/*
+					 * running the whole binary via -t, no
+					 * way of blaming the particular subtest
+					 */
+					igt_assert_eqstr(igt_get_result(tests, "igt@abort-fixture"), "abort");
+					igt_assert_no_result_for(tests, "igt@abort-fixture@a-subtest");
+					igt_assert_no_result_for(tests, "igt@abort-fixture@b-subtest");
+				} else {
+					igt_assert_eqstr(igt_get_result(tests, "igt@abort-fixture@a-subtest"), "abort");
+					igt_assert_eqstr(igt_get_result(tests, "igt@abort-fixture@b-subtest"), "notrun");
+				}
+
+				igt_assert_eq(json_object_put(results), 1);
+			}
+
+			igt_fixture {
+				close(dirfd);
+				clear_directory(dirname);
+				free_job_list(list);
+			}
+		}
+	}
+
+	igt_subtest_group {
+		struct job_list *list = malloc(sizeof(*list));
+		volatile int dirfd = -1;
+
+		for (int multiple = 0; multiple <= 1; ++multiple) {
+			char dirname[] = "tmpdirXXXXXX";
+			char filename[] = "tmplistXXXXXX";
+			const char testlisttext[] = "igt@abort-fixture@b-subtest\n"
+				"igt@abort-fixture@a-subtest\n";
+
+			igt_fixture {
+				int fd;
+				igt_require((fd = mkstemp(filename)) >= 0);
+				igt_require(write(fd, testlisttext, strlen(testlisttext)) == strlen(testlisttext));
+				close(fd);
+				igt_require(mkdtemp(dirname) != NULL);
+				rmdir(dirname);
+
+				init_job_list(list);
+			}
+
+			igt_subtest_f("execute-abort-fixture-testlist%s", multiple ? "-multiple" : "") {
+				struct execute_state state;
+				struct json_object *results, *tests;
+				const char *argv[] = { "runner", multiple ? "--multiple-mode" : "--sync",
+						       "--test-list", filename,
+						       testdatadir,
+						       dirname,
+				};
+
+				igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
+				igt_assert(create_job_list(list, settings));
+				igt_assert(initialize_execute_state(&state, settings, list));
+				igt_assert(!execute(&state, settings, list)); /* false = signal abort */
+
+				igt_assert_f((dirfd = open(dirname, O_DIRECTORY | O_RDONLY)) >= 0,
+					     "Execute didn't create the results directory\n");
+				igt_assert_f((results = generate_results_json(dirfd)) != NULL,
+					     "Results parsing failed\n");
+
+				igt_assert(json_object_object_get_ex(results, "tests", &tests));
+
+				if (multiple) /* multiple mode = no notruns */
+					igt_assert_no_result_for(tests, "igt@abort-fixture@a-subtest");
+				else
+					igt_assert_eqstr(igt_get_result(tests, "igt@abort-fixture@a-subtest"), "notrun");
+
+
+				igt_assert_eqstr(igt_get_result(tests, "igt@abort-fixture@b-subtest"), "abort");
+
+				igt_assert_eq(json_object_put(results), 1);
+			}
+
+			igt_fixture {
+				unlink(filename);
+				close(dirfd);
+				clear_directory(dirname);
+				free_job_list(list);
+			}
+		}
+	}
+
+	igt_subtest_group {
+		struct job_list *list = malloc(sizeof(*list));
+		volatile int dirfd = -1;
+
+		for (int multiple = 0; multiple <= 1; ++multiple) {
+			char dirname[] = "tmpdirXXXXXX";
+
+			igt_fixture {
+				igt_require(mkdtemp(dirname) != NULL);
+				rmdir(dirname);
+
+				init_job_list(list);
+			}
+
+			igt_subtest_f("execute-abort-dynamic%s", multiple ? "-multiple" : "") {
+				struct execute_state state;
+				struct json_object *results, *tests;
+				const char *argv[] = { "runner", multiple ? "--multiple-mode" : "--sync",
+						       "-t", "^abort-dynamic$",
+						       testdatadir,
+						       dirname,
+				};
+
+				igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
+				igt_assert(create_job_list(list, settings));
+				igt_assert(initialize_execute_state(&state, settings, list));
+				igt_assert(!execute(&state, settings, list)); /* false = signal abort */
+
+				igt_assert_f((dirfd = open(dirname, O_DIRECTORY | O_RDONLY)) >= 0,
+					     "Execute didn't create the results directory\n");
+				igt_assert_f((results = generate_results_json(dirfd)) != NULL,
+					     "Results parsing failed\n");
+
+				igt_assert(json_object_object_get_ex(results, "tests", &tests));
+
+				/* { */
+				/* 	const char *json_string; */
+				/* 	json_string = json_object_to_json_string_ext(tests, JSON_C_TO_STRING_PRETTY); */
+				/* 	printf("****\n%s\n***\n", json_string); */
+				/* } */
+
+				igt_assert_eqstr(igt_get_result(tests, "igt@abort-dynamic@a-subtest@dynamic-1"), "pass");
+				igt_assert_eqstr(igt_get_result(tests, "igt@abort-dynamic@b-subtest@dynamic-1"), "pass");
+				igt_assert_eqstr(igt_get_result(tests, "igt@abort-dynamic@b-subtest@dynamic-2"), "abort");
+
+				igt_assert_no_result_for(tests, "igt@abort-dynamic@b-subtest@dynamic-3");
+
+				if (multiple) /* multiple mode = no notruns */
+					igt_assert_no_result_for(tests, "igt@abort-dynamic@c-subtest");
+				else
+					igt_assert_eqstr(igt_get_result(tests, "igt@abort-dynamic@c-subtest"), "notrun");
+
+				igt_assert_eq(json_object_put(results), 1);
+			}
+
+			igt_fixture {
+				close(dirfd);
+				clear_directory(dirname);
+				free_job_list(list);
+			}
+		}
+	}
+
 	igt_subtest("file-descriptor-leakage") {
 		int i;
 
diff --git a/runner/testdata/abort-dynamic.c b/runner/testdata/abort-dynamic.c
new file mode 100644
index 00000000..66cf13a7
--- /dev/null
+++ b/runner/testdata/abort-dynamic.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright © 2020 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "igt.h"
+
+igt_main
+{
+	igt_subtest_with_dynamic("a-subtest") {
+		igt_dynamic("dynamic-1")
+			;
+	}
+
+	igt_subtest_with_dynamic("b-subtest") {
+		igt_dynamic("dynamic-1")
+			;
+
+		igt_dynamic("dynamic-2")
+			igt_abort_on_f(true, "I'm out!\n");
+
+		igt_dynamic("dynamic-3")
+			;
+	}
+
+	igt_subtest("c-subtest")
+		;
+}
diff --git a/runner/testdata/abort-fixture.c b/runner/testdata/abort-fixture.c
new file mode 100644
index 00000000..6a1cb986
--- /dev/null
+++ b/runner/testdata/abort-fixture.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright © 2020 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "igt.h"
+
+igt_main
+{
+	igt_fixture {
+		igt_abort_on_f(true, "I'm out!\n");
+	}
+
+	igt_subtest("a-subtest")
+		;
+
+	igt_subtest("b-subtest")
+		;
+}
diff --git a/runner/testdata/abort-simple.c b/runner/testdata/abort-simple.c
new file mode 100644
index 00000000..94eef72c
--- /dev/null
+++ b/runner/testdata/abort-simple.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright © 2020 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "igt.h"
+
+igt_simple_main
+{
+	igt_abort_on_f(true, "I'm out!\n");
+}
diff --git a/runner/testdata/abort.c b/runner/testdata/abort.c
new file mode 100644
index 00000000..074946a4
--- /dev/null
+++ b/runner/testdata/abort.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright © 2020 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "igt.h"
+
+igt_main
+{
+	igt_subtest("a-subtest")
+		;
+
+	igt_subtest("b-subtest")
+		igt_abort_on_f(true, "I'm out!\n");
+
+	igt_subtest("c-subtest")
+		;
+}
diff --git a/runner/testdata/meson.build b/runner/testdata/meson.build
index 631ba5b9..1f822591 100644
--- a/runner/testdata/meson.build
+++ b/runner/testdata/meson.build
@@ -3,6 +3,10 @@ testdata_progs = [ 'successtest',
 		   'no-subtests',
 		   'skippers',
 		   'dynamic',
+		   'abort',
+		   'abort-dynamic',
+		   'abort-fixture',
+		   'abort-simple',
 		 ]
 
 testdata_executables = []
-- 
2.24.1

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [igt-dev] [PATCH i-g-t 6/9] lib/chamelium: Clear error after checking if chamelium is reachable
  2020-02-12 13:21 [igt-dev] [PATCH i-g-t 0/9] Abort on Chamelium failure Arkadiusz Hiler
                   ` (4 preceding siblings ...)
  2020-02-12 13:22 ` [igt-dev] [PATCH i-g-t 5/9] runner: Abort the run when test exits with IGT_EXIT_ABORT Arkadiusz Hiler
@ 2020-02-12 13:22 ` Arkadiusz Hiler
  2020-02-14 12:17   ` Petri Latvala
  2020-02-12 13:23 ` [igt-dev] [PATCH i-g-t 7/9] lib/chamelium: Make it clear that function asserts Arkadiusz Hiler
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 29+ messages in thread
From: Arkadiusz Hiler @ 2020-02-12 13:22 UTC (permalink / raw)
  To: igt-dev; +Cc: Petri Latvala

Otherwise this may get us stuck in perpetual failure mode.

Signed-off-by: Arkadiusz Hiler <arkadiusz.hiler@intel.com>
---
 lib/igt_chamelium.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
index aaf17d51..b347682d 100644
--- a/lib/igt_chamelium.c
+++ b/lib/igt_chamelium.c
@@ -361,11 +361,17 @@ static bool __chamelium_is_reachable(struct chamelium *chamelium)
 	if (res != NULL)
 		xmlrpc_DECREF(res);
 
-	if (chamelium->env.fault_occurred)
+	if (chamelium->env.fault_occurred) {
 		igt_debug("Chamelium RPC call failed: %s\n",
 			  chamelium->env.fault_string);
 
-	return !chamelium->env.fault_occurred;
+		xmlrpc_env_clean(&chamelium->env);
+		xmlrpc_env_init(&chamelium->env);
+
+		return false;
+	}
+
+	return true;
 }
 
 void chamelium_wait_reachable(struct chamelium *chamelium, int timeout)
-- 
2.24.1

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [igt-dev] [PATCH i-g-t 7/9] lib/chamelium: Make it clear that function asserts
  2020-02-12 13:21 [igt-dev] [PATCH i-g-t 0/9] Abort on Chamelium failure Arkadiusz Hiler
                   ` (5 preceding siblings ...)
  2020-02-12 13:22 ` [igt-dev] [PATCH i-g-t 6/9] lib/chamelium: Clear error after checking if chamelium is reachable Arkadiusz Hiler
@ 2020-02-12 13:23 ` Arkadiusz Hiler
  2020-02-14 12:19   ` Petri Latvala
  2020-02-12 13:23 ` [igt-dev] [PATCH i-g-t 8/9] lib/chamelium: Add functions to initialize XMLRPC only Arkadiusz Hiler
                   ` (3 subsequent siblings)
  10 siblings, 1 reply; 29+ messages in thread
From: Arkadiusz Hiler @ 2020-02-12 13:23 UTC (permalink / raw)
  To: igt-dev; +Cc: Petri Latvala

chamelium_wait_reachable() is asserting internally if the chamelium not
reachable. Let's make it return bool instead and create
void chamelium_assert_reachable() that fails the run.

Signed-off-by: Arkadiusz Hiler <arkadiusz.hiler@intel.com>
---
 lib/igt_chamelium.c   | 10 +++++++---
 lib/igt_chamelium.h   |  3 ++-
 tests/kms_chamelium.c |  4 ++--
 3 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
index b347682d..5f9f777c 100644
--- a/lib/igt_chamelium.c
+++ b/lib/igt_chamelium.c
@@ -374,11 +374,15 @@ static bool __chamelium_is_reachable(struct chamelium *chamelium)
 	return true;
 }
 
-void chamelium_wait_reachable(struct chamelium *chamelium, int timeout)
+bool chamelium_wait_reachable(struct chamelium *chamelium, int timeout)
 {
-	bool chamelium_online = igt_wait(__chamelium_is_reachable(chamelium),
-					 timeout * 1000, 100);
+	return igt_wait(__chamelium_is_reachable(chamelium),
+			timeout * 1000, 100);
+}
 
+void chamelium_assert_reachable(struct chamelium *chamelium, int timeout)
+{
+	bool chamelium_online = chamelium_wait_reachable(chamelium, timeout);
 	igt_assert_f(chamelium_online,
 		     "Couldn't connect to Chamelium for %ds", timeout);
 }
diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
index d03c924a..db6803b1 100644
--- a/lib/igt_chamelium.h
+++ b/lib/igt_chamelium.h
@@ -112,7 +112,8 @@ drmModeConnector *chamelium_port_get_connector(struct chamelium *chamelium,
 					       bool reprobe);
 const char *chamelium_port_get_name(struct chamelium_port *port);
 
-void chamelium_wait_reachable(struct chamelium *chamelium, int timeout);
+bool chamelium_wait_reachable(struct chamelium *chamelium, int timeout);
+void chamelium_assert_reachable(struct chamelium *chamelium, int timeout);
 void chamelium_plug(struct chamelium *chamelium, struct chamelium_port *port);
 void chamelium_unplug(struct chamelium *chamelium, struct chamelium_port *port);
 bool chamelium_is_plugged(struct chamelium *chamelium,
diff --git a/tests/kms_chamelium.c b/tests/kms_chamelium.c
index 5c4a1892..8243d2ef 100644
--- a/tests/kms_chamelium.c
+++ b/tests/kms_chamelium.c
@@ -376,7 +376,7 @@ try_suspend_resume_hpd(data_t *data, struct chamelium_port *port,
 
 	igt_system_suspend_autoresume(state, test);
 	igt_assert(wait_for_hotplug(mon, &timeout));
-	chamelium_wait_reachable(data->chamelium, ONLINE_TIMEOUT);
+	chamelium_assert_reachable(data->chamelium, ONLINE_TIMEOUT);
 
 	if (port) {
 		igt_assert_eq(reprobe_connector(data, port), target_state);
@@ -493,7 +493,7 @@ test_suspend_resume_edid_change(data_t *data, struct chamelium_port *port,
 
 	igt_system_suspend_autoresume(state, test);
 	igt_assert(igt_hotplug_detected(mon, HOTPLUG_TIMEOUT));
-	chamelium_wait_reachable(data->chamelium, ONLINE_TIMEOUT);
+	chamelium_assert_reachable(data->chamelium, ONLINE_TIMEOUT);
 
 	get_connectors_link_status_failed(data, link_status_failed[1]);
 
-- 
2.24.1

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [igt-dev] [PATCH i-g-t 8/9] lib/chamelium: Add functions to initialize XMLRPC only
  2020-02-12 13:21 [igt-dev] [PATCH i-g-t 0/9] Abort on Chamelium failure Arkadiusz Hiler
                   ` (6 preceding siblings ...)
  2020-02-12 13:23 ` [igt-dev] [PATCH i-g-t 7/9] lib/chamelium: Make it clear that function asserts Arkadiusz Hiler
@ 2020-02-12 13:23 ` Arkadiusz Hiler
  2020-02-14 12:22   ` Petri Latvala
  2020-02-12 13:23 ` [igt-dev] [PATCH i-g-t 9/9] lib/kms: Try to plug all Chamelium ports, abort if it fails Arkadiusz Hiler
                   ` (2 subsequent siblings)
  10 siblings, 1 reply; 29+ messages in thread
From: Arkadiusz Hiler @ 2020-02-12 13:23 UTC (permalink / raw)
  To: igt-dev; +Cc: Petri Latvala

Let's extract the bit that reads the config and initializes xmlrpc so we
can do some basic things with chamelium without the need to do port
auto-discovery and connector mapping.

Signed-off-by: Arkadiusz Hiler <arkadiusz.hiler@intel.com>
---
 lib/igt_chamelium.c | 90 +++++++++++++++++++++++++++++++++------------
 lib/igt_chamelium.h |  2 +
 2 files changed, 69 insertions(+), 23 deletions(-)

diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
index 5f9f777c..d5d8dc60 100644
--- a/lib/igt_chamelium.c
+++ b/lib/igt_chamelium.c
@@ -2294,7 +2294,7 @@ static bool chamelium_autodiscover(struct chamelium *chamelium, int drm_fd)
 	return true;
 }
 
-static bool chamelium_read_config(struct chamelium *chamelium, int drm_fd)
+static bool chamelium_read_config(struct chamelium *chamelium)
 {
 	GError *error = NULL;
 
@@ -2311,10 +2311,7 @@ static bool chamelium_read_config(struct chamelium *chamelium, int drm_fd)
 		return false;
 	}
 
-	if (!chamelium_read_port_mappings(chamelium, drm_fd)) {
-		return false;
-	}
-	return chamelium_autodiscover(chamelium, drm_fd);
+	return true;
 }
 
 /**
@@ -2338,6 +2335,64 @@ static void chamelium_exit_handler(int sig)
 		chamelium_deinit(cleanup_instance);
 }
 
+/**
+ * chamelium_deinit_rpc_only:
+ * @chamelium: The Chamelium instance to use
+ *
+ * Frees the resources used by a connection to the chamelium that was set up
+ * with #chamelium_init_rpc_only.
+ */
+void chamelium_deinit_rpc_only(struct chamelium *chamelium)
+{
+	xmlrpc_env_clean(&chamelium->env);
+	free(chamelium);
+}
+
+/**
+ * chamelium_init_rpc_only:
+ *
+ * Sets up a connection with a chamelium, using the URL specified in the
+ * Chamelium configuration. The function initializes only the RPC - no port
+ * autodiscovery happens, which means only the functions that do not require
+ * struct #chamelium_port can be called with an instance produced by this
+ * function.
+ *
+ * #chamelium_init is almost always a better choice.
+ *
+ * Returns: A newly initialized chamelium struct, or NULL on lack of
+ * configuration
+ */
+struct chamelium *chamelium_init_rpc_only(void)
+{
+	struct chamelium *chamelium = malloc(sizeof(struct chamelium));
+
+	if (!chamelium)
+		return NULL;
+
+	memset(chamelium, 0, sizeof(*chamelium));
+
+	chamelium->drm_fd = -1;
+
+	/* Setup the libxmlrpc context */
+	xmlrpc_env_init(&chamelium->env);
+	xmlrpc_client_setup_global_const(&chamelium->env);
+	xmlrpc_client_create(&chamelium->env, XMLRPC_CLIENT_NO_FLAGS, PACKAGE,
+			     PACKAGE_VERSION, NULL, 0, &chamelium->client);
+	if (chamelium->env.fault_occurred) {
+		igt_debug("Failed to init xmlrpc: %s\n",
+			  chamelium->env.fault_string);
+		goto error;
+	}
+
+	if (!chamelium_read_config(chamelium))
+		goto error;
+
+	return chamelium;
+error:
+	chamelium_deinit_rpc_only(chamelium);
+	return NULL;
+}
+
 /**
  * chamelium_init:
  * @chamelium: The Chamelium instance to use
@@ -2354,9 +2409,9 @@ static void chamelium_exit_handler(int sig)
  */
 struct chamelium *chamelium_init(int drm_fd)
 {
-	struct chamelium *chamelium = malloc(sizeof(struct chamelium));
+	struct chamelium *chamelium = chamelium_init_rpc_only();
 
-	if (!chamelium)
+	if (chamelium == NULL)
 		return NULL;
 
 	/* A chamelium instance was set up previously, so clean it up before
@@ -2365,34 +2420,23 @@ struct chamelium *chamelium_init(int drm_fd)
 	if (cleanup_instance)
 		chamelium_deinit(cleanup_instance);
 
-	memset(chamelium, 0, sizeof(*chamelium));
 	chamelium->drm_fd = drm_fd;
 	IGT_INIT_LIST_HEAD(&chamelium->edids);
 
-	/* Setup the libxmlrpc context */
-	xmlrpc_env_init(&chamelium->env);
-	xmlrpc_client_setup_global_const(&chamelium->env);
-	xmlrpc_client_create(&chamelium->env, XMLRPC_CLIENT_NO_FLAGS, PACKAGE,
-			     PACKAGE_VERSION, NULL, 0, &chamelium->client);
-	if (chamelium->env.fault_occurred) {
-		igt_debug("Failed to init xmlrpc: %s\n",
-			  chamelium->env.fault_string);
+	if (!chamelium_read_port_mappings(chamelium, drm_fd))
 		goto error;
-	}
 
-	if (!chamelium_read_config(chamelium, drm_fd))
+	if (!chamelium_autodiscover(chamelium, drm_fd))
 		goto error;
 
+
 	cleanup_instance = chamelium;
 	igt_install_exit_handler(chamelium_exit_handler);
 
 	return chamelium;
-
 error:
-	xmlrpc_env_clean(&chamelium->env);
-	free(chamelium);
-
-	return NULL;
+	chamelium_deinit_rpc_only(chamelium);
+	return chamelium;
 }
 
 /**
diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
index db6803b1..3b9a1242 100644
--- a/lib/igt_chamelium.h
+++ b/lib/igt_chamelium.h
@@ -100,6 +100,8 @@ struct chamelium_edid;
  */
 #define CHAMELIUM_MAX_AUDIO_CHANNELS 8
 
+void chamelium_deinit_rpc_only(struct chamelium *chamelium);
+struct chamelium *chamelium_init_rpc_only(void);
 struct chamelium *chamelium_init(int drm_fd);
 void chamelium_deinit(struct chamelium *chamelium);
 void chamelium_reset(struct chamelium *chamelium);
-- 
2.24.1

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [igt-dev] [PATCH i-g-t 9/9] lib/kms: Try to plug all Chamelium ports, abort if it fails
  2020-02-12 13:21 [igt-dev] [PATCH i-g-t 0/9] Abort on Chamelium failure Arkadiusz Hiler
                   ` (7 preceding siblings ...)
  2020-02-12 13:23 ` [igt-dev] [PATCH i-g-t 8/9] lib/chamelium: Add functions to initialize XMLRPC only Arkadiusz Hiler
@ 2020-02-12 13:23 ` Arkadiusz Hiler
  2020-02-14 12:27   ` Petri Latvala
  2020-02-12 16:38 ` [igt-dev] ✓ Fi.CI.BAT: success for Abort on Chamelium failure Patchwork
  2020-02-14 15:37 ` [igt-dev] ✗ Fi.CI.IGT: failure " Patchwork
  10 siblings, 1 reply; 29+ messages in thread
From: Arkadiusz Hiler @ 2020-02-12 13:23 UTC (permalink / raw)
  To: igt-dev; +Cc: Petri Latvala

Using chamelium as a display for non-chamelium-aware test is
challenging. The board can be left in multiple different states after
kms_chamelium tests even though we have atexit() handlers and other
measures which try to assure that all ports are plugged in. Sadly this
is not 100% reliable. We also had a few boards hard hanging (happens
very seldom) and requiring manual intervention.

This leads to changes in the testing configuration - we may end up with
any number of connectors plugged in which makes a lot of kms_ tests to
flip between skip and pass depending on a run.

In an attempt to make connectors state less random this patch makes
igt_display_require() chamelium-aware. If chamelium is configured for
given machine we try to reach it and make sure everything is plugged in.
If we fail to do so we abort the execution because the testing
configuration is an unknown.

For machines without a configured chamelium this boils down to a nop.

I have run a bunch of tests and measured how much time we spend in the
Chamelium section of igt_display_require() (n = 1000) with chamelium
configured:

    Min: 0.0030s     Max:    0.0113s
    Avg: 0.0089s     Median: 0.0089s

With ~1000 of KMS subtests in a run it's only a mere 9s.

Fixes: https://gitlab.freedesktop.org/drm/igt-gpu-tools/issues/20
Signed-off-by: Arkadiusz Hiler <arkadiusz.hiler@intel.com>
---
 lib/igt_chamelium.c         | 55 +++++++++++++++++++++++++++++++++++--
 lib/igt_chamelium.h         |  1 +
 lib/igt_kms.c               | 18 ++++++++++++
 tests/kms_chamelium.c       |  7 +++--
 tests/kms_color_chamelium.c |  7 +++--
 5 files changed, 80 insertions(+), 8 deletions(-)

diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
index d5d8dc60..cdf0e3ad 100644
--- a/lib/igt_chamelium.c
+++ b/lib/igt_chamelium.c
@@ -1978,7 +1978,13 @@ static size_t chamelium_get_video_ports(struct chamelium *chamelium,
 	int res_len, i, port_id;
 	size_t port_ids_len = 0;
 
-	res = chamelium_rpc(chamelium, NULL, "GetSupportedInputs", "()");
+	res = __chamelium_rpc(chamelium, NULL, "GetSupportedInputs", "()");
+	if (chamelium->env.fault_occurred) {
+		igt_debug("Chamelium RPC call failed: %s\n",
+		     chamelium->env.fault_string);
+
+		return -1;
+	}
 	res_len = xmlrpc_array_size(&chamelium->env, res);
 	for (i = 0; i < res_len; i++) {
 		xmlrpc_array_read_item(&chamelium->env, res, i, &res_port);
@@ -2181,6 +2187,8 @@ static bool chamelium_autodiscover(struct chamelium *chamelium, int drm_fd)
 	candidate_ports_len = chamelium_get_video_ports(chamelium,
 							candidate_ports);
 
+	igt_assert(candidate_ports_len > 0);
+
 	igt_debug("Starting Chamelium port auto-discovery on %zu ports\n",
 		  candidate_ports_len);
 	igt_gettime(&start);
@@ -2299,14 +2307,14 @@ static bool chamelium_read_config(struct chamelium *chamelium)
 	GError *error = NULL;
 
 	if (!igt_key_file) {
-		igt_warn("No configuration file available for chamelium\n");
+		igt_debug("No configuration file available for chamelium\n");
 		return false;
 	}
 
 	chamelium->url = g_key_file_get_string(igt_key_file, "Chamelium", "URL",
 					       &error);
 	if (!chamelium->url) {
-		igt_warn("Couldn't read chamelium URL from config file: %s\n",
+		igt_debug("Couldn't read chamelium URL from config file: %s\n",
 			 error->message);
 		return false;
 	}
@@ -2402,6 +2410,9 @@ error:
  * Chamelium configuration. This must be called first before trying to use the
  * chamelium.
  *
+ * Needs to happen *after* igt_display_require() as otherwise the board will
+ * get reset.
+ *
  * If we fail to establish a connection with the chamelium, fail to find a
  * configured connector, etc. we fail the current test.
  *
@@ -2482,6 +2493,44 @@ void chamelium_deinit(struct chamelium *chamelium)
 	free(chamelium);
 }
 
+bool chamelium_plug_all(struct chamelium *chamelium)
+{
+	size_t port_count;
+	int port_ids[CHAMELIUM_MAX_PORTS];
+	xmlrpc_value *v;
+	v = __chamelium_rpc(chamelium, NULL, "Reset", "()");
+
+	if (v != NULL)
+		xmlrpc_DECREF(v);
+
+	if (chamelium->env.fault_occurred) {
+		igt_debug("Chamelium RPC call failed: %s\n",
+		     chamelium->env.fault_string);
+
+		return false;
+	}
+
+	port_count = chamelium_get_video_ports(chamelium, port_ids);
+	if (port_count <= 0)
+		return false;
+
+	for (int i = 0; i < port_count; ++i) {
+		v = __chamelium_rpc(chamelium, NULL, "Plug", "(i)", port_ids[i]);
+
+		if (v != NULL)
+			xmlrpc_DECREF(v);
+
+		if (chamelium->env.fault_occurred) {
+			igt_debug("Chamelium RPC call failed: %s\n",
+			     chamelium->env.fault_string);
+
+			return false;
+		}
+	}
+
+	return true;
+}
+
 igt_constructor {
 	/* Frame dumps can be large, so we need to be able to handle very large
 	 * responses
diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
index 3b9a1242..fb273b1a 100644
--- a/lib/igt_chamelium.h
+++ b/lib/igt_chamelium.h
@@ -217,5 +217,6 @@ void chamelium_crop_analog_frame(struct chamelium_frame_dump *dump, int width,
 void chamelium_destroy_frame_dump(struct chamelium_frame_dump *dump);
 void chamelium_destroy_audio_file(struct chamelium_audio_file *audio_file);
 void chamelium_infoframe_destroy(struct chamelium_infoframe *infoframe);
+bool chamelium_plug_all(struct chamelium *chamelium);
 
 #endif /* IGT_CHAMELIUM_H */
diff --git a/lib/igt_kms.c b/lib/igt_kms.c
index 54de45e5..7f9fafb3 100644
--- a/lib/igt_kms.c
+++ b/lib/igt_kms.c
@@ -58,6 +58,9 @@
 #include "igt_device.h"
 #include "igt_sysfs.h"
 #include "sw_sync.h"
+#ifdef HAVE_CHAMELIUM
+#include "igt_chamelium.h"
+#endif
 
 /**
  * SECTION:igt_kms
@@ -1886,6 +1889,21 @@ void igt_display_require(igt_display_t *display, int drm_fd)
 	if (!resources)
 		goto out;
 
+#ifdef HAVE_CHAMELIUM
+	{
+		struct chamelium *chamelium;
+
+		chamelium = chamelium_init_rpc_only();
+		if (chamelium) {
+			igt_abort_on_f(!chamelium_wait_reachable(chamelium, 20),
+				       "cannot reach the configured chamelium!\n");
+			igt_abort_on_f(!chamelium_plug_all(chamelium),
+				       "failed to plug all the chamelium ports!\n");
+			chamelium_deinit_rpc_only(chamelium);
+		}
+	}
+#endif
+
 	/*
 	 * We cache the number of pipes, that number is a physical limit of the
 	 * hardware and cannot change of time (for now, at least).
diff --git a/tests/kms_chamelium.c b/tests/kms_chamelium.c
index 8243d2ef..34e6dda9 100644
--- a/tests/kms_chamelium.c
+++ b/tests/kms_chamelium.c
@@ -2623,6 +2623,10 @@ igt_main
 
 	igt_fixture {
 		data.drm_fd = drm_open_driver_master(DRIVER_ANY);
+		igt_display_require(&data.display, data.drm_fd);
+		igt_require(data.display.is_atomic);
+
+		/* we need to initalize chamelium after igt_display_require */
 		data.chamelium = chamelium_init(data.drm_fd);
 		igt_require(data.chamelium);
 
@@ -2636,9 +2640,6 @@ igt_main
 
 		/* So fbcon doesn't try to reprobe things itself */
 		kmstest_set_vt_graphics_mode();
-
-		igt_display_require(&data.display, data.drm_fd);
-		igt_require(data.display.is_atomic);
 	}
 
 	igt_describe("DisplayPort tests");
diff --git a/tests/kms_color_chamelium.c b/tests/kms_color_chamelium.c
index 34a1888c..7f5a911c 100644
--- a/tests/kms_color_chamelium.c
+++ b/tests/kms_color_chamelium.c
@@ -724,6 +724,11 @@ igt_main
 		data.drm_fd = drm_open_driver_master(DRIVER_ANY);
 		if (is_i915_device(data.drm_fd))
 			data.devid = intel_get_drm_devid(data.drm_fd);
+
+		igt_display_require(&data.display, data.drm_fd);
+		igt_require(data.display.is_atomic);
+
+		/* we need to initalize chamelium after igt_display_require */
 		data.chamelium = chamelium_init(data.drm_fd);
 		igt_require(data.chamelium);
 
@@ -734,8 +739,6 @@ igt_main
 			igt_skip("No ports connected\n");
 
 		kmstest_set_vt_graphics_mode();
-		igt_display_require(&data.display, data.drm_fd);
-		igt_require(data.display.is_atomic);
 	}
 
 	for_each_pipe_static(pipe)
-- 
2.24.1

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* Re: [igt-dev] [PATCH i-g-t 4/9] runner/runner_tests: Extract helper for inspecting test result
  2020-02-12 13:21 ` [igt-dev] [PATCH i-g-t 4/9] runner/runner_tests: Extract helper for inspecting test result Arkadiusz Hiler
@ 2020-02-12 13:37   ` Petri Latvala
  2020-02-12 13:42     ` Petri Latvala
  2020-02-14 12:05   ` Petri Latvala
  1 sibling, 1 reply; 29+ messages in thread
From: Petri Latvala @ 2020-02-12 13:37 UTC (permalink / raw)
  To: Arkadiusz Hiler; +Cc: igt-dev

On Wed, Feb 12, 2020 at 03:21:18PM +0200, Arkadiusz Hiler wrote:
> to make this bit of code more readable and to reuse it in the following patch
> 
> Signed-off-by: Arkadiusz Hiler <arkadiusz.hiler@intel.com>
> ---
>  runner/runner_tests.c | 30 +++++++++++++++++-------------
>  1 file changed, 17 insertions(+), 13 deletions(-)
> 
> diff --git a/runner/runner_tests.c b/runner/runner_tests.c
> index ed30b3f9..dd590f33 100644
> --- a/runner/runner_tests.c
> +++ b/runner/runner_tests.c
> @@ -32,6 +32,16 @@ static const char testdatadir[] = TESTDATA_DIRECTORY;
>  /* The total number of test binaries in runner/testdata/ */
>  #define NUM_TESTDATA_BINARIES 4
>  
> +static const char *igt_get_result(struct json_object *tests, const char* testname)
> +{
> +	struct json_object *obj;
> +
> +	igt_assert(json_object_object_get_ex(tests, testname, &obj));
> +	igt_assert(json_object_object_get_ex(obj, "result", &obj));
> +
> +	return json_object_get_string(obj);
> +}
> +
>  static void igt_assert_eqstr(const char *one, const char *two)
>  {
>  	if (one == NULL && two == NULL)
> @@ -1432,7 +1442,7 @@ igt_main
>  
>  		igt_subtest("dynamic-subtests-in-testlist") {
>  			struct execute_state state;
> -			struct json_object *results, *obj;
> +			struct json_object *results, *tests;
>  			const char *argv[] = { "runner",
>  					       "--test-list", filename,
>  					       testdatadir,
> @@ -1453,16 +1463,13 @@ igt_main
>  			igt_assert_f((results = generate_results_json(dirfd)) != NULL,
>  				     "Results parsing failed\n");
>  
> -			obj = results;
> -			igt_assert(json_object_object_get_ex(obj, "tests", &obj));
> +			igt_assert(json_object_object_get_ex(results, "tests", &tests));
>  
>  			/* Check that the dynamic subtest we didn't request is not reported */
> -			igt_assert(!json_object_object_get_ex(obj, "igt@dynamic@dynamic-subtest@failing", NULL));
> +			igt_assert_no_result_for(tests, "igt@dynamic@dynamic-subtest@failing");


Where is igt_assert_no_result_for defined? *blind*


-- 
Petri Latvala
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [igt-dev] [PATCH i-g-t 4/9] runner/runner_tests: Extract helper for inspecting test result
  2020-02-12 13:37   ` Petri Latvala
@ 2020-02-12 13:42     ` Petri Latvala
  2020-02-12 13:59       ` Arkadiusz Hiler
  0 siblings, 1 reply; 29+ messages in thread
From: Petri Latvala @ 2020-02-12 13:42 UTC (permalink / raw)
  To: Arkadiusz Hiler; +Cc: igt-dev

On Wed, Feb 12, 2020 at 03:37:37PM +0200, Petri Latvala wrote:
> On Wed, Feb 12, 2020 at 03:21:18PM +0200, Arkadiusz Hiler wrote:
> > to make this bit of code more readable and to reuse it in the following patch
> > 
> > Signed-off-by: Arkadiusz Hiler <arkadiusz.hiler@intel.com>
> > ---
> >  runner/runner_tests.c | 30 +++++++++++++++++-------------
> >  1 file changed, 17 insertions(+), 13 deletions(-)
> > 
> > diff --git a/runner/runner_tests.c b/runner/runner_tests.c
> > index ed30b3f9..dd590f33 100644
> > --- a/runner/runner_tests.c
> > +++ b/runner/runner_tests.c
> > @@ -32,6 +32,16 @@ static const char testdatadir[] = TESTDATA_DIRECTORY;
> >  /* The total number of test binaries in runner/testdata/ */
> >  #define NUM_TESTDATA_BINARIES 4
> >  
> > +static const char *igt_get_result(struct json_object *tests, const char* testname)
> > +{
> > +	struct json_object *obj;
> > +
> > +	igt_assert(json_object_object_get_ex(tests, testname, &obj));
> > +	igt_assert(json_object_object_get_ex(obj, "result", &obj));
> > +
> > +	return json_object_get_string(obj);
> > +}
> > +
> >  static void igt_assert_eqstr(const char *one, const char *two)
> >  {
> >  	if (one == NULL && two == NULL)
> > @@ -1432,7 +1442,7 @@ igt_main
> >  
> >  		igt_subtest("dynamic-subtests-in-testlist") {
> >  			struct execute_state state;
> > -			struct json_object *results, *obj;
> > +			struct json_object *results, *tests;
> >  			const char *argv[] = { "runner",
> >  					       "--test-list", filename,
> >  					       testdatadir,
> > @@ -1453,16 +1463,13 @@ igt_main
> >  			igt_assert_f((results = generate_results_json(dirfd)) != NULL,
> >  				     "Results parsing failed\n");
> >  
> > -			obj = results;
> > -			igt_assert(json_object_object_get_ex(obj, "tests", &obj));
> > +			igt_assert(json_object_object_get_ex(results, "tests", &tests));
> >  
> >  			/* Check that the dynamic subtest we didn't request is not reported */
> > -			igt_assert(!json_object_object_get_ex(obj, "igt@dynamic@dynamic-subtest@failing", NULL));
> > +			igt_assert_no_result_for(tests, "igt@dynamic@dynamic-subtest@failing");
> 
> 
> Where is igt_assert_no_result_for defined? *blind*

Found it hiding in the next patch.


-- 
Petri Latvala
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [igt-dev] [PATCH i-g-t 4/9] runner/runner_tests: Extract helper for inspecting test result
  2020-02-12 13:42     ` Petri Latvala
@ 2020-02-12 13:59       ` Arkadiusz Hiler
  0 siblings, 0 replies; 29+ messages in thread
From: Arkadiusz Hiler @ 2020-02-12 13:59 UTC (permalink / raw)
  To: Petri Latvala; +Cc: igt-dev

On Wed, Feb 12, 2020 at 03:42:04PM +0200, Petri Latvala wrote:
> On Wed, Feb 12, 2020 at 03:37:37PM +0200, Petri Latvala wrote:
> > On Wed, Feb 12, 2020 at 03:21:18PM +0200, Arkadiusz Hiler wrote:
> > > to make this bit of code more readable and to reuse it in the following patch
> > > 
> > > Signed-off-by: Arkadiusz Hiler <arkadiusz.hiler@intel.com>
> > > ---
> > >  runner/runner_tests.c | 30 +++++++++++++++++-------------
> > >  1 file changed, 17 insertions(+), 13 deletions(-)
> > > 
> > > diff --git a/runner/runner_tests.c b/runner/runner_tests.c
> > > index ed30b3f9..dd590f33 100644
> > > --- a/runner/runner_tests.c
> > > +++ b/runner/runner_tests.c
> > > @@ -32,6 +32,16 @@ static const char testdatadir[] = TESTDATA_DIRECTORY;
> > >  /* The total number of test binaries in runner/testdata/ */
> > >  #define NUM_TESTDATA_BINARIES 4
> > >  
> > > +static const char *igt_get_result(struct json_object *tests, const char* testname)
> > > +{
> > > +	struct json_object *obj;
> > > +
> > > +	igt_assert(json_object_object_get_ex(tests, testname, &obj));
> > > +	igt_assert(json_object_object_get_ex(obj, "result", &obj));
> > > +
> > > +	return json_object_get_string(obj);
> > > +}
> > > +
> > >  static void igt_assert_eqstr(const char *one, const char *two)
> > >  {
> > >  	if (one == NULL && two == NULL)
> > > @@ -1432,7 +1442,7 @@ igt_main
> > >  
> > >  		igt_subtest("dynamic-subtests-in-testlist") {
> > >  			struct execute_state state;
> > > -			struct json_object *results, *obj;
> > > +			struct json_object *results, *tests;
> > >  			const char *argv[] = { "runner",
> > >  					       "--test-list", filename,
> > >  					       testdatadir,
> > > @@ -1453,16 +1463,13 @@ igt_main
> > >  			igt_assert_f((results = generate_results_json(dirfd)) != NULL,
> > >  				     "Results parsing failed\n");
> > >  
> > > -			obj = results;
> > > -			igt_assert(json_object_object_get_ex(obj, "tests", &obj));
> > > +			igt_assert(json_object_object_get_ex(results, "tests", &tests));
> > >  
> > >  			/* Check that the dynamic subtest we didn't request is not reported */
> > > -			igt_assert(!json_object_object_get_ex(obj, "igt@dynamic@dynamic-subtest@failing", NULL));
> > > +			igt_assert_no_result_for(tests, "igt@dynamic@dynamic-subtest@failing");
> > 
> > 
> > Where is igt_assert_no_result_for defined? *blind*
> 
> Found it hiding in the next patch.

Fixed in:

https://gitlab.freedesktop.org/ivyl/igt/commits/igt_abort
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [igt-dev] ✓ Fi.CI.BAT: success for Abort on Chamelium failure
  2020-02-12 13:21 [igt-dev] [PATCH i-g-t 0/9] Abort on Chamelium failure Arkadiusz Hiler
                   ` (8 preceding siblings ...)
  2020-02-12 13:23 ` [igt-dev] [PATCH i-g-t 9/9] lib/kms: Try to plug all Chamelium ports, abort if it fails Arkadiusz Hiler
@ 2020-02-12 16:38 ` Patchwork
  2020-02-14 15:37 ` [igt-dev] ✗ Fi.CI.IGT: failure " Patchwork
  10 siblings, 0 replies; 29+ messages in thread
From: Patchwork @ 2020-02-12 16:38 UTC (permalink / raw)
  To: Arkadiusz Hiler; +Cc: igt-dev

== Series Details ==

Series: Abort on Chamelium failure
URL   : https://patchwork.freedesktop.org/series/73358/
State : success

== Summary ==

CI Bug Log - changes from CI_DRM_7922 -> IGTPW_4137
====================================================

Summary
-------

  **SUCCESS**

  No regressions found.

  External URL: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/index.html

Known issues
------------

  Here are the changes found in IGTPW_4137 that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@gem_close_race@basic-threads:
    - fi-byt-j1900:       [PASS][1] -> [INCOMPLETE][2] ([i915#45])
   [1]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/fi-byt-j1900/igt@gem_close_race@basic-threads.html
   [2]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/fi-byt-j1900/igt@gem_close_race@basic-threads.html

  * igt@i915_selftest@live_execlists:
    - fi-icl-y:           [PASS][3] -> [DMESG-FAIL][4] ([fdo#108569])
   [3]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/fi-icl-y/igt@i915_selftest@live_execlists.html
   [4]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/fi-icl-y/igt@i915_selftest@live_execlists.html

  * igt@i915_selftest@live_gem_contexts:
    - fi-hsw-peppy:       [PASS][5] -> [DMESG-FAIL][6] ([i915#722])
   [5]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/fi-hsw-peppy/igt@i915_selftest@live_gem_contexts.html
   [6]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/fi-hsw-peppy/igt@i915_selftest@live_gem_contexts.html
    - fi-cml-s:           [PASS][7] -> [DMESG-FAIL][8] ([i915#877])
   [7]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/fi-cml-s/igt@i915_selftest@live_gem_contexts.html
   [8]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/fi-cml-s/igt@i915_selftest@live_gem_contexts.html

  * igt@kms_chamelium@hdmi-hpd-fast:
    - fi-kbl-7500u:       [PASS][9] -> [FAIL][10] ([i915#217])
   [9]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/fi-kbl-7500u/igt@kms_chamelium@hdmi-hpd-fast.html
   [10]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/fi-kbl-7500u/igt@kms_chamelium@hdmi-hpd-fast.html

  
#### Possible fixes ####

  * igt@gem_exec_parallel@contexts:
    - {fi-ehl-1}:         [INCOMPLETE][11] ([i915#937]) -> [PASS][12]
   [11]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/fi-ehl-1/igt@gem_exec_parallel@contexts.html
   [12]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/fi-ehl-1/igt@gem_exec_parallel@contexts.html

  * igt@i915_selftest@live_gtt:
    - fi-kbl-7500u:       [TIMEOUT][13] ([fdo#112271]) -> [PASS][14]
   [13]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/fi-kbl-7500u/igt@i915_selftest@live_gtt.html
   [14]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/fi-kbl-7500u/igt@i915_selftest@live_gtt.html

  
#### Warnings ####

  * igt@kms_chamelium@common-hpd-after-suspend:
    - fi-pnv-d510:        [SKIP][15] ([fdo#109271] / [fdo#111827]) -> [SKIP][16] ([fdo#109271]) +8 similar issues
   [15]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/fi-pnv-d510/igt@kms_chamelium@common-hpd-after-suspend.html
   [16]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/fi-pnv-d510/igt@kms_chamelium@common-hpd-after-suspend.html

  * igt@kms_chamelium@dp-crc-fast:
    - fi-blb-e6850:       [SKIP][17] ([fdo#109271] / [fdo#111827]) -> [SKIP][18] ([fdo#109271]) +8 similar issues
   [17]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/fi-blb-e6850/igt@kms_chamelium@dp-crc-fast.html
   [18]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/fi-blb-e6850/igt@kms_chamelium@dp-crc-fast.html
    - fi-gdg-551:         [SKIP][19] ([fdo#109271] / [fdo#111827]) -> [SKIP][20] ([fdo#109271]) +8 similar issues
   [19]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/fi-gdg-551/igt@kms_chamelium@dp-crc-fast.html
   [20]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/fi-gdg-551/igt@kms_chamelium@dp-crc-fast.html

  * igt@kms_chamelium@hdmi-edid-read:
    - fi-kbl-8809g:       [SKIP][21] ([fdo#109271] / [fdo#111827]) -> [SKIP][22] ([fdo#109271]) +8 similar issues
   [21]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/fi-kbl-8809g/igt@kms_chamelium@hdmi-edid-read.html
   [22]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/fi-kbl-8809g/igt@kms_chamelium@hdmi-edid-read.html

  * igt@kms_chamelium@vga-edid-read:
    - fi-bwr-2160:        [SKIP][23] ([fdo#109271] / [fdo#111827]) -> [SKIP][24] ([fdo#109271]) +8 similar issues
   [23]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/fi-bwr-2160/igt@kms_chamelium@vga-edid-read.html
   [24]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/fi-bwr-2160/igt@kms_chamelium@vga-edid-read.html

  
  {name}: This element is suppressed. This means it is ignored when computing
          the status of the difference (SUCCESS, WARNING, or FAILURE).

  [fdo#108569]: https://bugs.freedesktop.org/show_bug.cgi?id=108569
  [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
  [fdo#111827]: https://bugs.freedesktop.org/show_bug.cgi?id=111827
  [fdo#112271]: https://bugs.freedesktop.org/show_bug.cgi?id=112271
  [i915#217]: https://gitlab.freedesktop.org/drm/intel/issues/217
  [i915#45]: https://gitlab.freedesktop.org/drm/intel/issues/45
  [i915#722]: https://gitlab.freedesktop.org/drm/intel/issues/722
  [i915#877]: https://gitlab.freedesktop.org/drm/intel/issues/877
  [i915#937]: https://gitlab.freedesktop.org/drm/intel/issues/937


Participating hosts (53 -> 44)
------------------------------

  Additional (1): fi-snb-2520m 
  Missing    (10): fi-cml-u2 fi-ilk-m540 fi-hsw-4200u fi-byt-squawks fi-icl-u2 fi-bsw-cyan fi-ctg-p8600 fi-kbl-7560u fi-byt-clapper fi-bdw-samus 


Build changes
-------------

  * CI: CI-20190529 -> None
  * IGT: IGT_5436 -> IGTPW_4137

  CI-20190529: 20190529
  CI_DRM_7922: 0367f4b85f1fbbb1f0df1064803c97d35ed53f24 @ git://anongit.freedesktop.org/gfx-ci/linux
  IGTPW_4137: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/index.html
  IGT_5436: 00a64098aaae2ac3154841d76c7b034165380282 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/index.html
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [igt-dev] [PATCH i-g-t 1/9] lib/tests: Extract fork helpers
  2020-02-12 13:21 ` [igt-dev] [PATCH i-g-t 1/9] lib/tests: Extract fork helpers Arkadiusz Hiler
@ 2020-02-14 11:57   ` Petri Latvala
  0 siblings, 0 replies; 29+ messages in thread
From: Petri Latvala @ 2020-02-14 11:57 UTC (permalink / raw)
  To: Arkadiusz Hiler; +Cc: igt-dev

On Wed, Feb 12, 2020 at 03:21:15PM +0200, Arkadiusz Hiler wrote:
> Because of excessive 'copy and paste' we ended up with multiple copies
> of almost the same fork helper. This patch extracts the do_fork helper
> out and switches all the tests over to it.
> 
> Additionally, preemptively I have extracted the more fancy fork helper
> that captures stderr/out + related functions out of igt_describe tests.
> 
> Signed-off-by: Arkadiusz Hiler <arkadiusz.hiler@intel.com>

Reviewed-by: Petri Latvala <petri.latvala@intel.com>


> ---
>  lib/tests/igt_assert.c               |  35 +++----
>  lib/tests/igt_conflicting_args.c     |  25 ++---
>  lib/tests/igt_describe.c             | 135 ++++++---------------------
>  lib/tests/igt_dynamic_subtests.c     |  18 ----
>  lib/tests/igt_fork.c                 |  71 ++++++--------
>  lib/tests/igt_invalid_subtest_name.c |  18 ----
>  lib/tests/igt_no_exit.c              |  18 ----
>  lib/tests/igt_segfault.c             |  59 +++++-------
>  lib/tests/igt_simulation.c           | 101 +++++++++-----------
>  lib/tests/igt_tests_common.h         |  91 ++++++++++++++++++
>  10 files changed, 232 insertions(+), 339 deletions(-)
> 
> diff --git a/lib/tests/igt_assert.c b/lib/tests/igt_assert.c
> index 1caf5d88..c94ac698 100644
> --- a/lib/tests/igt_assert.c
> +++ b/lib/tests/igt_assert.c
> @@ -38,8 +38,6 @@
>  
>  #include "igt_tests_common.h"
>  
> -char test[] = "test";
> -char *argv_run[] = { test };
>  void (*test_to_run)(void) = NULL;
>  
>  /*
> @@ -55,26 +53,17 @@ void (*test_to_run)(void) = NULL;
>  	exec_total++; \
>  }
>  
> -static int do_fork(void)
> +static void fake_test(void)
>  {
> -	int pid, status;
> -	int argc;
> -
> -	switch (pid = fork()) {
> -	case -1:
> -		internal_assert(0);
> -	case 0:
> -		argc = ARRAY_SIZE(argv_run);
> -		igt_simple_init(argc, argv_run);
> -		test_to_run();
> -		igt_exit();
> -	default:
> -		while (waitpid(pid, &status, 0) == -1 &&
> -		       errno == EINTR)
> -			;
> -
> -		return status;
> -	}
> +	char test[] = "test";
> +	char *argv_run[] = { test };
> +	int argc = ARRAY_SIZE(argv_run);
> +
> +	igt_simple_init(argc, argv_run);
> +
> +	test_to_run();
> +
> +	igt_exit();
>  }
>  
>  static void test_cmpint_negative(void)
> @@ -150,7 +139,7 @@ igt_main
>  	 * we inherit the state from the parent, so ...
>  	 */
>  	test_to_run = test_cmpint_negative;
> -	ret = do_fork();
> +	ret = do_fork(fake_test);
>  	igt_subtest("igt_cmpint_negative")
>  		internal_assert_wexited(ret, IGT_EXIT_FAILURE);
>  
> @@ -158,7 +147,7 @@ igt_main
>  		test_fd();
>  
>  	test_to_run = test_fd_negative;
> -	ret = do_fork();
> +	ret = do_fork(fake_test);
>  	igt_subtest("igt_assert_fd_negative")
>  		internal_assert_wexited(ret, IGT_EXIT_FAILURE);
>  }
> diff --git a/lib/tests/igt_conflicting_args.c b/lib/tests/igt_conflicting_args.c
> index f600abd4..b644fd4b 100644
> --- a/lib/tests/igt_conflicting_args.c
> +++ b/lib/tests/igt_conflicting_args.c
> @@ -43,25 +43,12 @@ static int opt_handler(int option, int option_index, void *input)
>  	return 0;
>  }
>  
> -static int do_fork(void)
> +static void fake_test(void)
>  {
>  	char test_name[] = "test";
> -
>  	char *argv[] = { test_name };
>  	int argc = ARRAY_SIZE(argv);
>  
> -	pid_t pid = fork();
> -	internal_assert(pid != -1);
> -
> -	if (pid) {
> -		int status;
> -		while (waitpid(pid, &status, 0) == -1 && errno == EINTR)
> -			;
> -
> -		return status;
> -	}
> -
> -
>  	igt_subtest_init_parse_opts(&argc, argv, short_options, long_options,
>  				    "", opt_handler, NULL);
>  	igt_subtest("dummy") {}
> @@ -73,27 +60,27 @@ int main(int argc, char **argv)
>  	/* no conflict */
>  	long_options[0] = (struct option) { "iterations", required_argument, NULL, 'i'};
>  	short_options = "";
> -	internal_assert_wexited(do_fork(), 0);
> +	internal_assert_wexited(do_fork(fake_test), 0);
>  
>  	/* conflict on short option */
>  	long_options[0] = (struct option) { "iterations", required_argument, NULL, 'i'};
>  	short_options = "h";
> -	internal_assert_wsignaled(do_fork(), SIGABRT);
> +	internal_assert_wsignaled(do_fork(fake_test), SIGABRT);
>  
>  	/* conflict on long option name */
>  	long_options[0] = (struct option) { "help", required_argument, NULL, 'i'};
>  	short_options = "";
> -	internal_assert_wsignaled(do_fork(), SIGABRT);
> +	internal_assert_wsignaled(do_fork(fake_test), SIGABRT);
>  
>  	/* conflict on long option 'val' representation vs short option */
>  	long_options[0] = (struct option) { "iterations", required_argument, NULL, 'h'};
>  	short_options = "";
> -	internal_assert_wsignaled(do_fork(), SIGABRT);
> +	internal_assert_wsignaled(do_fork(fake_test), SIGABRT);
>  
>  	/* conflict on long option 'val' representations */
>  	long_options[0] = (struct option) { "iterations", required_argument, NULL, 500};
>  	short_options = "";
> -	internal_assert_wsignaled(do_fork(), SIGABRT);
> +	internal_assert_wsignaled(do_fork(fake_test), SIGABRT);
>  
>  	return 0;
>  }
> diff --git a/lib/tests/igt_describe.c b/lib/tests/igt_describe.c
> index 6f3a4319..7b4fa9af 100644
> --- a/lib/tests/igt_describe.c
> +++ b/lib/tests/igt_describe.c
> @@ -28,9 +28,15 @@
>  #include "drmtest.h"
>  #include "igt_tests_common.h"
>  
> +char prog[] = "igt_describe";
> +char fake_arg[100];
> +char *fake_argv[] = {prog, fake_arg};
> +int fake_argc = ARRAY_SIZE(fake_argv);
> +
>  IGT_TEST_DESCRIPTION("the top level description");
> -static void fake_main(int argc, char **argv) {
> -	igt_subtest_init(argc, argv);
> +static void fake_main(void)
> +{
> +	igt_subtest_init(fake_argc, fake_argv);
>  
>  	igt_describe("Basic A");
>  	igt_subtest("A")
> @@ -101,33 +107,33 @@ static void fake_main(int argc, char **argv) {
>  static const char DESCRIBE_ALL_OUTPUT[] = \
>  	"the top level description\n"
>  	"\n"
> -	"SUB A ../lib/tests/igt_describe.c:36:\n"
> +	"SUB A ../lib/tests/igt_describe.c:42:\n"
>  	"  Basic A\n"
>  	"\n"
> -	"SUB B ../lib/tests/igt_describe.c:45:\n"
> +	"SUB B ../lib/tests/igt_describe.c:51:\n"
>  	"  Group with B, C & D\n"
>  	"\n"
>  	"  Basic B\n"
>  	"\n"
> -	"SUB C ../lib/tests/igt_describe.c:54:\n"
> +	"SUB C ../lib/tests/igt_describe.c:60:\n"
>  	"  Group with B, C & D\n"
>  	"\n"
>  	"  Group with C & D\n"
>  	"\n"
>  	"  Basic C\n"
>  	"\n"
> -	"SUB D ../lib/tests/igt_describe.c:58:\n"
> +	"SUB D ../lib/tests/igt_describe.c:64:\n"
>  	"  Group with B, C & D\n"
>  	"\n"
>  	"  Group with C & D\n"
>  	"\n"
> -	"SUB E ../lib/tests/igt_describe.c:66:\n"
> +	"SUB E ../lib/tests/igt_describe.c:72:\n"
>  	"  NO DOCUMENTATION!\n"
>  	"\n"
> -	"SUB F ../lib/tests/igt_describe.c:71:\n"
> +	"SUB F ../lib/tests/igt_describe.c:77:\n"
>  	"  NO DOCUMENTATION!\n"
>  	"\n"
> -	"SUB G ../lib/tests/igt_describe.c:80:\n"
> +	"SUB G ../lib/tests/igt_describe.c:86:\n"
>  	"  this description should be so long that it wraps itself nicely in the terminal this\n"
>  	"  description should be so long that it wraps itself nicely in the terminal this description\n"
>  	"  should be so long that it wraps itself nicely in the terminal this description should be so\n"
> @@ -135,17 +141,17 @@ static const char DESCRIBE_ALL_OUTPUT[] = \
>  	"  wraps itself nicely in the terminal this description should be so long that it wraps itself\n"
>  	"  nicely in the terminal\n"
>  	"\n"
> -	"SUB F ../lib/tests/igt_describe.c:87:\n"
> +	"SUB F ../lib/tests/igt_describe.c:93:\n"
>  	"  verylongwordthatshoudlbeprintedeventhoughitspastthewrppinglimitverylongwordthatshoudlbeprintedeventhoughitspastthewrappinglimit\n"
>  	"  verylongwordthatshoudlbeprintedeventhoughitspastthewrappinglimitverylongwordthatshoudlbeprintedeventhoughitspastthewrappinglimit\n"
>  	"\n"
> -	"SUB G ../lib/tests/igt_describe.c:91:\n"
> +	"SUB G ../lib/tests/igt_describe.c:97:\n"
>  	"  Subtest with dynamic subsubtests\n\n";
>  
>  static const char JUST_C_OUTPUT[] = \
>  	"the top level description\n"
>  	"\n"
> -	"SUB C ../lib/tests/igt_describe.c:54:\n"
> +	"SUB C ../lib/tests/igt_describe.c:60:\n"
>  	"  Group with B, C & D\n"
>  	"\n"
>  	"  Group with C & D\n"
> @@ -153,95 +159,22 @@ static const char JUST_C_OUTPUT[] = \
>  	"  Basic C\n"
>  	"\n";
>  
> -static void assert_pipe_empty(int fd)
> -{
> -	char buf[5];
> -	internal_assert(0 == read(fd, buf, sizeof(buf)));
> -}
> -
> -static void read_whole_pipe(int fd, char *buf, size_t buflen)
> -{
> -	ssize_t readlen;
> -	off_t offset;
> -
> -	offset = 0;
> -	while ((readlen = read(fd, buf+offset, buflen-offset))) {
> -		if (readlen == -1) {
> -			if (errno == EINTR) {
> -				continue;
> -			} else {
> -				printf("read failed with %s\n", strerror(errno));
> -				exit(1);
> -			}
> -		}
> -		internal_assert(readlen != -1);
> -		offset += readlen;
> -	}
> -}
> -
> -static pid_t do_fork(int argc, char **argv, int *out, int *err)
> -{
> -	int outfd[2], errfd[2];
> -	pid_t pid;
> -
> -	internal_assert(pipe(outfd) != -1);
> -	internal_assert(pipe(errfd) != -1);
> -
> -	pid = fork();
> -	internal_assert(pid != -1);
> -
> -	if (pid == 0) {
> -		while (dup2(outfd[1], STDOUT_FILENO) == -1 && errno == EINTR) {}
> -		while (dup2(errfd[1], STDERR_FILENO) == -1 && errno == EINTR) {}
> -
> -		close(outfd[0]);
> -		close(outfd[1]);
> -		close(errfd[0]);
> -		close(errfd[1]);
> -
> -		fake_main(argc, argv);
> -
> -		exit(-1);
> -	} else {
> -		/* close the writing ends */
> -		close(outfd[1]);
> -		close(errfd[1]);
> -
> -		*out = outfd[0];
> -		*err = errfd[0];
> -
> -		return pid;
> -	}
> -}
> -
> -static int _wait(pid_t pid, int *status) {
> -	int ret;
> -
> -	do {
> -		ret = waitpid(pid, status, 0);
> -	} while (ret == -1 && errno == EINTR);
> -
> -	return ret;
> -}
> -
>  int main(int argc, char **argv)
>  {
> -	char prog[] = "igt_describe";
>  	int status;
>  	int outfd, errfd;
> +	pid_t pid;
>  
>  	/* describe all subtest */ {
>  		static char out[4096];
> -		char arg[] = "--describe";
> -		char *fake_argv[] = {prog, arg};
> -		int fake_argc = ARRAY_SIZE(fake_argv);
> +		strncpy(fake_arg, "--describe", sizeof(fake_arg));
>  
> -		pid_t pid = do_fork(fake_argc, fake_argv, &outfd, &errfd);
> +		pid = do_fork_bg_with_pipes(fake_main, &outfd, &errfd);
>  
>  		read_whole_pipe(outfd, out, sizeof(out));
>  		assert_pipe_empty(errfd);
>  
> -		internal_assert(_wait(pid, &status) != -1);
> +		internal_assert(safe_wait(pid, &status) != -1);
>  		internal_assert(WIFEXITED(status));
>  		internal_assert(WEXITSTATUS(status) == IGT_EXIT_SUCCESS);
>  		internal_assert(0 == strcmp(DESCRIBE_ALL_OUTPUT, out));
> @@ -252,16 +185,14 @@ int main(int argc, char **argv)
>  
>  	/* describe C using a pattern */ {
>  		static char out[4096];
> -		char arg[] = "--describe=C";
> -		char *fake_argv[] = {prog, arg};
> -		int fake_argc = ARRAY_SIZE(fake_argv);
> +		strncpy(fake_arg, "--describe=C", sizeof(fake_arg));
>  
> -		pid_t pid = do_fork(fake_argc, fake_argv, &outfd, &errfd);
> +		pid = do_fork_bg_with_pipes(fake_main, &outfd, &errfd);
>  
>  		read_whole_pipe(outfd, out, sizeof(out));
>  		assert_pipe_empty(errfd);
>  
> -		internal_assert(_wait(pid, &status) != -1);
> +		internal_assert(safe_wait(pid, &status) != -1);
>  		internal_assert(WIFEXITED(status));
>  		internal_assert(WEXITSTATUS(status) == IGT_EXIT_SUCCESS);
>  		internal_assert(0 == strcmp(JUST_C_OUTPUT, out));
> @@ -272,15 +203,13 @@ int main(int argc, char **argv)
>  
>  	/* fail describing with a bad pattern */ {
>  		static char err[4096];
> -		char arg[] = "--describe=Z";
> -		char *fake_argv[] = {prog, arg};
> -		int fake_argc = ARRAY_SIZE(fake_argv);
> +		strncpy(fake_arg, "--describe=Z", sizeof(fake_arg));
>  
> -		pid_t pid = do_fork(fake_argc, fake_argv, &outfd, &errfd);
> +		pid = do_fork_bg_with_pipes(fake_main, &outfd, &errfd);
>  
>  		read_whole_pipe(errfd, err, sizeof(err));
>  
> -		internal_assert(_wait(pid, &status) != -1);
> +		internal_assert(safe_wait(pid, &status) != -1);
>  		internal_assert(WIFEXITED(status));
>  		internal_assert(WEXITSTATUS(status) == IGT_EXIT_INVALID);
>  		internal_assert(strstr(err, "Unknown subtest: Z"));
> @@ -291,15 +220,13 @@ int main(int argc, char **argv)
>  
>  	/* trying to igt_describe a dynamic subsubtest should assert */ {
>  		static char err[4096];
> -		char arg[] = "--run-subtest=G";
> -		char *fake_argv[] = {prog, arg};
> -		int fake_argc = ARRAY_SIZE(fake_argv);
> +		strncpy(fake_arg, "--run-subtest=G", sizeof(fake_arg));
>  
> -		pid_t pid = do_fork(fake_argc, fake_argv, &outfd, &errfd);
> +		pid = do_fork_bg_with_pipes(fake_main, &outfd, &errfd);
>  
>  		read_whole_pipe(errfd, err, sizeof(err));
>  
> -		internal_assert(_wait(pid, &status) != -1);
> +		internal_assert(safe_wait(pid, &status) != -1);
>  		internal_assert_wsignaled(status, SIGABRT);
>  
>  		close(outfd);
> diff --git a/lib/tests/igt_dynamic_subtests.c b/lib/tests/igt_dynamic_subtests.c
> index 606104c5..bd1e1675 100644
> --- a/lib/tests/igt_dynamic_subtests.c
> +++ b/lib/tests/igt_dynamic_subtests.c
> @@ -29,24 +29,6 @@
>  
>  #include "igt_tests_common.h"
>  
> -static int do_fork(void (*test_to_run)(void))
> -{
> -	int pid, status;
> -
> -	switch (pid = fork()) {
> -	case -1:
> -		internal_assert(0);
> -	case 0:
> -		test_to_run();
> -	default:
> -		while (waitpid(pid, &status, 0) == -1 &&
> -		       errno == EINTR)
> -			;
> -
> -		return status;
> -	}
> -}
> -
>  static void dynamic_subtest_in_normal_subtest(void)
>  {
>  	char prog[] = "igt_no_exit";
> diff --git a/lib/tests/igt_fork.c b/lib/tests/igt_fork.c
> index e30584fd..4fd0e0c8 100644
> --- a/lib/tests/igt_fork.c
> +++ b/lib/tests/igt_fork.c
> @@ -35,37 +35,52 @@
>  #include "igt_tests_common.h"
>  
>  char test[] = "test";
> -char *argv_run[] = { test };
> +char *fake_argv[] = { test };
> +int fake_argc = ARRAY_SIZE(fake_argv);
>  
>  static void igt_fork_vs_skip(void)
>  {
> +	igt_simple_init(fake_argc, fake_argv);
> +
>  	igt_fork(i, 1) {
>  		igt_skip("skipping");
>  	}
>  
>  	igt_waitchildren();
> +
> +	igt_exit();
>  }
>  
>  static void igt_fork_vs_assert(void)
>  {
> +	igt_simple_init(fake_argc, fake_argv);
> +
>  	igt_fork(i, 1) {
>  		igt_assert(0);
>  	}
>  
>  	igt_waitchildren();
> +
> +	igt_exit();
>  }
>  
>  static void igt_fork_leak(void)
>  {
> +	igt_simple_init(fake_argc, fake_argv);
> +
>  	igt_fork(i, 1) {
>  		sleep(10);
>  	}
> +
> +	igt_exit();
>  }
>  
>  static void plain_fork_leak(void)
>  {
>  	int pid;
>  
> +	igt_simple_init(fake_argc, fake_argv);
> +
>  	switch (pid = fork()) {
>  	case -1:
>  		internal_assert(0);
> @@ -74,59 +89,21 @@ static void plain_fork_leak(void)
>  	default:
>  		exit(0);
>  	}
> +
> +	igt_exit();
>  }
>  
>  static void igt_fork_timeout_leak(void)
>  {
> +	igt_simple_init(fake_argc, fake_argv);
> +
>  	igt_fork(i, 1) {
>  		sleep(10);
>  	}
>  
>  	igt_waitchildren_timeout(1, "library test");
> -}
> -
> -static int do_fork(void (*test_to_run)(void))
> -{
> -	int pid, status;
> -	int argc;
> -
> -	switch (pid = fork()) {
> -	case -1:
> -		internal_assert(0);
> -	case 0:
> -		argc = ARRAY_SIZE(argv_run);
> -		igt_simple_init(argc, argv_run);
> -		test_to_run();
> -		igt_exit();
> -	default:
> -		while (waitpid(pid, &status, 0) == -1 &&
> -		       errno == EINTR)
> -			;
> -
> -		return status;
> -	}
> -}
> -
> -static int do_subtest(void (*test_to_run)(void))
> -{
> -	int pid, status;
> -	int argc;
> -
> -	switch (pid = fork()) {
> -	case -1:
> -		internal_assert(0);
> -	case 0:
> -		argc = ARRAY_SIZE(argv_run);
> -		igt_subtest_init(argc, argv_run);
> -		test_to_run();
> -		igt_exit();
> -	default:
> -		while (waitpid(pid, &status, 0) == -1 &&
> -		       errno == EINTR)
> -			;
>  
> -		return status;
> -	}
> +	igt_exit();
>  }
>  
>  static void subtest_leak(void)
> @@ -135,6 +112,8 @@ static void subtest_leak(void)
>  		mmap(0, 4096, PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
>  	const int num_children = 4096 / sizeof(*children);
>  
> +	igt_subtest_init(fake_argc, fake_argv);
> +
>  	igt_subtest("fork-leak") {
>  		igt_fork(child, num_children)
>  			children[child] = getpid();
> @@ -148,6 +127,8 @@ static void subtest_leak(void)
>  		assert(kill(children[i], 0) == -1 && errno == ESRCH);
>  
>  	munmap(children, 4096);
> +
> +	igt_exit();
>  }
>  
>  int main(int argc, char **argv)
> @@ -174,6 +155,6 @@ int main(int argc, char **argv)
>  	ret = do_fork(plain_fork_leak);
>  	internal_assert_wsignaled(ret, SIGABRT);
>  
> -	ret = do_subtest(subtest_leak);
> +	ret = do_fork(subtest_leak);
>  	internal_assert_wexited(ret, IGT_EXIT_FAILURE); /* not asserted! */
>  }
> diff --git a/lib/tests/igt_invalid_subtest_name.c b/lib/tests/igt_invalid_subtest_name.c
> index 92e767ab..32c4bcbc 100644
> --- a/lib/tests/igt_invalid_subtest_name.c
> +++ b/lib/tests/igt_invalid_subtest_name.c
> @@ -60,24 +60,6 @@ static void nonexisting_subtest(void)
>  	igt_exit();
>  }
>  
> -static int do_fork(void (*test_to_run)(void))
> -{
> -	int pid, status;
> -
> -	switch (pid = fork()) {
> -	case -1:
> -		internal_assert(0);
> -	case 0:
> -		test_to_run();
> -	default:
> -		while (waitpid(pid, &status, 0) == -1 &&
> -		       errno == EINTR)
> -			;
> -
> -		return status;
> -	}
> -}
> -
>  int main(int argc, char **argv)
>  {
>  	int ret;
> diff --git a/lib/tests/igt_no_exit.c b/lib/tests/igt_no_exit.c
> index 82f00b52..d303eba7 100644
> --- a/lib/tests/igt_no_exit.c
> +++ b/lib/tests/igt_no_exit.c
> @@ -56,24 +56,6 @@ static void no_exit(void)
>  		;
>  }
>  
> -static int do_fork(void (*test_to_run)(void))
> -{
> -	int pid, status;
> -
> -	switch (pid = fork()) {
> -	case -1:
> -		internal_assert(0);
> -	case 0:
> -		test_to_run();
> -	default:
> -		while (waitpid(pid, &status, 0) == -1 &&
> -		       errno == EINTR)
> -			;
> -
> -		return status;
> -	}
> -}
> -
>  int main(int argc, char **argv)
>  {
>  	int ret;
> diff --git a/lib/tests/igt_segfault.c b/lib/tests/igt_segfault.c
> index 0d872f67..38c040a6 100644
> --- a/lib/tests/igt_segfault.c
> +++ b/lib/tests/igt_segfault.c
> @@ -48,51 +48,38 @@
>  bool simple;
>  bool runa;
>  bool runc;
> -char test[] = "test";
> -char *argv_run[] = { test };
>  
>  static void crashme(void)
>  {
>  	raise(SIGSEGV);
>  }
>  
> -static int do_fork(void)
> +static void fake_test(void)
>  {
> -	int pid, status;
> -	int argc;
> -
> -	switch (pid = fork()) {
> -	case -1:
> -		internal_assert(0);
> -	case 0:
> -		argc = ARRAY_SIZE(argv_run);
> -		if (simple) {
> -			igt_simple_init(argc, argv_run);
> -			crashme();
> +	char prog[] = "test";
> +	char *fake_argv[] = { prog };
> +	int fake_argc = ARRAY_SIZE(fake_argv);
>  
> -			igt_exit();
> -		} else {
> -			igt_subtest_init(argc, argv_run);
>  
> -			if(runa)
> -				igt_subtest("A")
> -					;
> +	if (simple) {
> +		igt_simple_init(fake_argc, fake_argv);
> +		crashme();
>  
> -			igt_subtest("B")
> -				crashme();
> +		igt_exit();
> +	} else {
> +		igt_subtest_init(fake_argc, fake_argv);
> +		if(runa)
> +			igt_subtest("A")
> +				;
>  
> -			if(runc)
> -				igt_subtest("C")
> -					;
> +		igt_subtest("B")
> +			crashme();
>  
> -			igt_exit();
> -		}
> -	default:
> -		while (waitpid(pid, &status, 0) == -1 &&
> -		       errno == EINTR)
> -			;
> +		if(runc)
> +			igt_subtest("C")
> +				;
>  
> -		return status;
> +		igt_exit();
>  	}
>  }
>  
> @@ -104,20 +91,20 @@ int main(int argc, char **argv)
>  	runc=false;
>  	igt_info("Simple test.\n");
>  	fflush(stdout);
> -	internal_assert_wsignaled(do_fork(), SIGSEGV);
> +	internal_assert_wsignaled(do_fork(fake_test), SIGSEGV);
>  
>  	/* Test crash in a single subtest is reported */
>  	simple = false;
>  	igt_info("Single subtest.\n");
>  	fflush(stdout);
> -	internal_assert_wexited(do_fork(), SIGSEGV + 128);
> +	internal_assert_wexited(do_fork(fake_test), SIGSEGV + 128);
>  
>  	/* Test crash in a subtest following a pass is reported */
>  	simple = false;
>  	runa=true;
>  	igt_info("Passing then crashing subtest.\n");
>  	fflush(stdout);
> -	internal_assert_wexited(do_fork(), SIGSEGV + 128);
> +	internal_assert_wexited(do_fork(fake_test), SIGSEGV + 128);
>  
>  	/* Test crash in a subtest preceeding a pass is reported */
>  	simple = false;
> @@ -125,7 +112,7 @@ int main(int argc, char **argv)
>  	runc=true;
>  	igt_info("Crashing then passing subtest.\n");
>  	fflush(stdout);
> -	internal_assert_wexited(do_fork(), SIGSEGV + 128);
> +	internal_assert_wexited(do_fork(fake_test), SIGSEGV + 128);
>  
>  	return 0;
>  }
> diff --git a/lib/tests/igt_simulation.c b/lib/tests/igt_simulation.c
> index 3f3cd88f..a0ea7000 100644
> --- a/lib/tests/igt_simulation.c
> +++ b/lib/tests/igt_simulation.c
> @@ -40,59 +40,44 @@ bool list_subtests;
>  bool in_fixture;
>  bool in_subtest;
>  
> -char test[] = "test";
> -char list[] = "--list-subtests";
> -char *argv_list[] = { test, list };
> -char *argv_run[] = { test };
> -
> -static int do_fork(void)
> +static void fake_test(void)
>  {
> -	int pid, status;
> +	char test[] = "test";
> +	char list[] = "--list-subtests";
> +	char *argv_list[] = { test, list };
> +	char *argv_run[] = { test };
>  	int argc;
>  
> -	switch (pid = fork()) {
> -	case -1:
> -		internal_assert(0);
> -	case 0:
> -		if (simple) {
> -			argc = 1;
> -			igt_simple_init(argc, argv_run);
> +	if (simple) {
> +		argc = 1;
> +		igt_simple_init(argc, argv_run);
>  
> -			igt_skip_on_simulation();
> +		igt_skip_on_simulation();
>  
> -			igt_exit();
> +		igt_exit();
> +	} else {
> +		if (list_subtests) {
> +			argc = 2;
> +			igt_subtest_init(argc, argv_list);
>  		} else {
> -			if (list_subtests) {
> -				argc = 2;
> -				igt_subtest_init(argc, argv_list);
> -			} else {
> -				argc = 1;
> -				igt_subtest_init(argc, argv_run);
> -			}
> -
> -			if (in_fixture) {
> -				igt_fixture
> -					igt_skip_on_simulation();
> -			} if (in_subtest) {
> -				igt_subtest("sim")
> -					igt_skip_on_simulation();
> -			} else
> -				igt_skip_on_simulation();
> -
> -			if (!in_subtest)
> -				igt_subtest("foo")
> -					;
> -
> -			igt_exit();
> +			argc = 1;
> +			igt_subtest_init(argc, argv_run);
>  		}
> -	default:
> -		while (waitpid(pid, &status, 0) == -1 &&
> -		       errno == EINTR)
> -			;
>  
> -		internal_assert(WIFEXITED(status));
> +		if (in_fixture) {
> +			igt_fixture
> +				igt_skip_on_simulation();
> +		} if (in_subtest) {
> +			igt_subtest("sim")
> +				igt_skip_on_simulation();
> +		} else
> +			igt_skip_on_simulation();
> +
> +		if (!in_subtest)
> +			igt_subtest("foo")
> +				;
>  
> -		return status;
> +		igt_exit();
>  	}
>  }
>  
> @@ -101,10 +86,10 @@ int main(int argc, char **argv)
>  	/* simple tests */
>  	simple = true;
>  	internal_assert(setenv("INTEL_SIMULATION", "1", 1) == 0);
> -	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SKIP);
> +	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SKIP);
>  
>  	internal_assert(setenv("INTEL_SIMULATION", "0", 1) == 0);
> -	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SUCCESS);
> +	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SUCCESS);
>  
>  	/* subtests, list mode */
>  	simple = false;
> @@ -112,28 +97,28 @@ int main(int argc, char **argv)
>  
>  	in_fixture = false;
>  	internal_assert(setenv("INTEL_SIMULATION", "1", 1) == 0);
> -	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SUCCESS);
> +	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SUCCESS);
>  
>  	internal_assert(setenv("INTEL_SIMULATION", "0", 1) == 0);
> -	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SUCCESS);
> +	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SUCCESS);
>  
>  	in_fixture = true;
>  	internal_assert(setenv("INTEL_SIMULATION", "1", 1) == 0);
> -	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SUCCESS);
> +	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SUCCESS);
>  
>  
>  	internal_assert(setenv("INTEL_SIMULATION", "0", 1) == 0);
> -	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SUCCESS);
> +	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SUCCESS);
>  
>  
>  	in_fixture = false;
>  	in_subtest = true;
>  	internal_assert(setenv("INTEL_SIMULATION", "1", 1) == 0);
> -	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SUCCESS);
> +	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SUCCESS);
>  
>  
>  	internal_assert(setenv("INTEL_SIMULATION", "0", 1) == 0);
> -	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SUCCESS);
> +	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SUCCESS);
>  
>  
>  	/* subtest, run mode */
> @@ -142,29 +127,29 @@ int main(int argc, char **argv)
>  
>  	in_fixture = false;
>  	internal_assert(setenv("INTEL_SIMULATION", "1", 1) == 0);
> -	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SKIP);
> +	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SKIP);
>  
>  	internal_assert(setenv("INTEL_SIMULATION", "0", 1) == 0);
> -	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SUCCESS);
> +	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SUCCESS);
>  
>  
>  	in_fixture = true;
>  	internal_assert(setenv("INTEL_SIMULATION", "1", 1) == 0);
> -	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SKIP);
> +	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SKIP);
>  
>  
>  	internal_assert(setenv("INTEL_SIMULATION", "0", 1) == 0);
> -	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SUCCESS);
> +	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SUCCESS);
>  
>  
>  	in_fixture = false;
>  	in_subtest = true;
>  	internal_assert(setenv("INTEL_SIMULATION", "1", 1) == 0);
> -	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SKIP);
> +	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SKIP);
>  
>  
>  	internal_assert(setenv("INTEL_SIMULATION", "0", 1) == 0);
> -	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SUCCESS);
> +	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SUCCESS);
>  
>  
>  	return 0;
> diff --git a/lib/tests/igt_tests_common.h b/lib/tests/igt_tests_common.h
> index e66ee37c..b3da3b34 100644
> --- a/lib/tests/igt_tests_common.h
> +++ b/lib/tests/igt_tests_common.h
> @@ -26,6 +26,8 @@
>  #define IGT_LIB_TESTS_COMMON_H
>  
>  #include <assert.h>
> +#include <sys/wait.h>
> +#include <errno.h>
>  
>  /*
>   * We need to hide assert from the cocci igt test refactor spatch.
> @@ -46,4 +48,93 @@ static inline void internal_assert_wsignaled(int wstatus, int signal)
>  	internal_assert(WIFSIGNALED(wstatus) &&
>  			WTERMSIG(wstatus) == signal);
>  }
> +
> +static inline int do_fork(void (*test_to_run)(void))
> +{
> +	int pid, status;
> +
> +	switch (pid = fork()) {
> +	case -1:
> +		internal_assert(0);
> +	case 0:
> +		test_to_run();
> +	default:
> +		while (waitpid(pid, &status, 0) == -1 &&
> +		       errno == EINTR)
> +			;
> +
> +		return status;
> +	}
> +}
> +
> +static inline pid_t do_fork_bg_with_pipes(void (*test_to_run)(void), int *out, int *err)
> +{
> +	int outfd[2], errfd[2];
> +	pid_t pid;
> +
> +	internal_assert(pipe(outfd) != -1);
> +	internal_assert(pipe(errfd) != -1);
> +
> +	pid = fork();
> +	internal_assert(pid != -1);
> +
> +	if (pid == 0) {
> +		while (dup2(outfd[1], STDOUT_FILENO) == -1 && errno == EINTR) {}
> +		while (dup2(errfd[1], STDERR_FILENO) == -1 && errno == EINTR) {}
> +
> +		close(outfd[0]);
> +		close(outfd[1]);
> +		close(errfd[0]);
> +		close(errfd[1]);
> +
> +		test_to_run();
> +
> +		exit(-1);
> +	} else {
> +		/* close the writing ends */
> +		close(outfd[1]);
> +		close(errfd[1]);
> +
> +		*out = outfd[0];
> +		*err = errfd[0];
> +
> +		return pid;
> +	}
> +}
> +
> +static inline int safe_wait(pid_t pid, int *status) {
> +	int ret;
> +
> +	do {
> +		ret = waitpid(pid, status, 0);
> +	} while (ret == -1 && errno == EINTR);
> +
> +	return ret;
> +}
> +
> +static inline void assert_pipe_empty(int fd)
> +{
> +	char buf[5];
> +	internal_assert(0 == read(fd, buf, sizeof(buf)));
> +}
> +
> +static inline void read_whole_pipe(int fd, char *buf, size_t buflen)
> +{
> +	ssize_t readlen;
> +	off_t offset;
> +
> +	offset = 0;
> +	while ((readlen = read(fd, buf+offset, buflen-offset))) {
> +		if (readlen == -1) {
> +			if (errno == EINTR) {
> +				continue;
> +			} else {
> +				printf("read failed with %s\n", strerror(errno));
> +				exit(1);
> +			}
> +		}
> +		internal_assert(readlen != -1);
> +		offset += readlen;
> +	}
> +}
>  #endif
> -- 
> 2.24.1
> 
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [igt-dev] [PATCH i-g-t 2/9] lib/tests: Add support for redirecting fork output to /dev/null
  2020-02-12 13:21 ` [igt-dev] [PATCH i-g-t 2/9] lib/tests: Add support for redirecting fork output to /dev/null Arkadiusz Hiler
@ 2020-02-14 12:01   ` Petri Latvala
  0 siblings, 0 replies; 29+ messages in thread
From: Petri Latvala @ 2020-02-14 12:01 UTC (permalink / raw)
  To: Arkadiusz Hiler; +Cc: igt-dev

On Wed, Feb 12, 2020 at 03:21:16PM +0200, Arkadiusz Hiler wrote:
> Trying to read interleaved writes is a bit tricky, so let's just use
> /dev/null if we care about contents on only one of those pipes.
> 
> Signed-off-by: Arkadiusz Hiler <arkadiusz.hiler@intel.com>

Reviewed-by: Petri Latvala <petri.latvala@intel.com>


> ---
>  lib/tests/igt_tests_common.h | 35 +++++++++++++++++++++++++++--------
>  1 file changed, 27 insertions(+), 8 deletions(-)
> 
> diff --git a/lib/tests/igt_tests_common.h b/lib/tests/igt_tests_common.h
> index b3da3b34..f285d657 100644
> --- a/lib/tests/igt_tests_common.h
> +++ b/lib/tests/igt_tests_common.h
> @@ -28,6 +28,8 @@
>  #include <assert.h>
>  #include <sys/wait.h>
>  #include <errno.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
>  
>  /*
>   * We need to hide assert from the cocci igt test refactor spatch.
> @@ -72,19 +74,32 @@ static inline pid_t do_fork_bg_with_pipes(void (*test_to_run)(void), int *out, i
>  	int outfd[2], errfd[2];
>  	pid_t pid;
>  
> -	internal_assert(pipe(outfd) != -1);
> -	internal_assert(pipe(errfd) != -1);
> +	if (out != NULL)
> +		internal_assert(pipe(outfd) != -1);
> +
> +	if (err != NULL)
> +		internal_assert(pipe(errfd) != -1);
>  
>  	pid = fork();
>  	internal_assert(pid != -1);
>  
>  	if (pid == 0) {
> +		/* we'll leak the /dev/null fds, let them die with the forked
> +		 * process, also close reading ends if they are any */
> +		if (out == NULL)
> +			outfd[1] = open("/dev/null", O_WRONLY);
> +		else
> +			close(outfd[0]);
> +
> +		if (err == NULL)
> +			errfd[1] = open("/dev/null", O_WRONLY);
> +		else
> +			close(errfd[0]);
> +
>  		while (dup2(outfd[1], STDOUT_FILENO) == -1 && errno == EINTR) {}
>  		while (dup2(errfd[1], STDERR_FILENO) == -1 && errno == EINTR) {}
>  
> -		close(outfd[0]);
>  		close(outfd[1]);
> -		close(errfd[0]);
>  		close(errfd[1]);
>  
>  		test_to_run();
> @@ -92,11 +107,15 @@ static inline pid_t do_fork_bg_with_pipes(void (*test_to_run)(void), int *out, i
>  		exit(-1);
>  	} else {
>  		/* close the writing ends */
> -		close(outfd[1]);
> -		close(errfd[1]);
> +		if (out != NULL) {
> +			close(outfd[1]);
> +			*out = outfd[0];
> +		}
>  
> -		*out = outfd[0];
> -		*err = errfd[0];
> +		if (err != NULL) {
> +			close(errfd[1]);
> +			*err = errfd[0];
> +		}
>  
>  		return pid;
>  	}
> -- 
> 2.24.1
> 
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [igt-dev] [PATCH i-g-t 3/9] lib: Make it possible to abort the whole execution from inside of a test
  2020-02-12 13:21 ` [igt-dev] [PATCH i-g-t 3/9] lib: Make it possible to abort the whole execution from inside of a test Arkadiusz Hiler
@ 2020-02-14 12:04   ` Petri Latvala
  0 siblings, 0 replies; 29+ messages in thread
From: Petri Latvala @ 2020-02-14 12:04 UTC (permalink / raw)
  To: Arkadiusz Hiler; +Cc: igt-dev

On Wed, Feb 12, 2020 at 03:21:17PM +0200, Arkadiusz Hiler wrote:
> igt_abort_on_f() is introduced which does very little cleanup and causes
> a hard exit() of the test binary with a unique exit code
> (IGT_EXIT_ABORT).
> 
> The exit code informs the monitoring process that there is a critical
> issue with the testing environment which may have an impact on the
> results if testing continues.
> 
> Signed-off-by: Arkadiusz Hiler <arkadiusz.hiler@intel.com>

Reviewed-by: Petri Latvala <petri.latvala@intel.com>


> ---
>  lib/igt_core.c        |  46 ++++++++-
>  lib/igt_core.h        |  29 ++++++
>  lib/tests/igt_abort.c | 227 ++++++++++++++++++++++++++++++++++++++++++
>  lib/tests/meson.build |   1 +
>  4 files changed, 300 insertions(+), 3 deletions(-)
>  create mode 100644 lib/tests/igt_abort.c
> 
> diff --git a/lib/igt_core.c b/lib/igt_core.c
> index 51041793..8bd1e642 100644
> --- a/lib/igt_core.c
> +++ b/lib/igt_core.c
> @@ -587,6 +587,7 @@ static void ftrace_dump_on_oops(bool enable)
>  }
>  
>  bool igt_exit_called;
> +bool igt_is_aborting;
>  static void common_exit_handler(int sig)
>  {
>  	if (!igt_only_list_subtests()) {
> @@ -595,7 +596,7 @@ static void common_exit_handler(int sig)
>  
>  	/* When not killed by a signal check that igt_exit() has been properly
>  	 * called. */
> -	assert(sig != 0 || igt_exit_called);
> +	assert(sig != 0 || igt_exit_called || igt_is_aborting);
>  }
>  
>  static void print_line_wrapping(const char *indent, const char *text)
> @@ -1944,6 +1945,46 @@ void __igt_fail_assert(const char *domain, const char *file, const int line,
>  	igt_fail(IGT_EXIT_FAILURE);
>  }
>  
> +static void kill_children(void)
> +{
> +	for (int c = 0; c < num_test_children; c++)
> +		kill(test_children[c], SIGKILL);
> +}
> +
> +void __igt_abort(const char *domain, const char *file, const int line,
> +		 const char *func, const char *expression,
> +		 const char *f, ...)
> +{
> +	va_list args;
> +	int err = errno;
> +
> +	igt_is_aborting = true;
> +
> +	igt_log(domain, IGT_LOG_CRITICAL,
> +		"Test abort in function %s, file %s:%i:\n", func, file,
> +		line);
> +	igt_log(domain, IGT_LOG_CRITICAL, "abort condition: %s\n", expression);
> +	if (err)
> +		igt_log(domain, IGT_LOG_CRITICAL, "Last errno: %i, %s\n", err,
> +			strerror(err));
> +
> +	if (f) {
> +		va_start(args, f);
> +		igt_vlog(domain, IGT_LOG_CRITICAL, f, args);
> +		va_end(args);
> +	}
> +
> +	/* just try our best, we are aborting the execution anyway */
> +	kill_children();
> +
> +	print_backtrace();
> +
> +	if (running_under_gdb())
> +		abort();
> +
> +	exit(IGT_EXIT_ABORT);
> +}
> +
>  /**
>   * igt_exit:
>   *
> @@ -1993,8 +2034,7 @@ void igt_exit(void)
>  			 command_str, igt_exitcode);
>  	igt_debug("Exiting with status code %d\n", igt_exitcode);
>  
> -	for (int c = 0; c < num_test_children; c++)
> -		kill(test_children[c], SIGKILL);
> +	kill_children();
>  	assert(!num_test_children);
>  
>  	assert(waitpid(-1, &tmp, WNOHANG) == -1 && errno == ECHILD);
> diff --git a/lib/igt_core.h b/lib/igt_core.h
> index c17a7ba8..a79b41af 100644
> --- a/lib/igt_core.h
> +++ b/lib/igt_core.h
> @@ -123,6 +123,14 @@ struct _GKeyFile *igt_load_igtrc(void);
>   */
>  #define IGT_EXIT_FAILURE 98
>  
> +/**
> + * IGT_EXIT_ABORT
> + *
> + * Exit status indicating a severe test/enviroment failure, any continued
> + * testing past this point can yeild unexpected reasults and is not recommended
> + */
> +#define IGT_EXIT_ABORT 112
> +
>  bool __igt_fixture(void);
>  void __igt_fixture_complete(void);
>  void __igt_fixture_end(void) __attribute__((noreturn));
> @@ -499,6 +507,11 @@ void __igt_fail_assert(const char *domain, const char *file,
>  		       const int line, const char *func, const char *assertion,
>  		       const char *format, ...)
>  	__attribute__((noreturn));
> +__attribute__((format(printf, 6, 7)))
> +void __igt_abort(const char *domain, const char *file, const int line,
> +		 const char *func, const char *expression,
> +		 const char *f, ...)
> +	__attribute__((noreturn));
>  void igt_exit(void) __attribute__((noreturn));
>  void igt_fatal_error(void) __attribute__((noreturn));
>  
> @@ -1027,6 +1040,22 @@ void igt_describe_f(const char *fmt, ...);
>  	else igt_debug("Test requirement passed: !(%s)\n", #expr); \
>  } while (0)
>  
> +
> +/**
> + * igt_abort_on_f:
> + * @expr: condition to test
> + * @...: format string and optional arguments
> + *
> + * Aborts current execution if a condition is met.
> + *
> + * Should be used only when there is a serious issue with the environment and
> + * any further testing may be affected by it.
> + */
> +#define igt_abort_on_f(expr, f...) \
> +	do { if ((expr)) \
> +		__igt_abort(IGT_LOG_DOMAIN, __FILE__, __LINE__, __func__, #expr , f); \
> +	} while (0)
> +
>  /* fork support code */
>  bool __igt_fork(void);
>  
> diff --git a/lib/tests/igt_abort.c b/lib/tests/igt_abort.c
> new file mode 100644
> index 00000000..53b7d4fd
> --- /dev/null
> +++ b/lib/tests/igt_abort.c
> @@ -0,0 +1,227 @@
> +/*
> + * Copyright © 2020 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + */
> +
> +#include "igt_core.h"
> +#include "drmtest.h"
> +
> +#include "igt_tests_common.h"
> +
> +char test[] = "test";
> +char *fake_argv[] = { test };
> +int fake_argc = ARRAY_SIZE(fake_argv);
> +
> +static void fake_simple_test(void)
> +{
> +	igt_simple_init(fake_argc, fake_argv);
> +
> +	igt_abort_on_f(true, "I'm out!\n");
> +
> +	exit(0); /* unreachable */
> +}
> +
> +static void fake_fixture_test(void)
> +{
> +	igt_subtest_init(fake_argc, fake_argv);
> +
> +	igt_fixture {
> +		igt_abort_on_f(true, "I'm out!\n");
> +	}
> +
> +	exit(0); /* unreachable */
> +}
> +
> +static void fake_outside_fixture_test(void)
> +{
> +	igt_subtest_init(fake_argc, fake_argv);
> +
> +	igt_abort_on_f(true, "I'm out!\n");
> +
> +	exit(0); /* unreachable */
> +}
> +
> +static void fake_subtest_test(void)
> +{
> +	igt_subtest_init(fake_argc, fake_argv);
> +
> +	igt_subtest("A")
> +		;
> +
> +	igt_subtest("B")
> +		igt_abort_on_f(true, "I'm out!\n");
> +
> +	igt_subtest("C")
> +		exit(0); /* unreachable */
> +
> +	exit(0); /* unreachable */
> +}
> +
> +static void fake_dynamic_test(void)
> +{
> +	igt_subtest_init(fake_argc, fake_argv);
> +
> +	igt_subtest_with_dynamic("A") {
> +		igt_dynamic("AA")
> +			;
> +		igt_dynamic("AB")
> +			igt_abort_on_f(true, "I'm out!\n");
> +
> +		igt_dynamic("AC")
> +			exit(0); /* unreachable */
> +
> +	}
> +
> +	igt_subtest("B")
> +		exit(0); /* unreachable */
> +
> +	exit(0); /* unreachable */
> +}
> +
> +static void fake_outside_dynamic_test(void)
> +{
> +	igt_subtest_init(fake_argc, fake_argv);
> +
> +	igt_subtest_with_dynamic("A") {
> +		igt_dynamic("AA")
> +			;
> +
> +		igt_abort_on_f(true, "I'm out!\n");
> +
> +		igt_dynamic("AB")
> +			exit(0); /* unreachable */
> +
> +		igt_dynamic("AC")
> +			exit(0); /* unreachable */
> +
> +	}
> +
> +	igt_subtest("B")
> +		exit(0); /* unreachable */
> +
> +	exit(0); /* unreachable */
> +}
> +
> +int main(int argc, char **argv)
> +{
> +	int status;
> +	pid_t pid;
> +
> +	/* make sure that we log the message and can abort from a simple test*/ {
> +		static char err[4096];
> +		int errfd;
> +
> +		pid = do_fork_bg_with_pipes(fake_simple_test, NULL, &errfd);
> +
> +		read_whole_pipe(errfd, err, sizeof(err));
> +
> +		internal_assert(strstr(err, "CRITICAL: Test abort"));
> +		internal_assert(strstr(err, "I'm out!"));
> +
> +		internal_assert(safe_wait(pid, &status) != -1);
> +		internal_assert_wexited(status, IGT_EXIT_ABORT);
> +	}
> +
> +	/* make sure that we can abort from a fixture */ {
> +		pid = do_fork_bg_with_pipes(fake_fixture_test, NULL, NULL);
> +		internal_assert(safe_wait(pid, &status) != -1);
> +		internal_assert_wexited(status, IGT_EXIT_ABORT);
> +	}
> +
> +	/* make sure that we can abort from outside fixture/subtest */ {
> +		pid = do_fork_bg_with_pipes(fake_outside_fixture_test, NULL, NULL);
> +		internal_assert(safe_wait(pid, &status) != -1);
> +		internal_assert_wexited(status, IGT_EXIT_ABORT);
> +	}
> +
> +	/* make sure we abort during B and don't see B's end/C start */ {
> +		static char out[4096];
> +		int outfd;
> +
> +		pid = do_fork_bg_with_pipes(fake_subtest_test, &outfd, NULL);
> +
> +		read_whole_pipe(outfd, out, sizeof(out));
> +
> +		internal_assert(safe_wait(pid, &status) != -1);
> +		internal_assert_wexited(status, IGT_EXIT_ABORT);
> +
> +		internal_assert(strstr(out, "Starting subtest: A"));
> +		internal_assert(strstr(out, "Subtest A:"));
> +
> +		internal_assert(strstr(out, "Starting subtest: B"));
> +		internal_assert(!strstr(out, "Subtest B:"));
> +
> +		internal_assert(!strstr(out, "Starting subtest: C"));
> +
> +		close(outfd);
> +	}
> +
> +	/* make sure we abort during AB and don't see AC/B */ {
> +		static char out[4096];
> +		int outfd;
> +
> +		pid = do_fork_bg_with_pipes(fake_dynamic_test, &outfd, NULL);
> +
> +		read_whole_pipe(outfd, out, sizeof(out));
> +
> +		internal_assert(safe_wait(pid, &status) != -1);
> +		internal_assert_wexited(status, IGT_EXIT_ABORT);
> +
> +		internal_assert(strstr(out, "Starting subtest: A"));
> +		internal_assert(strstr(out, "Starting dynamic subtest: AA"));
> +		internal_assert(strstr(out, "Dynamic subtest AA:"));
> +
> +		internal_assert(strstr(out, "Starting dynamic subtest: AB"));
> +		internal_assert(!strstr(out, "Dynamic subtest AB:"));
> +
> +		internal_assert(!strstr(out, "Starting subtest: B"));
> +
> +		close(outfd);
> +
> +	}
> +
> +	/* make sure we abort between AA and AB */ {
> +		static char out[4096];
> +		int outfd;
> +
> +		pid = do_fork_bg_with_pipes(fake_outside_dynamic_test, &outfd, NULL);
> +
> +		read_whole_pipe(outfd, out, sizeof(out));
> +
> +		internal_assert(safe_wait(pid, &status) != -1);
> +		internal_assert_wexited(status, IGT_EXIT_ABORT);
> +
> +		internal_assert(strstr(out, "Starting subtest: A"));
> +		internal_assert(strstr(out, "Starting dynamic subtest: AA"));
> +		internal_assert(strstr(out, "Dynamic subtest AA:"));
> +
> +		internal_assert(!strstr(out, "Starting dynamic subtest: AB"));
> +		internal_assert(!strstr(out, "Dynamic subtest AB:"));
> +
> +		internal_assert(!strstr(out, "Starting subtest: B"));
> +
> +		close(outfd);
> +
> +	}
> +
> +	return 0;
> +}
> diff --git a/lib/tests/meson.build b/lib/tests/meson.build
> index e5066665..e75a723a 100644
> --- a/lib/tests/meson.build
> +++ b/lib/tests/meson.build
> @@ -1,5 +1,6 @@
>  lib_tests = [
>  	'igt_assert',
> +	'igt_abort',
>  	'igt_can_fail',
>  	'igt_can_fail_simple',
>  	'igt_conflicting_args',
> -- 
> 2.24.1
> 
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [igt-dev] [PATCH i-g-t 4/9] runner/runner_tests: Extract helper for inspecting test result
  2020-02-12 13:21 ` [igt-dev] [PATCH i-g-t 4/9] runner/runner_tests: Extract helper for inspecting test result Arkadiusz Hiler
  2020-02-12 13:37   ` Petri Latvala
@ 2020-02-14 12:05   ` Petri Latvala
  1 sibling, 0 replies; 29+ messages in thread
From: Petri Latvala @ 2020-02-14 12:05 UTC (permalink / raw)
  To: Arkadiusz Hiler; +Cc: igt-dev

On Wed, Feb 12, 2020 at 03:21:18PM +0200, Arkadiusz Hiler wrote:
> to make this bit of code more readable and to reuse it in the following patch
> 
> Signed-off-by: Arkadiusz Hiler <arkadiusz.hiler@intel.com>

Reviewed-by: Petri Latvala <petri.latvala@intel.com>

> ---
>  runner/runner_tests.c | 30 +++++++++++++++++-------------
>  1 file changed, 17 insertions(+), 13 deletions(-)
> 
> diff --git a/runner/runner_tests.c b/runner/runner_tests.c
> index ed30b3f9..dd590f33 100644
> --- a/runner/runner_tests.c
> +++ b/runner/runner_tests.c
> @@ -32,6 +32,16 @@ static const char testdatadir[] = TESTDATA_DIRECTORY;
>  /* The total number of test binaries in runner/testdata/ */
>  #define NUM_TESTDATA_BINARIES 4
>  
> +static const char *igt_get_result(struct json_object *tests, const char* testname)
> +{
> +	struct json_object *obj;
> +
> +	igt_assert(json_object_object_get_ex(tests, testname, &obj));
> +	igt_assert(json_object_object_get_ex(obj, "result", &obj));
> +
> +	return json_object_get_string(obj);
> +}
> +
>  static void igt_assert_eqstr(const char *one, const char *two)
>  {
>  	if (one == NULL && two == NULL)
> @@ -1432,7 +1442,7 @@ igt_main
>  
>  		igt_subtest("dynamic-subtests-in-testlist") {
>  			struct execute_state state;
> -			struct json_object *results, *obj;
> +			struct json_object *results, *tests;
>  			const char *argv[] = { "runner",
>  					       "--test-list", filename,
>  					       testdatadir,
> @@ -1453,16 +1463,13 @@ igt_main
>  			igt_assert_f((results = generate_results_json(dirfd)) != NULL,
>  				     "Results parsing failed\n");
>  
> -			obj = results;
> -			igt_assert(json_object_object_get_ex(obj, "tests", &obj));
> +			igt_assert(json_object_object_get_ex(results, "tests", &tests));
>  
>  			/* Check that the dynamic subtest we didn't request is not reported */
> -			igt_assert(!json_object_object_get_ex(obj, "igt@dynamic@dynamic-subtest@failing", NULL));
> +			igt_assert_no_result_for(tests, "igt@dynamic@dynamic-subtest@failing");
>  
>  			/* Check that the dynamic subtest we did request is */
> -			igt_assert(json_object_object_get_ex(obj, "igt@dynamic@dynamic-subtest@passing", &obj));
> -			igt_assert(json_object_object_get_ex(obj, "result", &obj));
> -			igt_assert_eqstr(json_object_get_string(obj), "pass");
> +			igt_assert_eqstr(igt_get_result(tests, "igt@dynamic@dynamic-subtest@passing"), "pass");
>  
>  			igt_assert_eq(json_object_put(results), 1);
>  		}
> @@ -1490,7 +1497,7 @@ igt_main
>  
>  		igt_subtest("dynamic-subtest-failure-should-not-cause-warn") {
>  			struct execute_state state;
> -			struct json_object *results, *obj;
> +			struct json_object *results, *tests;
>  			const char *argv[] = { "runner",
>  					       "-t", "dynamic",
>  					       testdatadir,
> @@ -1507,12 +1514,9 @@ igt_main
>  			igt_assert_f((results = generate_results_json(dirfd)) != NULL,
>  				     "Results parsing failed\n");
>  
> -			obj = results;
> -			igt_assert(json_object_object_get_ex(obj, "tests", &obj));
> -			igt_assert(json_object_object_get_ex(obj, "igt@dynamic@dynamic-subtest@passing", &obj));
> -			igt_assert(json_object_object_get_ex(obj, "result", &obj));
> +			igt_assert(json_object_object_get_ex(results, "tests", &tests));
>  
> -			igt_assert_eqstr(json_object_get_string(obj), "pass");
> +			igt_assert_eqstr(igt_get_result(tests, "igt@dynamic@dynamic-subtest@passing"), "pass");
>  
>  			igt_assert_eq(json_object_put(results), 1);
>  		}
> -- 
> 2.24.1
> 
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [igt-dev] [PATCH i-g-t 5/9] runner: Abort the run when test exits with IGT_EXIT_ABORT
  2020-02-12 13:22 ` [igt-dev] [PATCH i-g-t 5/9] runner: Abort the run when test exits with IGT_EXIT_ABORT Arkadiusz Hiler
@ 2020-02-14 12:16   ` Petri Latvala
  0 siblings, 0 replies; 29+ messages in thread
From: Petri Latvala @ 2020-02-14 12:16 UTC (permalink / raw)
  To: Arkadiusz Hiler; +Cc: igt-dev

On Wed, Feb 12, 2020 at 03:22:32PM +0200, Arkadiusz Hiler wrote:
> Now that the IGT tests have a mechanism for signaling broken testing
> conditions we can stop the run on the first test that has noticed it,
> and possibly has triggered that state.
> 
> Traditionally run would have continued with that test failing and the
> side effects would trickle down into the other tests causing a lot of
> skip/fails.
> 
> Signed-off-by: Arkadiusz Hiler <arkadiusz.hiler@intel.com>
> ---
>  runner/executor.c                             |   3 +
>  .../aborted-after-a-test/reference.json       |   6 +
>  .../aborted-on-boot/reference.json            |   6 +
>  .../dmesg-escapes/reference.json              |   3 +
>  .../dmesg-results/reference.json              |   5 +
>  .../reference.json                            |   3 +
>  .../reference.json                            |   3 +
>  .../dmesg-warn-level/reference.json           |   3 +
>  .../reference.json                            |   3 +
>  .../dynamic-subtests/reference.json           |   3 +
>  .../reference.json                            |   5 +
>  .../json_tests_data/normal-run/reference.json |   5 +
>  .../reference.json                            |   4 +
>  .../notrun-results/reference.json             |   5 +
>  .../piglit-style-dmesg/reference.json         |   5 +
>  .../unprintable-characters/reference.json     |   5 +-
>  .../warnings-with-dmesg-warns/reference.json  |   5 +
>  .../json_tests_data/warnings/reference.json   |   5 +

Ahh, the joys of top-down testing.



> diff --git a/runner/resultgen.c b/runner/resultgen.c
> index 105ec887..5e72db9a 100644
> --- a/runner/resultgen.c
> +++ b/runner/resultgen.c
> @@ -645,6 +645,16 @@ static void process_dynamic_subtest_output(const char *piglit_name,
>  					     &dynresulttext, &dyntime,
>  					     dyn_result_idx < 0 ? NULL : matches.items[dyn_result_idx].where,
>  					     dynend);
> +
> +			if (!strcmp(dynresulttext, "incomplete")) {
> +				struct json_object *parent_subtest;
> +
> +				if (json_object_object_get_ex(tests, piglit_name, &parent_subtest) &&
> +				    json_object_object_get_ex(parent_subtest, "result", &parent_subtest) &&
> +				    !strcmp(json_object_get_string(parent_subtest), "abort"))
> +					dynresulttext = "abort";
> +			}
> +

Fairly self-explanatory but could use a comment explaining what is
done when and why.


>  			set_result(current_dynamic_test, dynresulttext);
>  			set_runtime(current_dynamic_test, dyntime);
>  		}
> @@ -1078,6 +1088,8 @@ static const char *result_from_exitcode(int exitcode)
>  		return "pass";
>  	case IGT_EXIT_INVALID:
>  		return "skip";
> +	case IGT_EXIT_ABORT:
> +		return "abort";
>  	case INCOMPLETE_EXITCODE:
>  		return "incomplete";
>  	default:
> @@ -1154,6 +1166,18 @@ static void fill_from_journal(int fd,
>  		}
>  	}
>  
> +	if (subtests->size && exitcode == IGT_EXIT_ABORT)
> +	{


Your { slipped down from the end of the line.


> +		char *last_subtest = subtests->subs[subtests->size - 1].name;
> +		char subtest_piglit_name[256];
> +		struct json_object *subtest_obj;
> +
> +		generate_piglit_name(entry->binary, last_subtest, subtest_piglit_name, sizeof(subtest_piglit_name));
> +		subtest_obj = get_or_create_json_object(tests, subtest_piglit_name);
> +
> +		set_result(subtest_obj, "abort");
> +	}
> +
>  	if (subtests->size == 0) {
>  		char *subtestname = NULL;
>  		char piglit_name[256];
> @@ -1297,6 +1321,7 @@ static struct json_object *get_totals_object(struct json_object *totals,
>  	json_object_object_add(obj, "dmesg-warn", json_object_new_int(0));
>  	json_object_object_add(obj, "skip", json_object_new_int(0));
>  	json_object_object_add(obj, "incomplete", json_object_new_int(0));
> +	json_object_object_add(obj, "abort", json_object_new_int(0));
>  	json_object_object_add(obj, "timeout", json_object_new_int(0));
>  	json_object_object_add(obj, "notrun", json_object_new_int(0));
>  	json_object_object_add(obj, "fail", json_object_new_int(0));
> diff --git a/runner/runner_tests.c b/runner/runner_tests.c
> index dd590f33..701da1a5 100644
> --- a/runner/runner_tests.c
> +++ b/runner/runner_tests.c
> @@ -28,9 +28,16 @@ static const char testdatadir[] = TESTDATA_DIRECTORY;
>   * that test binaries without subtests should still be counted as one
>   * for this macro.
>   */
> -#define NUM_TESTDATA_SUBTESTS 6
> +#define NUM_TESTDATA_SUBTESTS 15
> +#define NUM_TESTDATA_ABORT_SUBTESTS 9
>  /* The total number of test binaries in runner/testdata/ */
> -#define NUM_TESTDATA_BINARIES 4
> +#define NUM_TESTDATA_BINARIES 8
> +
> +static void igt_assert_no_result_for(struct json_object *tests, const char* testname)
> +{
> +	struct json_object *obj;
> +	igt_assert(!json_object_object_get_ex(tests, testname, &obj));
> +}
>  
>  static const char *igt_get_result(struct json_object *tests, const char* testname)
>  {
> @@ -941,6 +948,7 @@ igt_main
>  			struct execute_state state;
>  			const char *argv[] = { "runner",
>  					       "--dry-run",
> +					       "-x", "^abort",
>  					       testdatadir,
>  					       dirname,
>  			};
> @@ -951,7 +959,7 @@ igt_main
>  			igt_assert(initialize_execute_state(&state, settings, list));
>  			igt_assert_eq(state.next, 0);
>  			igt_assert(state.dry);
> -			igt_assert_eq(list->size, NUM_TESTDATA_SUBTESTS);
> +			igt_assert_eq(list->size, NUM_TESTDATA_SUBTESTS - NUM_TESTDATA_ABORT_SUBTESTS);
>  
>  			igt_assert_f((dirfd = open(dirname, O_DIRECTORY | O_RDONLY)) >= 0,
>  				     "Dry run initialization didn't create the results directory.\n");
> @@ -972,7 +980,7 @@ igt_main
>  			igt_assert(initialize_execute_state_from_resume(dirfd, &state, settings, list));
>  			igt_assert_eq(state.next, 0);
>  			igt_assert(!state.dry);
> -			igt_assert_eq(list->size, NUM_TESTDATA_SUBTESTS);
> +			igt_assert_eq(list->size, NUM_TESTDATA_SUBTESTS - NUM_TESTDATA_ABORT_SUBTESTS);
>  			/* initialize_execute_state_from_resume() closes the dirfd */
>  			igt_assert_f((dirfd = open(dirname, O_DIRECTORY | O_RDONLY)) >= 0,
>  				     "Dry run resume somehow deleted the results directory.\n");
> @@ -1499,7 +1507,7 @@ igt_main
>  			struct execute_state state;
>  			struct json_object *results, *tests;
>  			const char *argv[] = { "runner",
> -					       "-t", "dynamic",
> +					       "-t", "^dynamic$",
>  					       testdatadir,
>  					       dirname,
>  			};
> @@ -1528,6 +1536,291 @@ igt_main
>  		}
>  	}
>  
> +	igt_subtest_group {
> +		struct job_list *list = malloc(sizeof(*list));
> +		volatile int dirfd = -1;
> +		char dirname[] = "tmpdirXXXXXX";
> +
> +		igt_fixture {
> +			igt_require(mkdtemp(dirname) != NULL);
> +			rmdir(dirname);
> +
> +			init_job_list(list);
> +		}
> +
> +		igt_subtest("execute-abort-simple") {
> +			struct execute_state state;
> +			struct json_object *results, *tests;
> +			const char *argv[] = { "runner",
> +					       "-t", "^abort-simple$",
> +					       testdatadir,
> +					       dirname,
> +			};
> +
> +			igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
> +			igt_assert(create_job_list(list, settings));
> +			igt_assert(initialize_execute_state(&state, settings, list));
> +			igt_assert(!execute(&state, settings, list)); /* false = signal abort */
> +
> +			igt_assert_f((dirfd = open(dirname, O_DIRECTORY | O_RDONLY)) >= 0,
> +				     "Execute didn't create the results directory\n");
> +			igt_assert_f((results = generate_results_json(dirfd)) != NULL,
> +				     "Results parsing failed\n");
> +
> +			igt_assert(json_object_object_get_ex(results, "tests", &tests));
> +
> +			igt_assert_eqstr(igt_get_result(tests, "igt@abort-simple"), "abort");
> +
> +			igt_assert_eq(json_object_put(results), 1);
> +		}
> +
> +		igt_fixture {
> +			close(dirfd);
> +			clear_directory(dirname);
> +			free_job_list(list);
> +		}
> +	}
> +
> +	igt_subtest_group {
> +		struct job_list *list = malloc(sizeof(*list));
> +		volatile int dirfd = -1;
> +
> +

Extra empty line here.


> +		for (int multiple = 0; multiple <= 1; ++multiple) {
> +			char dirname[] = "tmpdirXXXXXX";
> +
> +			igt_fixture {
> +				igt_require(mkdtemp(dirname) != NULL);
> +				rmdir(dirname);
> +
> +				init_job_list(list);
> +			}
> +
> +			igt_subtest_f("execute-abort%s", multiple ? "-multiple" : "") {
> +				struct execute_state state;
> +				struct json_object *results, *tests;
> +				const char *argv[] = { "runner",
> +						       "-t", "^abort$",
> +						       multiple ? "--multiple-mode" : "--sync",
> +						       testdatadir,
> +						       dirname,
> +				};
> +
> +				igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
> +				igt_assert(create_job_list(list, settings));
> +				igt_assert(initialize_execute_state(&state, settings, list));
> +				igt_assert(!execute(&state, settings, list)); /* false = signal abort */
> +
> +				igt_assert_f((dirfd = open(dirname, O_DIRECTORY | O_RDONLY)) >= 0,
> +					     "Execute didn't create the results directory\n");
> +				igt_assert_f((results = generate_results_json(dirfd)) != NULL,
> +					     "Results parsing failed\n");
> +
> +				igt_assert(json_object_object_get_ex(results, "tests", &tests));
> +
> +				igt_assert_eqstr(igt_get_result(tests, "igt@abort@a-subtest"), "pass");
> +				igt_assert_eqstr(igt_get_result(tests, "igt@abort@b-subtest"), "abort");
> +
> +				if (multiple) /* no notrun injection for multiple mode */
> +					igt_assert_no_result_for(tests, "igt@abort@c-subtest");
> +				else
> +					igt_assert_eqstr(igt_get_result(tests, "igt@abort@c-subtest"), "notrun");
> +
> +				igt_assert_eq(json_object_put(results), 1);
> +			}
> +
> +			igt_fixture {
> +				close(dirfd);
> +				clear_directory(dirname);
> +				free_job_list(list);
> +			}
> +		}
> +	}
> +
> +	igt_subtest_group {
> +		struct job_list *list = malloc(sizeof(*list));
> +		volatile int dirfd = -1;
> +
> +		for (int multiple = 0; multiple <= 1; ++multiple) {
> +			char dirname[] = "tmpdirXXXXXX";
> +
> +			igt_fixture {
> +				igt_require(mkdtemp(dirname) != NULL);
> +				rmdir(dirname);
> +
> +				init_job_list(list);
> +			}
> +
> +			igt_subtest_f("execute-abort-fixture%s", multiple ? "-multiple" : "") {
> +				struct execute_state state;
> +				struct json_object *results, *tests;
> +				const char *argv[] = { "runner", multiple ? "--multiple-mode" : "--sync",
> +						       "-t", "^abort-fixture$",
> +						       testdatadir,
> +						       dirname,
> +				};
> +
> +				igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
> +				igt_assert(create_job_list(list, settings));
> +				igt_assert(initialize_execute_state(&state, settings, list));
> +				igt_assert(!execute(&state, settings, list)); /* false = signal abort */
> +
> +				igt_assert_f((dirfd = open(dirname, O_DIRECTORY | O_RDONLY)) >= 0,
> +					     "Execute didn't create the results directory\n");
> +				igt_assert_f((results = generate_results_json(dirfd)) != NULL,
> +					     "Results parsing failed\n");
> +
> +				igt_assert(json_object_object_get_ex(results, "tests", &tests));
> +
> +				if (multiple) {
> +					/*
> +					 * running the whole binary via -t, no
> +					 * way of blaming the particular subtest
> +					 */
> +					igt_assert_eqstr(igt_get_result(tests, "igt@abort-fixture"), "abort");
> +					igt_assert_no_result_for(tests, "igt@abort-fixture@a-subtest");
> +					igt_assert_no_result_for(tests, "igt@abort-fixture@b-subtest");
> +				} else {
> +					igt_assert_eqstr(igt_get_result(tests, "igt@abort-fixture@a-subtest"), "abort");
> +					igt_assert_eqstr(igt_get_result(tests, "igt@abort-fixture@b-subtest"), "notrun");
> +				}
> +
> +				igt_assert_eq(json_object_put(results), 1);
> +			}
> +
> +			igt_fixture {
> +				close(dirfd);
> +				clear_directory(dirname);
> +				free_job_list(list);
> +			}
> +		}
> +	}
> +
> +	igt_subtest_group {
> +		struct job_list *list = malloc(sizeof(*list));
> +		volatile int dirfd = -1;
> +
> +		for (int multiple = 0; multiple <= 1; ++multiple) {
> +			char dirname[] = "tmpdirXXXXXX";
> +			char filename[] = "tmplistXXXXXX";
> +			const char testlisttext[] = "igt@abort-fixture@b-subtest\n"
> +				"igt@abort-fixture@a-subtest\n";
> +
> +			igt_fixture {
> +				int fd;
> +				igt_require((fd = mkstemp(filename)) >= 0);
> +				igt_require(write(fd, testlisttext, strlen(testlisttext)) == strlen(testlisttext));
> +				close(fd);
> +				igt_require(mkdtemp(dirname) != NULL);
> +				rmdir(dirname);
> +
> +				init_job_list(list);
> +			}
> +
> +			igt_subtest_f("execute-abort-fixture-testlist%s", multiple ? "-multiple" : "") {
> +				struct execute_state state;
> +				struct json_object *results, *tests;
> +				const char *argv[] = { "runner", multiple ? "--multiple-mode" : "--sync",
> +						       "--test-list", filename,
> +						       testdatadir,
> +						       dirname,
> +				};
> +
> +				igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
> +				igt_assert(create_job_list(list, settings));
> +				igt_assert(initialize_execute_state(&state, settings, list));
> +				igt_assert(!execute(&state, settings, list)); /* false = signal abort */
> +
> +				igt_assert_f((dirfd = open(dirname, O_DIRECTORY | O_RDONLY)) >= 0,
> +					     "Execute didn't create the results directory\n");
> +				igt_assert_f((results = generate_results_json(dirfd)) != NULL,
> +					     "Results parsing failed\n");
> +
> +				igt_assert(json_object_object_get_ex(results, "tests", &tests));
> +
> +				if (multiple) /* multiple mode = no notruns */
> +					igt_assert_no_result_for(tests, "igt@abort-fixture@a-subtest");
> +				else
> +					igt_assert_eqstr(igt_get_result(tests, "igt@abort-fixture@a-subtest"), "notrun");
> +
> +
> +				igt_assert_eqstr(igt_get_result(tests, "igt@abort-fixture@b-subtest"), "abort");
> +
> +				igt_assert_eq(json_object_put(results), 1);
> +			}
> +
> +			igt_fixture {
> +				unlink(filename);
> +				close(dirfd);
> +				clear_directory(dirname);
> +				free_job_list(list);
> +			}
> +		}
> +	}
> +
> +	igt_subtest_group {
> +		struct job_list *list = malloc(sizeof(*list));
> +		volatile int dirfd = -1;
> +
> +		for (int multiple = 0; multiple <= 1; ++multiple) {
> +			char dirname[] = "tmpdirXXXXXX";
> +
> +			igt_fixture {
> +				igt_require(mkdtemp(dirname) != NULL);
> +				rmdir(dirname);
> +
> +				init_job_list(list);
> +			}
> +
> +			igt_subtest_f("execute-abort-dynamic%s", multiple ? "-multiple" : "") {
> +				struct execute_state state;
> +				struct json_object *results, *tests;
> +				const char *argv[] = { "runner", multiple ? "--multiple-mode" : "--sync",
> +						       "-t", "^abort-dynamic$",
> +						       testdatadir,
> +						       dirname,
> +				};
> +
> +				igt_assert(parse_options(ARRAY_SIZE(argv), (char**)argv, settings));
> +				igt_assert(create_job_list(list, settings));
> +				igt_assert(initialize_execute_state(&state, settings, list));
> +				igt_assert(!execute(&state, settings, list)); /* false = signal abort */
> +
> +				igt_assert_f((dirfd = open(dirname, O_DIRECTORY | O_RDONLY)) >= 0,
> +					     "Execute didn't create the results directory\n");
> +				igt_assert_f((results = generate_results_json(dirfd)) != NULL,
> +					     "Results parsing failed\n");
> +
> +				igt_assert(json_object_object_get_ex(results, "tests", &tests));
> +
> +				/* { */
> +				/* 	const char *json_string; */
> +				/* 	json_string = json_object_to_json_string_ext(tests, JSON_C_TO_STRING_PRETTY); */
> +				/* 	printf("****\n%s\n***\n", json_string); */
> +				/* } */

New phone, who dis?


Cosmetic editorial comments only, with those addressed,
Reviewed-by: Petri Latvala <petri.latvala@intel.com>
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [igt-dev] [PATCH i-g-t 6/9] lib/chamelium: Clear error after checking if chamelium is reachable
  2020-02-12 13:22 ` [igt-dev] [PATCH i-g-t 6/9] lib/chamelium: Clear error after checking if chamelium is reachable Arkadiusz Hiler
@ 2020-02-14 12:17   ` Petri Latvala
  0 siblings, 0 replies; 29+ messages in thread
From: Petri Latvala @ 2020-02-14 12:17 UTC (permalink / raw)
  To: Arkadiusz Hiler; +Cc: igt-dev

On Wed, Feb 12, 2020 at 03:22:54PM +0200, Arkadiusz Hiler wrote:
> Otherwise this may get us stuck in perpetual failure mode.
> 
> Signed-off-by: Arkadiusz Hiler <arkadiusz.hiler@intel.com>

Reviewed-by: Petri Latvala <petri.latvala@intel.com>

> ---
>  lib/igt_chamelium.c | 10 ++++++++--
>  1 file changed, 8 insertions(+), 2 deletions(-)
> 
> diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
> index aaf17d51..b347682d 100644
> --- a/lib/igt_chamelium.c
> +++ b/lib/igt_chamelium.c
> @@ -361,11 +361,17 @@ static bool __chamelium_is_reachable(struct chamelium *chamelium)
>  	if (res != NULL)
>  		xmlrpc_DECREF(res);
>  
> -	if (chamelium->env.fault_occurred)
> +	if (chamelium->env.fault_occurred) {
>  		igt_debug("Chamelium RPC call failed: %s\n",
>  			  chamelium->env.fault_string);
>  
> -	return !chamelium->env.fault_occurred;
> +		xmlrpc_env_clean(&chamelium->env);
> +		xmlrpc_env_init(&chamelium->env);
> +
> +		return false;
> +	}
> +
> +	return true;
>  }
>  
>  void chamelium_wait_reachable(struct chamelium *chamelium, int timeout)
> -- 
> 2.24.1
> 
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [igt-dev] [PATCH i-g-t 7/9] lib/chamelium: Make it clear that function asserts
  2020-02-12 13:23 ` [igt-dev] [PATCH i-g-t 7/9] lib/chamelium: Make it clear that function asserts Arkadiusz Hiler
@ 2020-02-14 12:19   ` Petri Latvala
  2020-02-17 13:45     ` Arkadiusz Hiler
  0 siblings, 1 reply; 29+ messages in thread
From: Petri Latvala @ 2020-02-14 12:19 UTC (permalink / raw)
  To: Arkadiusz Hiler; +Cc: igt-dev

On Wed, Feb 12, 2020 at 03:23:13PM +0200, Arkadiusz Hiler wrote:
> chamelium_wait_reachable() is asserting internally if the chamelium not
> reachable. Let's make it return bool instead and create
> void chamelium_assert_reachable() that fails the run.
> 
> Signed-off-by: Arkadiusz Hiler <arkadiusz.hiler@intel.com>

Reviewed-by: Petri Latvala <petri.latvala@intel.com>

Aside, Chamelium stuff is documented in a .txt but are there docs for
the lib/igt_chamelium functions anywhere?
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [igt-dev] [PATCH i-g-t 8/9] lib/chamelium: Add functions to initialize XMLRPC only
  2020-02-12 13:23 ` [igt-dev] [PATCH i-g-t 8/9] lib/chamelium: Add functions to initialize XMLRPC only Arkadiusz Hiler
@ 2020-02-14 12:22   ` Petri Latvala
  0 siblings, 0 replies; 29+ messages in thread
From: Petri Latvala @ 2020-02-14 12:22 UTC (permalink / raw)
  To: Arkadiusz Hiler; +Cc: igt-dev

On Wed, Feb 12, 2020 at 03:23:30PM +0200, Arkadiusz Hiler wrote:
> Let's extract the bit that reads the config and initializes xmlrpc so we
> can do some basic things with chamelium without the need to do port
> auto-discovery and connector mapping.
> 
> Signed-off-by: Arkadiusz Hiler <arkadiusz.hiler@intel.com>
> ---
>  lib/igt_chamelium.c | 90 +++++++++++++++++++++++++++++++++------------
>  lib/igt_chamelium.h |  2 +
>  2 files changed, 69 insertions(+), 23 deletions(-)
> 
> diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
> index 5f9f777c..d5d8dc60 100644
> --- a/lib/igt_chamelium.c
> +++ b/lib/igt_chamelium.c
> @@ -2294,7 +2294,7 @@ static bool chamelium_autodiscover(struct chamelium *chamelium, int drm_fd)
>  	return true;
>  }
>  
> -static bool chamelium_read_config(struct chamelium *chamelium, int drm_fd)
> +static bool chamelium_read_config(struct chamelium *chamelium)
>  {
>  	GError *error = NULL;
>  
> @@ -2311,10 +2311,7 @@ static bool chamelium_read_config(struct chamelium *chamelium, int drm_fd)
>  		return false;
>  	}
>  
> -	if (!chamelium_read_port_mappings(chamelium, drm_fd)) {
> -		return false;
> -	}
> -	return chamelium_autodiscover(chamelium, drm_fd);
> +	return true;
>  }
>  
>  /**
> @@ -2338,6 +2335,64 @@ static void chamelium_exit_handler(int sig)
>  		chamelium_deinit(cleanup_instance);
>  }
>  
> +/**
> + * chamelium_deinit_rpc_only:
> + * @chamelium: The Chamelium instance to use
> + *
> + * Frees the resources used by a connection to the chamelium that was set up
> + * with #chamelium_init_rpc_only.
> + */
> +void chamelium_deinit_rpc_only(struct chamelium *chamelium)
> +{
> +	xmlrpc_env_clean(&chamelium->env);
> +	free(chamelium);
> +}
> +
> +/**
> + * chamelium_init_rpc_only:
> + *
> + * Sets up a connection with a chamelium, using the URL specified in the
> + * Chamelium configuration. The function initializes only the RPC - no port
> + * autodiscovery happens, which means only the functions that do not require
> + * struct #chamelium_port can be called with an instance produced by this
> + * function.
> + *
> + * #chamelium_init is almost always a better choice.
> + *
> + * Returns: A newly initialized chamelium struct, or NULL on lack of
> + * configuration
> + */
> +struct chamelium *chamelium_init_rpc_only(void)
> +{
> +	struct chamelium *chamelium = malloc(sizeof(struct chamelium));
> +
> +	if (!chamelium)
> +		return NULL;
> +
> +	memset(chamelium, 0, sizeof(*chamelium));
> +
> +	chamelium->drm_fd = -1;
> +
> +	/* Setup the libxmlrpc context */
> +	xmlrpc_env_init(&chamelium->env);
> +	xmlrpc_client_setup_global_const(&chamelium->env);
> +	xmlrpc_client_create(&chamelium->env, XMLRPC_CLIENT_NO_FLAGS, PACKAGE,
> +			     PACKAGE_VERSION, NULL, 0, &chamelium->client);
> +	if (chamelium->env.fault_occurred) {
> +		igt_debug("Failed to init xmlrpc: %s\n",
> +			  chamelium->env.fault_string);
> +		goto error;
> +	}
> +
> +	if (!chamelium_read_config(chamelium))
> +		goto error;
> +
> +	return chamelium;
> +error:
> +	chamelium_deinit_rpc_only(chamelium);
> +	return NULL;
> +}
> +
>  /**
>   * chamelium_init:
>   * @chamelium: The Chamelium instance to use
> @@ -2354,9 +2409,9 @@ static void chamelium_exit_handler(int sig)
>   */
>  struct chamelium *chamelium_init(int drm_fd)
>  {
> -	struct chamelium *chamelium = malloc(sizeof(struct chamelium));
> +	struct chamelium *chamelium = chamelium_init_rpc_only();
>  
> -	if (!chamelium)
> +	if (chamelium == NULL)
>  		return NULL;
>  
>  	/* A chamelium instance was set up previously, so clean it up before
> @@ -2365,34 +2420,23 @@ struct chamelium *chamelium_init(int drm_fd)
>  	if (cleanup_instance)
>  		chamelium_deinit(cleanup_instance);
>  
> -	memset(chamelium, 0, sizeof(*chamelium));
>  	chamelium->drm_fd = drm_fd;
>  	IGT_INIT_LIST_HEAD(&chamelium->edids);
>  
> -	/* Setup the libxmlrpc context */
> -	xmlrpc_env_init(&chamelium->env);
> -	xmlrpc_client_setup_global_const(&chamelium->env);
> -	xmlrpc_client_create(&chamelium->env, XMLRPC_CLIENT_NO_FLAGS, PACKAGE,
> -			     PACKAGE_VERSION, NULL, 0, &chamelium->client);
> -	if (chamelium->env.fault_occurred) {
> -		igt_debug("Failed to init xmlrpc: %s\n",
> -			  chamelium->env.fault_string);
> +	if (!chamelium_read_port_mappings(chamelium, drm_fd))
>  		goto error;
> -	}
>  
> -	if (!chamelium_read_config(chamelium, drm_fd))
> +	if (!chamelium_autodiscover(chamelium, drm_fd))
>  		goto error;
>  
> +

Extra empty line.


Reviewed-by: Petri Latvala <petri.latvala@intel.com>
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [igt-dev] [PATCH i-g-t 9/9] lib/kms: Try to plug all Chamelium ports, abort if it fails
  2020-02-12 13:23 ` [igt-dev] [PATCH i-g-t 9/9] lib/kms: Try to plug all Chamelium ports, abort if it fails Arkadiusz Hiler
@ 2020-02-14 12:27   ` Petri Latvala
  0 siblings, 0 replies; 29+ messages in thread
From: Petri Latvala @ 2020-02-14 12:27 UTC (permalink / raw)
  To: Arkadiusz Hiler; +Cc: igt-dev

On Wed, Feb 12, 2020 at 03:23:49PM +0200, Arkadiusz Hiler wrote:
> Using chamelium as a display for non-chamelium-aware test is
> challenging. The board can be left in multiple different states after
> kms_chamelium tests even though we have atexit() handlers and other
> measures which try to assure that all ports are plugged in. Sadly this
> is not 100% reliable. We also had a few boards hard hanging (happens
> very seldom) and requiring manual intervention.
> 
> This leads to changes in the testing configuration - we may end up with
> any number of connectors plugged in which makes a lot of kms_ tests to
> flip between skip and pass depending on a run.
> 
> In an attempt to make connectors state less random this patch makes
> igt_display_require() chamelium-aware. If chamelium is configured for
> given machine we try to reach it and make sure everything is plugged in.
> If we fail to do so we abort the execution because the testing
> configuration is an unknown.
> 
> For machines without a configured chamelium this boils down to a nop.
> 
> I have run a bunch of tests and measured how much time we spend in the
> Chamelium section of igt_display_require() (n = 1000) with chamelium
> configured:
> 
>     Min: 0.0030s     Max:    0.0113s
>     Avg: 0.0089s     Median: 0.0089s
> 
> With ~1000 of KMS subtests in a run it's only a mere 9s.
> 
> Fixes: https://gitlab.freedesktop.org/drm/igt-gpu-tools/issues/20
> Signed-off-by: Arkadiusz Hiler <arkadiusz.hiler@intel.com>
> ---
>  lib/igt_chamelium.c         | 55 +++++++++++++++++++++++++++++++++++--
>  lib/igt_chamelium.h         |  1 +
>  lib/igt_kms.c               | 18 ++++++++++++
>  tests/kms_chamelium.c       |  7 +++--
>  tests/kms_color_chamelium.c |  7 +++--
>  5 files changed, 80 insertions(+), 8 deletions(-)
> 
> diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
> index d5d8dc60..cdf0e3ad 100644
> --- a/lib/igt_chamelium.c
> +++ b/lib/igt_chamelium.c
> @@ -1978,7 +1978,13 @@ static size_t chamelium_get_video_ports(struct chamelium *chamelium,
>  	int res_len, i, port_id;
>  	size_t port_ids_len = 0;
>  
> -	res = chamelium_rpc(chamelium, NULL, "GetSupportedInputs", "()");
> +	res = __chamelium_rpc(chamelium, NULL, "GetSupportedInputs", "()");
> +	if (chamelium->env.fault_occurred) {
> +		igt_debug("Chamelium RPC call failed: %s\n",
> +		     chamelium->env.fault_string);
> +
> +		return -1;
> +	}
>  	res_len = xmlrpc_array_size(&chamelium->env, res);
>  	for (i = 0; i < res_len; i++) {
>  		xmlrpc_array_read_item(&chamelium->env, res, i, &res_port);
> @@ -2181,6 +2187,8 @@ static bool chamelium_autodiscover(struct chamelium *chamelium, int drm_fd)
>  	candidate_ports_len = chamelium_get_video_ports(chamelium,
>  							candidate_ports);
>  
> +	igt_assert(candidate_ports_len > 0);
> +
>  	igt_debug("Starting Chamelium port auto-discovery on %zu ports\n",
>  		  candidate_ports_len);
>  	igt_gettime(&start);
> @@ -2299,14 +2307,14 @@ static bool chamelium_read_config(struct chamelium *chamelium)
>  	GError *error = NULL;
>  
>  	if (!igt_key_file) {
> -		igt_warn("No configuration file available for chamelium\n");
> +		igt_debug("No configuration file available for chamelium\n");
>  		return false;
>  	}
>  
>  	chamelium->url = g_key_file_get_string(igt_key_file, "Chamelium", "URL",
>  					       &error);
>  	if (!chamelium->url) {
> -		igt_warn("Couldn't read chamelium URL from config file: %s\n",
> +		igt_debug("Couldn't read chamelium URL from config file: %s\n",
>  			 error->message);
>  		return false;
>  	}
> @@ -2402,6 +2410,9 @@ error:
>   * Chamelium configuration. This must be called first before trying to use the
>   * chamelium.
>   *
> + * Needs to happen *after* igt_display_require() as otherwise the board will
> + * get reset.
> + *
>   * If we fail to establish a connection with the chamelium, fail to find a
>   * configured connector, etc. we fail the current test.
>   *
> @@ -2482,6 +2493,44 @@ void chamelium_deinit(struct chamelium *chamelium)
>  	free(chamelium);
>  }
>  
> +bool chamelium_plug_all(struct chamelium *chamelium)
> +{
> +	size_t port_count;
> +	int port_ids[CHAMELIUM_MAX_PORTS];
> +	xmlrpc_value *v;
> +	v = __chamelium_rpc(chamelium, NULL, "Reset", "()");
> +
> +	if (v != NULL)
> +		xmlrpc_DECREF(v);
> +
> +	if (chamelium->env.fault_occurred) {
> +		igt_debug("Chamelium RPC call failed: %s\n",
> +		     chamelium->env.fault_string);
> +
> +		return false;
> +	}
> +
> +	port_count = chamelium_get_video_ports(chamelium, port_ids);
> +	if (port_count <= 0)
> +		return false;
> +
> +	for (int i = 0; i < port_count; ++i) {
> +		v = __chamelium_rpc(chamelium, NULL, "Plug", "(i)", port_ids[i]);
> +
> +		if (v != NULL)
> +			xmlrpc_DECREF(v);
> +
> +		if (chamelium->env.fault_occurred) {
> +			igt_debug("Chamelium RPC call failed: %s\n",
> +			     chamelium->env.fault_string);
> +
> +			return false;
> +		}
> +	}
> +
> +	return true;
> +}
> +
>  igt_constructor {
>  	/* Frame dumps can be large, so we need to be able to handle very large
>  	 * responses
> diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
> index 3b9a1242..fb273b1a 100644
> --- a/lib/igt_chamelium.h
> +++ b/lib/igt_chamelium.h
> @@ -217,5 +217,6 @@ void chamelium_crop_analog_frame(struct chamelium_frame_dump *dump, int width,
>  void chamelium_destroy_frame_dump(struct chamelium_frame_dump *dump);
>  void chamelium_destroy_audio_file(struct chamelium_audio_file *audio_file);
>  void chamelium_infoframe_destroy(struct chamelium_infoframe *infoframe);
> +bool chamelium_plug_all(struct chamelium *chamelium);
>  
>  #endif /* IGT_CHAMELIUM_H */
> diff --git a/lib/igt_kms.c b/lib/igt_kms.c
> index 54de45e5..7f9fafb3 100644
> --- a/lib/igt_kms.c
> +++ b/lib/igt_kms.c
> @@ -58,6 +58,9 @@
>  #include "igt_device.h"
>  #include "igt_sysfs.h"
>  #include "sw_sync.h"
> +#ifdef HAVE_CHAMELIUM
> +#include "igt_chamelium.h"
> +#endif
>  
>  /**
>   * SECTION:igt_kms
> @@ -1886,6 +1889,21 @@ void igt_display_require(igt_display_t *display, int drm_fd)
>  	if (!resources)
>  		goto out;
>  
> +#ifdef HAVE_CHAMELIUM
> +	{
> +		struct chamelium *chamelium;
> +
> +		chamelium = chamelium_init_rpc_only();
> +		if (chamelium) {
> +			igt_abort_on_f(!chamelium_wait_reachable(chamelium, 20),
> +				       "cannot reach the configured chamelium!\n");
> +			igt_abort_on_f(!chamelium_plug_all(chamelium),
> +				       "failed to plug all the chamelium ports!\n");
> +			chamelium_deinit_rpc_only(chamelium);
> +		}
> +	}
> +#endif
> +
>  	/*
>  	 * We cache the number of pipes, that number is a physical limit of the
>  	 * hardware and cannot change of time (for now, at least).
> diff --git a/tests/kms_chamelium.c b/tests/kms_chamelium.c
> index 8243d2ef..34e6dda9 100644
> --- a/tests/kms_chamelium.c
> +++ b/tests/kms_chamelium.c
> @@ -2623,6 +2623,10 @@ igt_main
>  
>  	igt_fixture {
>  		data.drm_fd = drm_open_driver_master(DRIVER_ANY);
> +		igt_display_require(&data.display, data.drm_fd);
> +		igt_require(data.display.is_atomic);
> +
> +		/* we need to initalize chamelium after igt_display_require */
>  		data.chamelium = chamelium_init(data.drm_fd);
>  		igt_require(data.chamelium);
>  
> @@ -2636,9 +2640,6 @@ igt_main
>  
>  		/* So fbcon doesn't try to reprobe things itself */
>  		kmstest_set_vt_graphics_mode();
> -
> -		igt_display_require(&data.display, data.drm_fd);
> -		igt_require(data.display.is_atomic);
>  	}

For this and kms_color_chamelium: Does it matter that
kmstest_set_vt_graphics_mode() is now after igt_display_require?


-- 
Petri Latvala
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [igt-dev] ✗ Fi.CI.IGT: failure for Abort on Chamelium failure
  2020-02-12 13:21 [igt-dev] [PATCH i-g-t 0/9] Abort on Chamelium failure Arkadiusz Hiler
                   ` (9 preceding siblings ...)
  2020-02-12 16:38 ` [igt-dev] ✓ Fi.CI.BAT: success for Abort on Chamelium failure Patchwork
@ 2020-02-14 15:37 ` Patchwork
  10 siblings, 0 replies; 29+ messages in thread
From: Patchwork @ 2020-02-14 15:37 UTC (permalink / raw)
  To: Arkadiusz Hiler; +Cc: igt-dev

== Series Details ==

Series: Abort on Chamelium failure
URL   : https://patchwork.freedesktop.org/series/73358/
State : failure

== Summary ==

CI Bug Log - changes from CI_DRM_7922_full -> IGTPW_4137_full
====================================================

Summary
-------

  **FAILURE**

  Serious unknown changes coming with IGTPW_4137_full absolutely need to be
  verified manually.
  
  If you think the reported changes have nothing to do with the changes
  introduced in IGTPW_4137_full, please notify your bug team to allow them
  to document this new failure mode, which will reduce false positives in CI.

  External URL: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/index.html

Possible new issues
-------------------

  Here are the unknown changes that may have been introduced in IGTPW_4137_full:

### IGT changes ###

#### Possible regressions ####

  * igt@kms_prime@basic-crc:
    - shard-tglb:         [PASS][1] -> [FAIL][2]
   [1]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-tglb5/igt@kms_prime@basic-crc.html
   [2]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-tglb2/igt@kms_prime@basic-crc.html

  
Known issues
------------

  Here are the changes found in IGTPW_4137_full that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@gem_ctx_isolation@vecs0-s3:
    - shard-kbl:          [PASS][3] -> [INCOMPLETE][4] ([fdo#103665])
   [3]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-kbl6/igt@gem_ctx_isolation@vecs0-s3.html
   [4]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-kbl3/igt@gem_ctx_isolation@vecs0-s3.html

  * igt@gem_ctx_shared@exec-single-timeline-bsd:
    - shard-iclb:         [PASS][5] -> [SKIP][6] ([fdo#110841])
   [5]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-iclb8/igt@gem_ctx_shared@exec-single-timeline-bsd.html
   [6]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-iclb2/igt@gem_ctx_shared@exec-single-timeline-bsd.html

  * igt@gem_exec_parallel@vcs1-fds:
    - shard-iclb:         [PASS][7] -> [SKIP][8] ([fdo#112080]) +11 similar issues
   [7]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-iclb4/igt@gem_exec_parallel@vcs1-fds.html
   [8]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-iclb7/igt@gem_exec_parallel@vcs1-fds.html

  * igt@gem_exec_schedule@pi-userfault-bsd:
    - shard-iclb:         [PASS][9] -> [SKIP][10] ([i915#677])
   [9]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-iclb3/igt@gem_exec_schedule@pi-userfault-bsd.html
   [10]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-iclb4/igt@gem_exec_schedule@pi-userfault-bsd.html

  * igt@gem_exec_schedule@preempt-queue-bsd:
    - shard-iclb:         [PASS][11] -> [SKIP][12] ([fdo#112146]) +3 similar issues
   [11]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-iclb7/igt@gem_exec_schedule@preempt-queue-bsd.html
   [12]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-iclb1/igt@gem_exec_schedule@preempt-queue-bsd.html

  * igt@gem_exec_schedule@preempt-queue-bsd1:
    - shard-iclb:         [PASS][13] -> [SKIP][14] ([fdo#109276]) +13 similar issues
   [13]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-iclb2/igt@gem_exec_schedule@preempt-queue-bsd1.html
   [14]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-iclb5/igt@gem_exec_schedule@preempt-queue-bsd1.html

  * igt@gem_softpin@noreloc-s3:
    - shard-apl:          [PASS][15] -> [DMESG-WARN][16] ([i915#180]) +3 similar issues
   [15]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-apl2/igt@gem_softpin@noreloc-s3.html
   [16]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-apl8/igt@gem_softpin@noreloc-s3.html

  * igt@gem_userptr_blits@sync-unmap-cycles:
    - shard-snb:          [PASS][17] -> [DMESG-WARN][18] ([fdo#111870] / [i915#478])
   [17]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-snb4/igt@gem_userptr_blits@sync-unmap-cycles.html
   [18]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-snb5/igt@gem_userptr_blits@sync-unmap-cycles.html

  * igt@i915_pm_rps@waitboost:
    - shard-iclb:         [PASS][19] -> [FAIL][20] ([i915#413])
   [19]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-iclb8/igt@i915_pm_rps@waitboost.html
   [20]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-iclb6/igt@i915_pm_rps@waitboost.html

  * igt@i915_selftest@live_gtt:
    - shard-hsw:          [PASS][21] -> [TIMEOUT][22] ([fdo#112271])
   [21]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-hsw2/igt@i915_selftest@live_gtt.html
   [22]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-hsw7/igt@i915_selftest@live_gtt.html

  * igt@kms_cursor_crc@pipe-a-cursor-128x42-onscreen:
    - shard-tglb:         [PASS][23] -> [FAIL][24] ([fdo#111703])
   [23]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-tglb6/igt@kms_cursor_crc@pipe-a-cursor-128x42-onscreen.html
   [24]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-tglb1/igt@kms_cursor_crc@pipe-a-cursor-128x42-onscreen.html

  * igt@kms_cursor_crc@pipe-c-cursor-suspend:
    - shard-kbl:          [PASS][25] -> [DMESG-WARN][26] ([i915#180]) +3 similar issues
   [25]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-kbl3/igt@kms_cursor_crc@pipe-c-cursor-suspend.html
   [26]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-kbl3/igt@kms_cursor_crc@pipe-c-cursor-suspend.html

  * igt@kms_cursor_legacy@pipe-c-torture-move:
    - shard-glk:          [PASS][27] -> [DMESG-WARN][28] ([i915#128])
   [27]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-glk7/igt@kms_cursor_legacy@pipe-c-torture-move.html
   [28]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-glk1/igt@kms_cursor_legacy@pipe-c-torture-move.html

  * igt@kms_draw_crc@draw-method-xrgb8888-mmap-wc-ytiled:
    - shard-tglb:         [PASS][29] -> [DMESG-FAIL][30] ([i915#402])
   [29]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-tglb6/igt@kms_draw_crc@draw-method-xrgb8888-mmap-wc-ytiled.html
   [30]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-tglb8/igt@kms_draw_crc@draw-method-xrgb8888-mmap-wc-ytiled.html

  * igt@kms_flip@flip-vs-modeset-interruptible:
    - shard-hsw:          [PASS][31] -> [DMESG-WARN][32] ([i915#44])
   [31]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-hsw1/igt@kms_flip@flip-vs-modeset-interruptible.html
   [32]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-hsw5/igt@kms_flip@flip-vs-modeset-interruptible.html

  * igt@kms_frontbuffer_tracking@fbc-1p-primscrn-spr-indfb-draw-mmap-gtt:
    - shard-kbl:          [PASS][33] -> [FAIL][34] ([i915#49])
   [33]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-kbl6/igt@kms_frontbuffer_tracking@fbc-1p-primscrn-spr-indfb-draw-mmap-gtt.html
   [34]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-kbl2/igt@kms_frontbuffer_tracking@fbc-1p-primscrn-spr-indfb-draw-mmap-gtt.html
    - shard-apl:          [PASS][35] -> [FAIL][36] ([i915#49])
   [35]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-apl4/igt@kms_frontbuffer_tracking@fbc-1p-primscrn-spr-indfb-draw-mmap-gtt.html
   [36]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-apl7/igt@kms_frontbuffer_tracking@fbc-1p-primscrn-spr-indfb-draw-mmap-gtt.html

  * igt@kms_frontbuffer_tracking@fbc-2p-primscrn-shrfb-msflip-blt:
    - shard-glk:          [PASS][37] -> [FAIL][38] ([i915#49])
   [37]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-glk7/igt@kms_frontbuffer_tracking@fbc-2p-primscrn-shrfb-msflip-blt.html
   [38]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-glk1/igt@kms_frontbuffer_tracking@fbc-2p-primscrn-shrfb-msflip-blt.html

  * igt@kms_plane_lowres@pipe-a-tiling-x:
    - shard-glk:          [PASS][39] -> [FAIL][40] ([i915#899]) +1 similar issue
   [39]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-glk6/igt@kms_plane_lowres@pipe-a-tiling-x.html
   [40]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-glk1/igt@kms_plane_lowres@pipe-a-tiling-x.html

  * igt@kms_plane_multiple@atomic-pipe-a-tiling-none:
    - shard-tglb:         [PASS][41] -> [FAIL][42] ([i915#778])
   [41]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-tglb5/igt@kms_plane_multiple@atomic-pipe-a-tiling-none.html
   [42]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-tglb1/igt@kms_plane_multiple@atomic-pipe-a-tiling-none.html

  * igt@kms_psr@psr2_primary_page_flip:
    - shard-iclb:         [PASS][43] -> [SKIP][44] ([fdo#109441]) +4 similar issues
   [43]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-iclb2/igt@kms_psr@psr2_primary_page_flip.html
   [44]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-iclb4/igt@kms_psr@psr2_primary_page_flip.html

  * igt@kms_setmode@basic:
    - shard-apl:          [PASS][45] -> [FAIL][46] ([i915#31])
   [45]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-apl4/igt@kms_setmode@basic.html
   [46]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-apl2/igt@kms_setmode@basic.html

  * igt@perf@gen12-mi-rpc:
    - shard-tglb:         [PASS][47] -> [TIMEOUT][48] ([fdo#112271] / [i915#1085])
   [47]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-tglb1/igt@perf@gen12-mi-rpc.html
   [48]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-tglb2/igt@perf@gen12-mi-rpc.html

  
#### Possible fixes ####

  * igt@gem_ctx_isolation@bcs0-s3:
    - shard-apl:          [DMESG-WARN][49] ([i915#180]) -> [PASS][50] +4 similar issues
   [49]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-apl8/igt@gem_ctx_isolation@bcs0-s3.html
   [50]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-apl6/igt@gem_ctx_isolation@bcs0-s3.html

  * igt@gem_exec_balancer@hang:
    - shard-tglb:         [TIMEOUT][51] ([fdo#112271]) -> [PASS][52]
   [51]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-tglb3/igt@gem_exec_balancer@hang.html
   [52]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-tglb6/igt@gem_exec_balancer@hang.html

  * igt@gem_exec_schedule@independent-bsd2:
    - shard-iclb:         [SKIP][53] ([fdo#109276]) -> [PASS][54] +27 similar issues
   [53]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-iclb6/igt@gem_exec_schedule@independent-bsd2.html
   [54]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-iclb4/igt@gem_exec_schedule@independent-bsd2.html

  * igt@gem_exec_schedule@pi-common-bsd:
    - shard-iclb:         [SKIP][55] ([i915#677]) -> [PASS][56]
   [55]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-iclb1/igt@gem_exec_schedule@pi-common-bsd.html
   [56]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-iclb3/igt@gem_exec_schedule@pi-common-bsd.html

  * igt@gem_exec_schedule@wide-bsd:
    - shard-iclb:         [SKIP][57] ([fdo#112146]) -> [PASS][58] +6 similar issues
   [57]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-iclb2/igt@gem_exec_schedule@wide-bsd.html
   [58]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-iclb7/igt@gem_exec_schedule@wide-bsd.html

  * igt@gem_mmap_gtt@basic-small-copy-xy:
    - shard-snb:          [DMESG-WARN][59] ([i915#478]) -> [PASS][60]
   [59]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-snb4/igt@gem_mmap_gtt@basic-small-copy-xy.html
   [60]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-snb2/igt@gem_mmap_gtt@basic-small-copy-xy.html

  * igt@gem_ppgtt@flink-and-close-vma-leak:
    - shard-glk:          [FAIL][61] ([i915#644]) -> [PASS][62]
   [61]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-glk1/igt@gem_ppgtt@flink-and-close-vma-leak.html
   [62]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-glk1/igt@gem_ppgtt@flink-and-close-vma-leak.html

  * igt@i915_pm_dc@dc5-dpms:
    - shard-iclb:         [FAIL][63] ([i915#447]) -> [PASS][64]
   [63]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-iclb3/igt@i915_pm_dc@dc5-dpms.html
   [64]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-iclb6/igt@i915_pm_dc@dc5-dpms.html

  * igt@i915_pm_dc@dc5-psr:
    - shard-tglb:         [SKIP][65] ([i915#668]) -> [PASS][66]
   [65]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-tglb1/igt@i915_pm_dc@dc5-psr.html
   [66]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-tglb5/igt@i915_pm_dc@dc5-psr.html

  * igt@i915_pm_dc@dc6-dpms:
    - shard-iclb:         [FAIL][67] ([i915#454]) -> [PASS][68]
   [67]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-iclb3/igt@i915_pm_dc@dc6-dpms.html
   [68]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-iclb4/igt@i915_pm_dc@dc6-dpms.html

  * igt@i915_pm_rpm@modeset-stress-extra-wait:
    - shard-glk:          [DMESG-WARN][69] ([i915#118] / [i915#95]) -> [PASS][70]
   [69]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-glk8/igt@i915_pm_rpm@modeset-stress-extra-wait.html
   [70]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-glk8/igt@i915_pm_rpm@modeset-stress-extra-wait.html

  * igt@kms_big_fb@y-tiled-16bpp-rotate-270:
    - shard-tglb:         [FAIL][71] ([i915#1172]) -> [PASS][72]
   [71]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-tglb1/igt@kms_big_fb@y-tiled-16bpp-rotate-270.html
   [72]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-tglb8/igt@kms_big_fb@y-tiled-16bpp-rotate-270.html

  * igt@kms_cursor_crc@pipe-a-cursor-suspend:
    - shard-kbl:          [DMESG-WARN][73] ([i915#180]) -> [PASS][74] +3 similar issues
   [73]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-kbl4/igt@kms_cursor_crc@pipe-a-cursor-suspend.html
   [74]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-kbl3/igt@kms_cursor_crc@pipe-a-cursor-suspend.html

  * igt@kms_draw_crc@draw-method-xrgb8888-mmap-gtt-ytiled:
    - shard-tglb:         [DMESG-FAIL][75] ([i915#402]) -> [PASS][76] +1 similar issue
   [75]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-tglb1/igt@kms_draw_crc@draw-method-xrgb8888-mmap-gtt-ytiled.html
   [76]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-tglb7/igt@kms_draw_crc@draw-method-xrgb8888-mmap-gtt-ytiled.html

  * igt@kms_plane_alpha_blend@pipe-a-alpha-opaque-fb:
    - shard-tglb:         [FAIL][77] ([i915#1184]) -> [PASS][78]
   [77]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-tglb1/igt@kms_plane_alpha_blend@pipe-a-alpha-opaque-fb.html
   [78]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-tglb2/igt@kms_plane_alpha_blend@pipe-a-alpha-opaque-fb.html

  * igt@kms_psr@psr2_primary_mmap_cpu:
    - shard-iclb:         [SKIP][79] ([fdo#109441]) -> [PASS][80] +2 similar issues
   [79]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-iclb4/igt@kms_psr@psr2_primary_mmap_cpu.html
   [80]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-iclb2/igt@kms_psr@psr2_primary_mmap_cpu.html

  * igt@kms_rotation_crc@multiplane-rotation-cropping-top:
    - shard-tglb:         [FAIL][81] ([i915#199]) -> [PASS][82]
   [81]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-tglb7/igt@kms_rotation_crc@multiplane-rotation-cropping-top.html
   [82]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-tglb7/igt@kms_rotation_crc@multiplane-rotation-cropping-top.html

  * igt@kms_vblank@pipe-b-ts-continuation-dpms-suspend:
    - shard-kbl:          [INCOMPLETE][83] ([fdo#103665]) -> [PASS][84]
   [83]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-kbl6/igt@kms_vblank@pipe-b-ts-continuation-dpms-suspend.html
   [84]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-kbl7/igt@kms_vblank@pipe-b-ts-continuation-dpms-suspend.html

  * igt@perf_pmu@busy-vcs1:
    - shard-iclb:         [SKIP][85] ([fdo#112080]) -> [PASS][86] +11 similar issues
   [85]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-iclb8/igt@perf_pmu@busy-vcs1.html
   [86]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-iclb1/igt@perf_pmu@busy-vcs1.html

  * igt@prime_mmap_coherency@ioctl-errors:
    - shard-hsw:          [FAIL][87] ([i915#831]) -> [PASS][88]
   [87]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-hsw7/igt@prime_mmap_coherency@ioctl-errors.html
   [88]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-hsw6/igt@prime_mmap_coherency@ioctl-errors.html

  * igt@prime_vgem@sync-blt:
    - shard-tglb:         [INCOMPLETE][89] ([i915#409]) -> [PASS][90]
   [89]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-tglb1/igt@prime_vgem@sync-blt.html
   [90]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-tglb3/igt@prime_vgem@sync-blt.html

  
#### Warnings ####

  * igt@gem_ctx_isolation@vcs1-nonpriv:
    - shard-iclb:         [FAIL][91] ([IGT#28]) -> [SKIP][92] ([fdo#112080])
   [91]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-iclb4/igt@gem_ctx_isolation@vcs1-nonpriv.html
   [92]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-iclb5/igt@gem_ctx_isolation@vcs1-nonpriv.html

  * igt@gem_ctx_isolation@vcs1-nonpriv-switch:
    - shard-iclb:         [SKIP][93] ([fdo#112080]) -> [FAIL][94] ([IGT#28])
   [93]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-iclb5/igt@gem_ctx_isolation@vcs1-nonpriv-switch.html
   [94]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-iclb4/igt@gem_ctx_isolation@vcs1-nonpriv-switch.html

  * igt@gem_tiled_blits@normal:
    - shard-hsw:          [FAIL][95] ([i915#818]) -> [FAIL][96] ([i915#694])
   [95]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-hsw7/igt@gem_tiled_blits@normal.html
   [96]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-hsw5/igt@gem_tiled_blits@normal.html

  * igt@i915_pm_rpm@sysfs-read:
    - shard-snb:          [INCOMPLETE][97] ([i915#82]) -> [SKIP][98] ([fdo#109271])
   [97]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-snb6/igt@i915_pm_rpm@sysfs-read.html
   [98]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-snb5/igt@i915_pm_rpm@sysfs-read.html

  * igt@kms_dp_dsc@basic-dsc-enable-edp:
    - shard-iclb:         [DMESG-WARN][99] ([i915#1226]) -> [SKIP][100] ([fdo#109349])
   [99]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7922/shard-iclb2/igt@kms_dp_dsc@basic-dsc-enable-edp.html
   [100]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/shard-iclb7/igt@kms_dp_dsc@basic-dsc-enable-edp.html

  
  [IGT#28]: https://gitlab.freedesktop.org/drm/igt-gpu-tools/issues/28
  [fdo#103665]: https://bugs.freedesktop.org/show_bug.cgi?id=103665
  [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
  [fdo#109276]: https://bugs.freedesktop.org/show_bug.cgi?id=109276
  [fdo#109349]: https://bugs.freedesktop.org/show_bug.cgi?id=109349
  [fdo#109441]: https://bugs.freedesktop.org/show_bug.cgi?id=109441
  [fdo#110841]: https://bugs.freedesktop.org/show_bug.cgi?id=110841
  [fdo#111703]: https://bugs.freedesktop.org/show_bug.cgi?id=111703
  [fdo#111870]: https://bugs.freedesktop.org/show_bug.cgi?id=111870
  [fdo#112080]: https://bugs.freedesktop.org/show_bug.cgi?id=112080
  [fdo#112146]: https://bugs.freedesktop.org/show_bug.cgi?id=112146
  [fdo#112271]: https://bugs.freedesktop.org/show_bug.cgi?id=112271
  [i915#1085]: https://gitlab.freedesktop.org/drm/intel/issues/1085
  [i915#1172]: https://gitlab.freedesktop.org/drm/intel/issues/1172
  [i915#118]: https://gitlab.freedesktop.org/drm/intel/issues/118
  [i915#1184]: https://gitlab.freedesktop.org/drm/intel/issues/1184
  [i915#1226]: https://gitlab.freedesktop.org/drm/intel/issues/1226
  [i915#128]: https://gitlab.freedesktop.org/drm/intel/issues/128
  [i915#180]: https://gitlab.freedesktop.org/drm/intel/issues/180
  [i915#199]: https://gitlab.freedesktop.org/drm/intel/issues/199
  [i915#31]: https://gitlab.freedesktop.org/drm/intel/issues/31
  [i915#402]: https://gitlab.freedesktop.org/drm/intel/issues/402
  [i915#409]: https://gitlab.freedesktop.org/drm/intel/issues/409
  [i915#413]: https://gitlab.freedesktop.org/drm/intel/issues/413
  [i915#44]: https://gitlab.freedesktop.org/drm/intel/issues/44
  [i915#447]: https://gitlab.freedesktop.org/drm/intel/issues/447
  [i915#454]: https://gitlab.freedesktop.org/drm/intel/issues/454
  [i915#478]: https://gitlab.freedesktop.org/drm/intel/issues/478
  [i915#49]: https://gitlab.freedesktop.org/drm/intel/issues/49
  [i915#644]: https://gitlab.freedesktop.org/drm/intel/issues/644
  [i915#668]: https://gitlab.freedesktop.org/drm/intel/issues/668
  [i915#677]: https://gitlab.freedesktop.org/drm/intel/issues/677
  [i915#694]: https://gitlab.freedesktop.org/drm/intel/issues/694
  [i915#778]: https://gitlab.freedesktop.org/drm/intel/issues/778
  [i915#818]: https://gitlab.freedesktop.org/drm/intel/issues/818
  [i915#82]: https://gitlab.freedesktop.org/drm/intel/issues/82
  [i915#831]: https://gitlab.freedesktop.org/drm/intel/issues/831
  [i915#899]: https://gitlab.freedesktop.org/drm/intel/issues/899
  [i915#95]: https://gitlab.freedesktop.org/drm/intel/issues/95


Participating hosts (10 -> 8)
------------------------------

  Missing    (2): pig-skl-6260u pig-glk-j5005 


Build changes
-------------

  * CI: CI-20190529 -> None
  * IGT: IGT_5436 -> IGTPW_4137
  * Piglit: piglit_4509 -> None

  CI-20190529: 20190529
  CI_DRM_7922: 0367f4b85f1fbbb1f0df1064803c97d35ed53f24 @ git://anongit.freedesktop.org/gfx-ci/linux
  IGTPW_4137: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/index.html
  IGT_5436: 00a64098aaae2ac3154841d76c7b034165380282 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools
  piglit_4509: fdc5a4ca11124ab8413c7988896eec4c97336694 @ git://anongit.freedesktop.org/piglit

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4137/index.html
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [igt-dev] [PATCH i-g-t 7/9] lib/chamelium: Make it clear that function asserts
  2020-02-14 12:19   ` Petri Latvala
@ 2020-02-17 13:45     ` Arkadiusz Hiler
  2020-02-17 14:00       ` Petri Latvala
  0 siblings, 1 reply; 29+ messages in thread
From: Arkadiusz Hiler @ 2020-02-17 13:45 UTC (permalink / raw)
  To: Petri Latvala; +Cc: igt-dev

On Fri, Feb 14, 2020 at 02:19:58PM +0200, Petri Latvala wrote:
> On Wed, Feb 12, 2020 at 03:23:13PM +0200, Arkadiusz Hiler wrote:
> > chamelium_wait_reachable() is asserting internally if the chamelium not
> > reachable. Let's make it return bool instead and create
> > void chamelium_assert_reachable() that fails the run.
> > 
> > Signed-off-by: Arkadiusz Hiler <arkadiusz.hiler@intel.com>
> 
> Reviewed-by: Petri Latvala <petri.latvala@intel.com>
> 
> Aside, Chamelium stuff is documented in a .txt but are there docs for
> the lib/igt_chamelium functions anywhere?

https://drm.pages.freedesktop.org/igt-gpu-tools/igt-gpu-tools-Chamelium.html ?
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [igt-dev] [PATCH i-g-t 7/9] lib/chamelium: Make it clear that function asserts
  2020-02-17 13:45     ` Arkadiusz Hiler
@ 2020-02-17 14:00       ` Petri Latvala
  2020-02-17 14:11         ` Arkadiusz Hiler
  0 siblings, 1 reply; 29+ messages in thread
From: Petri Latvala @ 2020-02-17 14:00 UTC (permalink / raw)
  To: Arkadiusz Hiler; +Cc: igt-dev

On Mon, Feb 17, 2020 at 03:45:04PM +0200, Arkadiusz Hiler wrote:
> On Fri, Feb 14, 2020 at 02:19:58PM +0200, Petri Latvala wrote:
> > On Wed, Feb 12, 2020 at 03:23:13PM +0200, Arkadiusz Hiler wrote:
> > > chamelium_wait_reachable() is asserting internally if the chamelium not
> > > reachable. Let's make it return bool instead and create
> > > void chamelium_assert_reachable() that fails the run.
> > > 
> > > Signed-off-by: Arkadiusz Hiler <arkadiusz.hiler@intel.com>
> > 
> > Reviewed-by: Petri Latvala <petri.latvala@intel.com>
> > 
> > Aside, Chamelium stuff is documented in a .txt but are there docs for
> > the lib/igt_chamelium functions anywhere?
> 
> https://drm.pages.freedesktop.org/igt-gpu-tools/igt-gpu-tools-Chamelium.html ?

/me blind

I got confuz by the patch context not having documentation comments
visible. And speaking of, docs for chamelium_wait_reachable pls?



-- 
Petri Latvala
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [igt-dev] [PATCH i-g-t 7/9] lib/chamelium: Make it clear that function asserts
  2020-02-17 14:00       ` Petri Latvala
@ 2020-02-17 14:11         ` Arkadiusz Hiler
  2020-02-17 14:13           ` Petri Latvala
  0 siblings, 1 reply; 29+ messages in thread
From: Arkadiusz Hiler @ 2020-02-17 14:11 UTC (permalink / raw)
  To: Petri Latvala; +Cc: igt-dev

On Mon, Feb 17, 2020 at 04:00:48PM +0200, Petri Latvala wrote:
> On Mon, Feb 17, 2020 at 03:45:04PM +0200, Arkadiusz Hiler wrote:
> > On Fri, Feb 14, 2020 at 02:19:58PM +0200, Petri Latvala wrote:
> > > On Wed, Feb 12, 2020 at 03:23:13PM +0200, Arkadiusz Hiler wrote:
> > > > chamelium_wait_reachable() is asserting internally if the chamelium not
> > > > reachable. Let's make it return bool instead and create
> > > > void chamelium_assert_reachable() that fails the run.
> > > > 
> > > > Signed-off-by: Arkadiusz Hiler <arkadiusz.hiler@intel.com>
> > > 
> > > Reviewed-by: Petri Latvala <petri.latvala@intel.com>
> > > 
> > > Aside, Chamelium stuff is documented in a .txt but are there docs for
> > > the lib/igt_chamelium functions anywhere?
> > 
> > https://drm.pages.freedesktop.org/igt-gpu-tools/igt-gpu-tools-Chamelium.html ?
> 
> /me blind
> 
> I got confuz by the patch context not having documentation comments
> visible. And speaking of, docs for chamelium_wait_reachable pls?

↓↓↓ bueno enough?

diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
index 5f9f777c..28706012 100644
--- a/lib/igt_chamelium.c
+++ b/lib/igt_chamelium.c
@@ -374,12 +374,26 @@ static bool __chamelium_is_reachable(struct chamelium *chamelium)
 	return true;
 }
 
+/**
+ * chamelium_wait_reachable:
+ * @chamelium: The Chamelium instance to use
+ * @timeout: Time (in seconds) to wait for chamelium to be reachable
+ *
+ * Returns: %true if the Chamelium is reachable, %false otherwise.
+ */
 bool chamelium_wait_reachable(struct chamelium *chamelium, int timeout)
 {
 	return igt_wait(__chamelium_is_reachable(chamelium),
 			timeout * 1000, 100);
 }
 
+/**
+ * chamelium_assert_reachable:
+ * @chamelium: The Chamelium instance to use
+ * @timeout: Time (in seconds) to wait for chamelium to be reachable
+ *
+ * Asserts that the chamelium is reachable.
+ */
 void chamelium_assert_reachable(struct chamelium *chamelium, int timeout)
 {
 	bool chamelium_online = chamelium_wait_reachable(chamelium, timeout);
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* Re: [igt-dev] [PATCH i-g-t 7/9] lib/chamelium: Make it clear that function asserts
  2020-02-17 14:11         ` Arkadiusz Hiler
@ 2020-02-17 14:13           ` Petri Latvala
  0 siblings, 0 replies; 29+ messages in thread
From: Petri Latvala @ 2020-02-17 14:13 UTC (permalink / raw)
  To: Arkadiusz Hiler; +Cc: igt-dev

On Mon, Feb 17, 2020 at 04:11:01PM +0200, Arkadiusz Hiler wrote:
> On Mon, Feb 17, 2020 at 04:00:48PM +0200, Petri Latvala wrote:
> > On Mon, Feb 17, 2020 at 03:45:04PM +0200, Arkadiusz Hiler wrote:
> > > On Fri, Feb 14, 2020 at 02:19:58PM +0200, Petri Latvala wrote:
> > > > On Wed, Feb 12, 2020 at 03:23:13PM +0200, Arkadiusz Hiler wrote:
> > > > > chamelium_wait_reachable() is asserting internally if the chamelium not
> > > > > reachable. Let's make it return bool instead and create
> > > > > void chamelium_assert_reachable() that fails the run.
> > > > > 
> > > > > Signed-off-by: Arkadiusz Hiler <arkadiusz.hiler@intel.com>
> > > > 
> > > > Reviewed-by: Petri Latvala <petri.latvala@intel.com>
> > > > 
> > > > Aside, Chamelium stuff is documented in a .txt but are there docs for
> > > > the lib/igt_chamelium functions anywhere?
> > > 
> > > https://drm.pages.freedesktop.org/igt-gpu-tools/igt-gpu-tools-Chamelium.html ?
> > 
> > /me blind
> > 
> > I got confuz by the patch context not having documentation comments
> > visible. And speaking of, docs for chamelium_wait_reachable pls?
> 
> ↓↓↓ bueno enough?

Good, good. R-b stands if you squash this in.


-- 
Petri Latvala
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [igt-dev] [PATCH i-g-t 9/9] lib/kms: Try to plug all Chamelium ports, abort if it fails
  2020-02-25 16:52 [igt-dev] [PATCH i-g-t 1/9] lib/tests: Extract fork helpers Arkadiusz Hiler
@ 2020-02-25 16:57 ` Arkadiusz Hiler
  0 siblings, 0 replies; 29+ messages in thread
From: Arkadiusz Hiler @ 2020-02-25 16:57 UTC (permalink / raw)
  To: igt-dev; +Cc: Petri Latvala

Using chamelium as a display for non-chamelium-aware test is
challenging. The board can be left in multiple different states after
kms_chamelium tests even though we have atexit() handlers and other
measures which try to assure that all ports are plugged in. Sadly this
is not 100% reliable. We also had a few boards hard hanging (happens
very seldom) and requiring manual intervention.

This leads to changes in the testing configuration - we may end up with
any number of connectors plugged in which makes a lot of kms_ tests to
flip between skip and pass depending on a run.

In an attempt to make connectors state less random this patch makes
igt_display_require() chamelium-aware. If chamelium is configured for
given machine we try to reach it and make sure everything is plugged in.
If we fail to do so we abort the execution because the testing
configuration is an unknown.

For machines without a configured chamelium this boils down to a nop.

I have run a bunch of tests and measured how much time we spend in the
Chamelium section of igt_display_require() (n = 1000) with chamelium
configured:

    Min: 0.0030s     Max:    0.0113s
    Avg: 0.0089s     Median: 0.0089s

With ~1000 of KMS subtests in a run it's only a mere 9s.

This will however add a bit of extra execution time to test skips
because of doing kmstest_set_vt_graphics_mode() and
igt_display_require() before even checking whether Chamelium is
configured.

v2: do kmstest_set_vt_graphics_mode() before requiring display (Petri)

Fixes: https://gitlab.freedesktop.org/drm/igt-gpu-tools/issues/20
Signed-off-by: Arkadiusz Hiler <arkadiusz.hiler@intel.com>
Reviewed-by: Petri Latvala <petri.latvala@intel.com>
---
 lib/igt_chamelium.c         | 55 +++++++++++++++++++++++++++++++++++--
 lib/igt_chamelium.h         |  1 +
 lib/igt_kms.c               | 18 ++++++++++++
 tests/kms_chamelium.c       | 13 +++++----
 tests/kms_color_chamelium.c |  7 +++--
 5 files changed, 83 insertions(+), 11 deletions(-)

diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
index 874e161b..3c9faeeb 100644
--- a/lib/igt_chamelium.c
+++ b/lib/igt_chamelium.c
@@ -1992,7 +1992,13 @@ static size_t chamelium_get_video_ports(struct chamelium *chamelium,
 	int res_len, i, port_id;
 	size_t port_ids_len = 0;
 
-	res = chamelium_rpc(chamelium, NULL, "GetSupportedInputs", "()");
+	res = __chamelium_rpc(chamelium, NULL, "GetSupportedInputs", "()");
+	if (chamelium->env.fault_occurred) {
+		igt_debug("Chamelium RPC call failed: %s\n",
+		     chamelium->env.fault_string);
+
+		return -1;
+	}
 	res_len = xmlrpc_array_size(&chamelium->env, res);
 	for (i = 0; i < res_len; i++) {
 		xmlrpc_array_read_item(&chamelium->env, res, i, &res_port);
@@ -2195,6 +2201,8 @@ static bool chamelium_autodiscover(struct chamelium *chamelium, int drm_fd)
 	candidate_ports_len = chamelium_get_video_ports(chamelium,
 							candidate_ports);
 
+	igt_assert(candidate_ports_len > 0);
+
 	igt_debug("Starting Chamelium port auto-discovery on %zu ports\n",
 		  candidate_ports_len);
 	igt_gettime(&start);
@@ -2313,14 +2321,14 @@ static bool chamelium_read_config(struct chamelium *chamelium)
 	GError *error = NULL;
 
 	if (!igt_key_file) {
-		igt_warn("No configuration file available for chamelium\n");
+		igt_debug("No configuration file available for chamelium\n");
 		return false;
 	}
 
 	chamelium->url = g_key_file_get_string(igt_key_file, "Chamelium", "URL",
 					       &error);
 	if (!chamelium->url) {
-		igt_warn("Couldn't read chamelium URL from config file: %s\n",
+		igt_debug("Couldn't read chamelium URL from config file: %s\n",
 			 error->message);
 		return false;
 	}
@@ -2416,6 +2424,9 @@ error:
  * Chamelium configuration. This must be called first before trying to use the
  * chamelium.
  *
+ * Needs to happen *after* igt_display_require() as otherwise the board will
+ * get reset.
+ *
  * If we fail to establish a connection with the chamelium, fail to find a
  * configured connector, etc. we fail the current test.
  *
@@ -2495,6 +2506,44 @@ void chamelium_deinit(struct chamelium *chamelium)
 	free(chamelium);
 }
 
+bool chamelium_plug_all(struct chamelium *chamelium)
+{
+	size_t port_count;
+	int port_ids[CHAMELIUM_MAX_PORTS];
+	xmlrpc_value *v;
+	v = __chamelium_rpc(chamelium, NULL, "Reset", "()");
+
+	if (v != NULL)
+		xmlrpc_DECREF(v);
+
+	if (chamelium->env.fault_occurred) {
+		igt_debug("Chamelium RPC call failed: %s\n",
+		     chamelium->env.fault_string);
+
+		return false;
+	}
+
+	port_count = chamelium_get_video_ports(chamelium, port_ids);
+	if (port_count <= 0)
+		return false;
+
+	for (int i = 0; i < port_count; ++i) {
+		v = __chamelium_rpc(chamelium, NULL, "Plug", "(i)", port_ids[i]);
+
+		if (v != NULL)
+			xmlrpc_DECREF(v);
+
+		if (chamelium->env.fault_occurred) {
+			igt_debug("Chamelium RPC call failed: %s\n",
+			     chamelium->env.fault_string);
+
+			return false;
+		}
+	}
+
+	return true;
+}
+
 igt_constructor {
 	/* Frame dumps can be large, so we need to be able to handle very large
 	 * responses
diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
index 3b9a1242..fb273b1a 100644
--- a/lib/igt_chamelium.h
+++ b/lib/igt_chamelium.h
@@ -217,5 +217,6 @@ void chamelium_crop_analog_frame(struct chamelium_frame_dump *dump, int width,
 void chamelium_destroy_frame_dump(struct chamelium_frame_dump *dump);
 void chamelium_destroy_audio_file(struct chamelium_audio_file *audio_file);
 void chamelium_infoframe_destroy(struct chamelium_infoframe *infoframe);
+bool chamelium_plug_all(struct chamelium *chamelium);
 
 #endif /* IGT_CHAMELIUM_H */
diff --git a/lib/igt_kms.c b/lib/igt_kms.c
index 54de45e5..7f9fafb3 100644
--- a/lib/igt_kms.c
+++ b/lib/igt_kms.c
@@ -58,6 +58,9 @@
 #include "igt_device.h"
 #include "igt_sysfs.h"
 #include "sw_sync.h"
+#ifdef HAVE_CHAMELIUM
+#include "igt_chamelium.h"
+#endif
 
 /**
  * SECTION:igt_kms
@@ -1886,6 +1889,21 @@ void igt_display_require(igt_display_t *display, int drm_fd)
 	if (!resources)
 		goto out;
 
+#ifdef HAVE_CHAMELIUM
+	{
+		struct chamelium *chamelium;
+
+		chamelium = chamelium_init_rpc_only();
+		if (chamelium) {
+			igt_abort_on_f(!chamelium_wait_reachable(chamelium, 20),
+				       "cannot reach the configured chamelium!\n");
+			igt_abort_on_f(!chamelium_plug_all(chamelium),
+				       "failed to plug all the chamelium ports!\n");
+			chamelium_deinit_rpc_only(chamelium);
+		}
+	}
+#endif
+
 	/*
 	 * We cache the number of pipes, that number is a physical limit of the
 	 * hardware and cannot change of time (for now, at least).
diff --git a/tests/kms_chamelium.c b/tests/kms_chamelium.c
index 8243d2ef..f127de8c 100644
--- a/tests/kms_chamelium.c
+++ b/tests/kms_chamelium.c
@@ -2622,7 +2622,14 @@ igt_main
 	size_t i;
 
 	igt_fixture {
+		/* So fbcon doesn't try to reprobe things itself */
+		kmstest_set_vt_graphics_mode();
+
 		data.drm_fd = drm_open_driver_master(DRIVER_ANY);
+		igt_display_require(&data.display, data.drm_fd);
+		igt_require(data.display.is_atomic);
+
+		/* we need to initalize chamelium after igt_display_require */
 		data.chamelium = chamelium_init(data.drm_fd);
 		igt_require(data.chamelium);
 
@@ -2633,12 +2640,6 @@ igt_main
 			data.edids[i] = chamelium_new_edid(data.chamelium,
 							   get_edid(i));
 		}
-
-		/* So fbcon doesn't try to reprobe things itself */
-		kmstest_set_vt_graphics_mode();
-
-		igt_display_require(&data.display, data.drm_fd);
-		igt_require(data.display.is_atomic);
 	}
 
 	igt_describe("DisplayPort tests");
diff --git a/tests/kms_color_chamelium.c b/tests/kms_color_chamelium.c
index 34a1888c..7f5a911c 100644
--- a/tests/kms_color_chamelium.c
+++ b/tests/kms_color_chamelium.c
@@ -724,6 +724,11 @@ igt_main
 		data.drm_fd = drm_open_driver_master(DRIVER_ANY);
 		if (is_i915_device(data.drm_fd))
 			data.devid = intel_get_drm_devid(data.drm_fd);
+
+		igt_display_require(&data.display, data.drm_fd);
+		igt_require(data.display.is_atomic);
+
+		/* we need to initalize chamelium after igt_display_require */
 		data.chamelium = chamelium_init(data.drm_fd);
 		igt_require(data.chamelium);
 
@@ -734,8 +739,6 @@ igt_main
 			igt_skip("No ports connected\n");
 
 		kmstest_set_vt_graphics_mode();
-		igt_display_require(&data.display, data.drm_fd);
-		igt_require(data.display.is_atomic);
 	}
 
 	for_each_pipe_static(pipe)
-- 
2.24.1

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply related	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2020-02-25 16:57 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-02-12 13:21 [igt-dev] [PATCH i-g-t 0/9] Abort on Chamelium failure Arkadiusz Hiler
2020-02-12 13:21 ` [igt-dev] [PATCH i-g-t 1/9] lib/tests: Extract fork helpers Arkadiusz Hiler
2020-02-14 11:57   ` Petri Latvala
2020-02-12 13:21 ` [igt-dev] [PATCH i-g-t 2/9] lib/tests: Add support for redirecting fork output to /dev/null Arkadiusz Hiler
2020-02-14 12:01   ` Petri Latvala
2020-02-12 13:21 ` [igt-dev] [PATCH i-g-t 3/9] lib: Make it possible to abort the whole execution from inside of a test Arkadiusz Hiler
2020-02-14 12:04   ` Petri Latvala
2020-02-12 13:21 ` [igt-dev] [PATCH i-g-t 4/9] runner/runner_tests: Extract helper for inspecting test result Arkadiusz Hiler
2020-02-12 13:37   ` Petri Latvala
2020-02-12 13:42     ` Petri Latvala
2020-02-12 13:59       ` Arkadiusz Hiler
2020-02-14 12:05   ` Petri Latvala
2020-02-12 13:22 ` [igt-dev] [PATCH i-g-t 5/9] runner: Abort the run when test exits with IGT_EXIT_ABORT Arkadiusz Hiler
2020-02-14 12:16   ` Petri Latvala
2020-02-12 13:22 ` [igt-dev] [PATCH i-g-t 6/9] lib/chamelium: Clear error after checking if chamelium is reachable Arkadiusz Hiler
2020-02-14 12:17   ` Petri Latvala
2020-02-12 13:23 ` [igt-dev] [PATCH i-g-t 7/9] lib/chamelium: Make it clear that function asserts Arkadiusz Hiler
2020-02-14 12:19   ` Petri Latvala
2020-02-17 13:45     ` Arkadiusz Hiler
2020-02-17 14:00       ` Petri Latvala
2020-02-17 14:11         ` Arkadiusz Hiler
2020-02-17 14:13           ` Petri Latvala
2020-02-12 13:23 ` [igt-dev] [PATCH i-g-t 8/9] lib/chamelium: Add functions to initialize XMLRPC only Arkadiusz Hiler
2020-02-14 12:22   ` Petri Latvala
2020-02-12 13:23 ` [igt-dev] [PATCH i-g-t 9/9] lib/kms: Try to plug all Chamelium ports, abort if it fails Arkadiusz Hiler
2020-02-14 12:27   ` Petri Latvala
2020-02-12 16:38 ` [igt-dev] ✓ Fi.CI.BAT: success for Abort on Chamelium failure Patchwork
2020-02-14 15:37 ` [igt-dev] ✗ Fi.CI.IGT: failure " Patchwork
2020-02-25 16:52 [igt-dev] [PATCH i-g-t 1/9] lib/tests: Extract fork helpers Arkadiusz Hiler
2020-02-25 16:57 ` [igt-dev] [PATCH i-g-t 9/9] lib/kms: Try to plug all Chamelium ports, abort if it fails Arkadiusz Hiler

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.