[yocto] [ptest-runner 6/8] Add <system-out></system-out> to XML when tests fail

Jiwei Sun jiwei.sun at windriver.com
Thu Sep 28 19:09:38 PDT 2017


* Introduce a maximum number of concurrent ptests, since
we are dealing with embedded targets.

* Add stdout || stderr output from ptests into XML.
For testcases running in parallel, cluttering stdout won't
help anyone.

Signed-off-by: Jiwei Sun <jiwei.sun at windriver.com>
---
 main.c                   |  2 +
 tests/data/reference.xml |  1 +
 tests/utils.c            |  4 +-
 utils.c                  | 99 +++++++++++++++++++++++++++++-------------------
 utils.h                  |  3 +-
 5 files changed, 67 insertions(+), 42 deletions(-)

diff --git a/main.c b/main.c
index d524200..a201e87 100644
--- a/main.c
+++ b/main.c
@@ -37,6 +37,7 @@
 
 #define DEFAULT_DIRECTORY "/usr/lib"
 #define DEFAULT_TIMEOUT 300
+#define DEFAULT_MAX_PARALLEL 64
 
 static inline void
 print_usage(FILE *stream, char *progname)
@@ -69,6 +70,7 @@ main(int argc, char *argv[])
 	opts.directory = strdup(DEFAULT_DIRECTORY);
 	opts.list = 0;
 	opts.timeout = DEFAULT_TIMEOUT;
+	opts.max_parallel = DEFAULT_MAX_PARALLEL;
 	opts.ptests = NULL;
 	opts.xml_filename = NULL;
 
diff --git a/tests/data/reference.xml b/tests/data/reference.xml
index 91522c7..a23b44b 100644
--- a/tests/data/reference.xml
+++ b/tests/data/reference.xml
@@ -4,5 +4,6 @@
 	</testcase>
 	<testcase classname='test2' name='run-ptest'>
 		<failure type='exit_code' message='run-ptest exited with code: 1'></failure>
+		<system-out>ERROR</system-out>
 	</testcase>
 </testsuite>
diff --git a/tests/utils.c b/tests/utils.c
index 9b1f442..bb799f4 100644
--- a/tests/utils.c
+++ b/tests/utils.c
@@ -262,9 +262,9 @@ START_TEST(test_xml_pass)
 	ck_assert(xp != NULL);
         entry.ptest = "test1";
         entry.run_ptest = "run-ptest";
-	xml_add_case(xp, 0, &entry);
+        xml_add_case(xp, 0, &entry, "");
         entry.ptest = "test2";
-        xml_add_case(xp, 1, &entry);
+        xml_add_case(xp, 1, &entry, "ERROR");
 	xml_finish(xp);
 
 	FILE *fp, *fr;
diff --git a/utils.c b/utils.c
index 056d7b7..0e97ac4 100644
--- a/utils.c
+++ b/utils.c
@@ -289,8 +289,13 @@ run_child(char *run_ptest, int fd_stdout, int fd_stderr)
 }
 
 static inline int
-wait_child(const char *ptest_dir, const char *run_ptest, pid_t pid,
-		int timeout, int *fds, FILE **fps)
+wait_child(const char *ptest_dir,
+	   const char *run_ptest,
+	   pid_t pid,
+	   int timeout,
+	   int *fds,
+	   FILE **fps,
+	   char *buf)
 {
 	struct pollfd pfds[2];
 	time_t sentinel;
@@ -311,7 +316,6 @@ wait_child(const char *ptest_dir, const char *run_ptest, pid_t pid,
 
 		r = poll(pfds, 2, WAIT_CHILD_POLL_TIMEOUT_MS);
 		if (r > 0) {
-			char buf[WAIT_CHILD_BUF_MAX_SIZE];
 			ssize_t n;
 
 			if (pfds[0].revents != 0) {
@@ -354,6 +358,35 @@ wait_child(const char *ptest_dir, const char *run_ptest, pid_t pid,
 	return status;
 }
 
+static void reap_all_children(FILE *fp) {
+	/* Reap all children before continuing */
+	while (1) {
+		int status;
+		pid_t pid;
+		pid = waitpid((pid_t)(-1), &status, WNOHANG);
+
+		/* Child reaped */
+		if (pid > 0) {
+			if (WIFEXITED(status)) {
+				if (WEXITSTATUS(status) == 0)
+					continue;
+			}
+			fprintf(fp, "One child failed to do its job pid:%u", pid);
+			exit(-1);
+		}
+
+		/* Still children alive */
+		if (pid == 0) {
+			usleep(100000); /* 100ms */
+			continue;
+		}
+
+		/* No more children to reap */
+		if (pid < 0)
+			break;
+	}
+}
+
 int
 run_ptests(struct ptest_list *head, const struct ptest_options opts,
 		const char *progname, FILE *fp, FILE *fp_stderr)
@@ -363,8 +396,8 @@ run_ptests(struct ptest_list *head, const struct ptest_options opts,
 
 	struct ptest_list *p;
 	char stime[GET_STIME_BUF_SIZE];
-
-	pid_t child, pid;
+	int nr_children = 0;
+	pid_t child;
 	int pipefd_stdout[2];
 	int pipefd_stderr[2];
 
@@ -395,8 +428,13 @@ run_ptests(struct ptest_list *head, const struct ptest_options opts,
 				continue;
 
 			master = fork();
-			if (master)
+			if (master) {
+				if (++nr_children >= opts.max_parallel) {
+					reap_all_children(fp);
+					nr_children = 0;
+				}
 				continue;
+			}
 
 		        ptest_dir = strdup(p->run_ptest);
 			if (ptest_dir == NULL) {
@@ -416,53 +454,30 @@ run_ptests(struct ptest_list *head, const struct ptest_options opts,
 				int status;
 				int fds[2]; fds[0] = pipefd_stdout[0]; fds[1] = pipefd_stderr[0];
 				FILE *fps[2]; fps[0] = fp; fps[1] = fp_stderr;
+				char buf[WAIT_CHILD_BUF_MAX_SIZE];
 
 //				fprintf(fp, "%s\n", get_stime(stime, GET_STIME_BUF_SIZE));
 				fprintf(fp, "BEGIN: %s\n", ptest_dir);
 
 				status = wait_child(ptest_dir, p->run_ptest, child,
-						opts.timeout, fds, fps);
+						    opts.timeout, fds, fps, buf);
 				if (status)
 					rc += 1;
 
 				if (opts.xml_filename)
 					xml_add_case(xh,
 						     status,
-						     (struct ptest_entry *)p);
+						     (struct ptest_entry *)p,
+						     buf);
 
-//				fprintf(fp, "END: %s\n", ptest_dir);
 //				fprintf(fp, "%s\n", get_stime(stime, GET_STIME_BUF_SIZE));
 				/* Let non-master gracefully terminate */
 				exit(0);
 			}
 		PTEST_LIST_ITERATE_END;
 
-		/* Reap all children before continuing */
-		while (1) {
-			int status;
-			pid = waitpid((pid_t)(-1), &status, WNOHANG);
-
-			/* Child reaped */
-			if (pid > 0) {
-				if (WIFEXITED(status)) {
-					if (WEXITSTATUS(status) == 0)
-						continue;
-				}
-				fprintf(fp, "One child failed to do its job pid:%u", pid);
-				exit(-1);
-			}
-
-			/* Still children alive */
-			if (pid == 0) {
-				usleep(100000); /* 100ms */
-				continue;
-			}
-
-			/* No more children to reap */
-			if (pid < 0)
-				break;
-		}
-
+		reap_all_children(fp);
+		
 		fprintf(fp, "START: %s\n", progname);
 		PTEST_LIST_ITERATE_START(head, p);
 		        char *ptest_dir;
@@ -487,19 +502,22 @@ run_ptests(struct ptest_list *head, const struct ptest_options opts,
 				int status;
 				int fds[2]; fds[0] = pipefd_stdout[0]; fds[1] = pipefd_stderr[0];
 				FILE *fps[2]; fps[0] = fp; fps[1] = fp_stderr;
+				char buf[WAIT_CHILD_BUF_MAX_SIZE];
 
+				memset(buf, 0, sizeof(buf));
 				fprintf(fp, "%s\n", get_stime(stime, GET_STIME_BUF_SIZE));
 				fprintf(fp, "BEGIN: %s\n", ptest_dir);
 
 				status = wait_child(ptest_dir, p->run_ptest, child,
-						opts.timeout, fds, fps);
+						    opts.timeout, fds, fps, buf);
 				if (status)
 					rc += 1;
 
 				if (opts.xml_filename)
 					xml_add_case(xh,
 						     status,
-						     (struct ptest_entry *)p);
+						     (struct ptest_entry *)p,
+						     buf);
 
 				fprintf(fp, "END: %s\n", ptest_dir);
 				fprintf(fp, "%s\n", get_stime(stime, GET_STIME_BUF_SIZE));
@@ -538,7 +556,7 @@ xml_create(int test_count, char *xml_filename)
 }
 
 void
-xml_add_case(FILE *xh, int status, struct ptest_entry *ptest)
+xml_add_case(FILE *xh, int status, struct ptest_entry *ptest, char *buf)
 {
 	struct flock lock;
 	int fd;
@@ -556,10 +574,13 @@ xml_add_case(FILE *xh, int status, struct ptest_entry *ptest)
 			"\t\t<failure type='exit_code'" \
 			" message='run-ptest exited with code: %d'>" \
 			"</failure>\n" \
+			"\t\t<system-out>%s" \
+			"</system-out>\n" \
 			"\t</testcase>\n",
 			ptest->ptest,
 			basename(bname),
-			status);
+			status,
+			buf);
 	}
 	else {
 		fprintf(xh, "\t<testcase classname='%s' name='%s'>\n" \
diff --git a/utils.h b/utils.h
index d0ef735..70e2abe 100644
--- a/utils.h
+++ b/utils.h
@@ -34,6 +34,7 @@ struct ptest_options {
 	char *directory;
 	int list;
 	int timeout;
+	int max_parallel;
 	char **ptests;
 	char *xml_filename;
 };
@@ -47,7 +48,7 @@ extern int run_ptests(struct ptest_list *, const struct ptest_options,
 		const char *, FILE *, FILE *);
 
 extern FILE *xml_create(int, char *);
-extern void xml_add_case(FILE *, int, struct ptest_entry *);
+extern void xml_add_case(FILE *, int, struct ptest_entry *, char *);
 extern void xml_finish(FILE *);
 
 #endif
-- 
1.8.3.1




More information about the yocto mailing list