Skip to contentSkip to conversation

feat: generate xml-file

PATCH In review Pascal Bach 3 participants 4 messages Jan 19, 2017 – Jan 20, 2017

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 feat: generate xml-file

From: Christian Schuler <[email protected]>

add a feature that allows the user to generate an XUnit xml-file. This file shows if the ptests run correctly or not. e.g. bash, zlib. It doesn't list the underlaying tests of the package.
The feature is activated by console input -x <filepath>. Unit-tests of the feature are included.

---
 README.md     |  1 +
 main.c        | 15 +++++++++++----
 tests/utils.c | 46 +++++++++++++++++++++++++++++++++++++++++++--
 utils.c       | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 utils.h       |  7 ++++++-
 5 files changed, 121 insertions(+), 8 deletions(-)
README.md +1 -0
index ed7a589..fedab04 100644
@@ -14,6 +14,7 @@ Now the ptest-runner2 support the next features:
 - List available ptests.
 - Specify the timeout for avoid blocking indefinetly.
 - Only run certain ptests.
+- XML-ouput
 
 Proposed features:
 
main.c +11 -4
index 31bf3b5..8dfdad6 100644
@@ -41,7 +41,7 @@
 static inline void
 print_usage(FILE *stream, char *progname)
 {
-	fprintf(stream, "Usage: %s [-d directory] [-l list] [-t timeout] "
+	fprintf(stream, "Usage: %s [-d directory] [-l list] [-t timeout] [-x xml-filename]"
 			"[-h] [ptest1 ptest2 ...]\n", progname);
 }
 
@@ -50,6 +50,7 @@ static struct {
 	int list;
 	int timeout;
 	char **ptests;
+	char * xml_filename;
 } opts;
 
 int
@@ -70,8 +71,9 @@ main(int argc, char *argv[])
 	opts.list = 0;
 	opts.timeout = DEFAULT_TIMEOUT;
 	opts.ptests = NULL;
+	opts.xml_filename = NULL;
 
-	while ((opt = getopt(argc, argv, "d:lt:h")) != -1) {
+	while ((opt = getopt(argc, argv, "d:ltx:h")) != -1) {
 		switch (opt) {
 			case 'd':
 				free(opts.directory);
@@ -88,6 +90,11 @@ main(int argc, char *argv[])
 				print_usage(stdout, argv[0]);
 				exit(0);
 			break;
+			case 'x':
+				free(opts.xml_filename);
+				opts.xml_filename = strdup(optarg);
+				CHECK_ALLOCATION(opts.xml_filename, 1, 1);
+			break;
 			default:
 				print_usage(stdout, argv[0]);
 				exit(1);
@@ -131,9 +138,9 @@ main(int argc, char *argv[])
 		run = filter_ptests(head, opts.ptests, ptest_num);
 		CHECK_ALLOCATION(run, ptest_num, 1);
 		ptest_list_free_all(head);
-	} 
+	}
 
-	rc = run_ptests(run, opts.timeout, argv[0], stdout, stderr);
+	rc = run_ptests(run, opts.timeout, argv[0], stdout, stderr, opts.xml_filename);
 
 	ptest_list_free_all(run);
 
tests/utils.c +44 -2

70 lines not on this page · raw message

utils.c +59 -1

85 lines not on this page · raw message

utils.h +6 -1
index 4dc23ef..99f6100 100644
@@ -30,10 +30,15 @@
 #define CHECK_ALLOCATION(p, size, exit_on_null) \
 	check_allocation1(p, size, __FILE__, __LINE__, exit_on_null)
 
+typedef FILE XML;
+
 extern void check_allocation1(void *, size_t, char *, int, int);
 extern struct ptest_list *get_available_ptests(const char *);
 extern int print_ptests(struct ptest_list *, FILE *);
 extern struct ptest_list *filter_ptests(struct ptest_list *, char **, int);
-extern int run_ptests(struct ptest_list *, int, const char *progname, FILE *, FILE *);
+extern int run_ptests(struct ptest_list *, int, const char *progname, FILE *, FILE *, char *xml_filename);
+extern XML * xml_create(int test_count, char *filename);
+extern void xml_add_case(XML *, int status, const char *ptest_dir);
+extern void xml_finish(XML *);
 
 #endif
Signature · 1 line
2.1.4
#1 lore raw

Hi Pascal and Christian,

Your patch looks good at first look, only a few comments about the code inline.

We are trying to standardize the results output format across our testing components in order to build up-on a Test reporting tool, so let us review the XML format.

Benjamin do you have a wiki page link with test result format information?

Cheers,
alimon

Quoted 75 lines · Pascal Bach

From: Christian Schuler <[email protected]>

add a feature that allows the user to generate an XUnit xml-file. This file shows if the ptests run correctly or not. e.g. bash, zlib. It doesn't list the underlaying tests of the package.
The feature is activated by console input -x <filepath>. Unit-tests of the feature are included.

---
 README.md     |  1 +
 main.c        | 15 +++++++++++----
 tests/utils.c | 46 +++++++++++++++++++++++++++++++++++++++++++--
 utils.c       | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 utils.h       |  7 ++++++-
 5 files changed, 121 insertions(+), 8 deletions(-)
README.md +1 -0
index ed7a589..fedab04 100644
@@ -14,6 +14,7 @@ Now the ptest-runner2 support the next features:
 - List available ptests.
 - Specify the timeout for avoid blocking indefinetly.
 - Only run certain ptests.
+- XML-ouput
 
 Proposed features:
 
main.c +9 -2
index 31bf3b5..8dfdad6 100644
@@ -41,7 +41,7 @@
 static inline void
 print_usage(FILE *stream, char *progname)
 {
-	fprintf(stream, "Usage: %s [-d directory] [-l list] [-t timeout] "
+	fprintf(stream, "Usage: %s [-d directory] [-l list] [-t timeout] [-x xml-filename]"
 			"[-h] [ptest1 ptest2 ...]\n", progname);
 }
 
@@ -50,6 +50,7 @@ static struct {
 	int list;
 	int timeout;
 	char **ptests;
+	char * xml_filename;
 } opts;
 
 int
@@ -70,8 +71,9 @@ main(int argc, char *argv[])
 	opts.list = 0;
 	opts.timeout = DEFAULT_TIMEOUT;
 	opts.ptests = NULL;
+	opts.xml_filename = NULL;
 
-	while ((opt = getopt(argc, argv, "d:lt:h")) != -1) {
+	while ((opt = getopt(argc, argv, "d:ltx:h")) != -1) {
 		switch (opt) {
 			case 'd':
 				free(opts.directory);
@@ -88,6 +90,11 @@ main(int argc, char *argv[])
 				print_usage(stdout, argv[0]);
 				exit(0);
 			break;
+			case 'x':
+				free(opts.xml_filename);
+				opts.xml_filename = strdup(optarg);
+				CHECK_ALLOCATION(opts.xml_filename, 1, 1);
+			break;
 			default:
 				print_usage(stdout, argv[0]);
 				exit(1);

main.c main(int argc, char *argv[]) · line 143

Quoted 8 lines
main.c +2 -2
@@ -131,9 +138,9 @@ main(int argc, char *argv[])
 		run = filter_ptests(head, opts.ptests, ptest_num);
 		CHECK_ALLOCATION(run, ptest_num, 1);
 		ptest_list_free_all(head);
-	} 
+	}
 
-	rc = run_ptests(run, opts.timeout, argv[0], stdout, stderr);
+	rc = run_ptests(run, opts.timeout, argv[0], stdout, stderr, opts.xml_filename);

Will be a good idea modify the run_ptest signature to pass the whole options to it.

I mean:

run_ptests(run, opts, argv[0], stdout, stderr)

If you could do a first patch with this change and then add your functionality realted to xml_filename will be good.

Quoted 183 lines
main.c +0 -0
 	ptest_list_free_all(run);
 
tests/utils.c +44 -2
index 1332798..dd869e9 100644
@@ -173,7 +173,7 @@ START_TEST(test_run_ptests)
 	ptest_list_remove(head, "hang", 1);
 	ptest_list_remove(head, "fail", 1);
 
-	rc = run_ptests(head, timeout, "test_run_ptests", fp_stdout, fp_stderr);
+	rc = run_ptests(head, timeout, "test_run_ptests", fp_stdout, fp_stderr, NULL);
 	ck_assert(rc == 0);
 	ptest_list_free_all(head);
 
@@ -234,6 +234,46 @@ START_TEST(test_run_fail_ptest)
 	ptest_list_free_all(head);
 END_TEST
 
+START_TEST(test_xml_pass)
+	char ref[] = "<?xml version='1.0' encoding='UTF-8'?>\n<testsuite name='ptests' tests='2'>\n"
+			"<testcase name='.'>\n<nodes expected='/' result='/'>\n"
+			"<nodes expected='0' result='0'>\n"
+			"</nodes>\n"
+			"</nodes>\n"
+			"</testcase>\n"
+			"<testcase name='.'>\n"
+			"<nodes expected='/' result='/'>\n"
+			"<nodes expected='0' result='1'>\n"
+			"<error type='Timeout/Unexpected error'>\n"
+			"A Timeout has occured or more tests than expected failed.\n"
+			"</error>\n"
+			"</nodes>\n"
+			"</nodes>\n"
+			"</testcase>\n"
+			"</testsuite>";
+	char buffer[strlen(ref)];
+
+	FILE *fp;
+	fp = xml_create(2, "./test_xml");
+	xml_add_case(fp, 0,".");
+	xml_add_case(fp, 1,".");
+	xml_finish(fp);
+
+	fp = fopen("./test_xml", "a+");
+	fseek(fp, 0, SEEK_SET);
+
+	fread(buffer, strlen(ref), 1, fp);
+	ck_assert(strncmp(ref, buffer, strlen(ref)) == 0);
+	fclose(fp);
+	unlink("./test_xml");
+
+END_TEST
+
+START_TEST(test_xml_fail)
+	ck_assert(xml_create(2, "./") == NULL);
+
+END_TEST
+
 Suite *
 utils_suite()
 {
@@ -249,6 +289,8 @@ utils_suite()
 	tcase_add_test(tc_core, test_run_ptests);
 	tcase_add_test(tc_core, test_run_timeout_ptest);
 	tcase_add_test(tc_core, test_run_fail_ptest);
+	tcase_add_test(tc_core, test_xml_pass);
+	tcase_add_test(tc_core, test_xml_fail);
 
 	suite_add_tcase(s, tc_core);
 
@@ -276,7 +318,7 @@ test_ptest_expected_failure(struct ptest_list *head, const int timeout, char *pr
 		ck_assert(ptest_list_length(filtered) == 1);
 
 		h_analizer(
-			run_ptests(filtered, timeout, progname, fp_stdout, fp_stderr),
+			run_ptests(filtered, timeout, progname, fp_stdout, fp_stderr, NULL),
 			fp_stdout, fp_stderr
 		);
 
utils.c +59 -1
index 77427e0..430fb7a 100644
@@ -303,9 +303,10 @@ wait_child(const char *ptest_dir, const char *run_ptest, pid_t pid,
 
 int
 run_ptests(struct ptest_list *head, int timeout, const char *progname,
-		FILE *fp, FILE *fp_stderr)
+		FILE *fp, FILE *fp_stderr, char *xml_filename)
 {
 	int rc = 0;
+	XML *xh;
 
 	struct ptest_list *p;
 	char stime[GET_STIME_BUF_SIZE];
@@ -314,6 +315,12 @@ run_ptests(struct ptest_list *head, int timeout, const char *progname,
 	int pipefd_stdout[2];
 	int pipefd_stderr[2];
 
+	if(xml_filename) {
+		xh = xml_create(ptest_list_length(head), xml_filename);
+		if(!xh)
+			exit(EXIT_FAILURE);
+	}
+
 	do
 	{
 		if ((rc = pipe2(pipefd_stdout, O_NONBLOCK)) == -1) 
@@ -355,6 +362,9 @@ run_ptests(struct ptest_list *head, int timeout, const char *progname,
 					fprintf(fp, "ERROR: Exit status is %d\n", status);
 					rc += 1;
 				}
+				if (xml_filename)
+					xml_add_case(xh, status, ptest_dir);
+        
 				fprintf(fp, "END: %s\n", ptest_dir);
 				fprintf(fp, "%s\n", get_stime(stime, GET_STIME_BUF_SIZE));
 			}
@@ -368,5 +378,53 @@ run_ptests(struct ptest_list *head, int timeout, const char *progname,
 	if (rc == -1) 
 		fprintf(fp_stderr, "run_ptests fails: %s", strerror(errno));
 
+	if (xml_filename)
+		xml_finish(xh);
+
 	return rc;
 }
+
+FILE *
+xml_create(int test_count, char *xml_filename)
+{
+	FILE *xh;
+
+	if ((xh = fopen(xml_filename, "w"))) {
+		fprintf(xh, "<?xml version='1.0' encoding='UTF-8'?>\n");
+		fprintf(xh, "<testsuite name='ptests' tests='%d'>\n", test_count);
+	}
+	else {
+		fprintf(stderr, "File could not be created. Make sure the path is correct and you have the right permissions.");
+		return NULL;
+	}
+
+	return xh;
+}
+
+void
+xml_add_case(FILE *xh, int status, const char *ptest_dir)
+{
+	fprintf(xh, "<testcase name='%s'>\n", ptest_dir);
+	fprintf(xh, "<nodes expected='/' result='/'>\n");
+
+	if(status == 0){
+		fprintf(xh, "<nodes expected='0' result='0'>\n");
+		fprintf(xh, "</nodes>\n");
+	}
+	else{
+		fprintf(xh, "<nodes expected='0' result='%d'>\n", status);
+		fprintf(xh, "<error type='Timeout/Unexpected error'>\n");
+		fprintf(xh, "A Timeout has occured or more tests than expected failed.\n");
+		fprintf(xh, "</error>\n");
+		fprintf(xh, "</nodes>\n");
+	}
+	fprintf(xh, "</nodes>\n");
+	fprintf(xh, "</testcase>\n");
+}
+
+void
+xml_finish(FILE *xh)
+{
+	fprintf(xh, "</testsuite>");
+	fclose(xh);
+}
utils.h +1 -0
index 4dc23ef..99f6100 100644
@@ -30,10 +30,15 @@
 #define CHECK_ALLOCATION(p, size, exit_on_null) \
 	check_allocation1(p, size, __FILE__, __LINE__, exit_on_null)
 
+typedef FILE XML;

utils.h line 42

Quoted 10 lines
utils.h +5 -1
+
 extern void check_allocation1(void *, size_t, char *, int, int);
 extern struct ptest_list *get_available_ptests(const char *);
 extern int print_ptests(struct ptest_list *, FILE *);
 extern struct ptest_list *filter_ptests(struct ptest_list *, char **, int);
-extern int run_ptests(struct ptest_list *, int, const char *progname, FILE *, FILE *);
+extern int run_ptests(struct ptest_list *, int, const char *progname, FILE *, FILE *, char *xml_filename);
+extern XML * xml_create(int test_count, char *filename);
+extern void xml_add_case(XML *, int status, const char *ptest_dir);
+extern void xml_finish(XML *);

I'm trying to follow BSD code-style so please remove variable names from prototypes. Also i make a mistake with progname that was before on the run_ptests prototype.

Also i don't wrote about code style into README, i will put a section into it, sorry for that.

Best regards,
alimon

Quoted 3 lines
utils.h +0 -0
 #endif
 
#2 lore raw

Sure Anibal, see my response inline.

Quoted 10 lines

-----Original Message-----
From: Aníbal Limón [mailto:[email protected]]
Sent: Thursday, January 19, 2017 11:42 AM
To: Pascal Bach <[email protected]>; [email protected]; Christian Schuler <[email protected]>; Esquivel, Benjamin <[email protected]>
Subject: Re: [yocto] [ptest-runner][PATCH] feat: generate xml-file

Hi Pascal and Christian,

Quoted 8 lines

Your patch looks good at first look, only a few comments about the code inline.

We are trying to standardize the results output format across our testing components in order to build up-on a Test reporting tool, so let us review the XML format.

Benjamin do you have a wiki page link with test result format information?

https://wiki.yoctoproject.org/wiki/QA/xUnit_XML_Template

Quoted 326 lines

Cheers,
alimon

Quoted 8 lines · Pascal Bach

From: Christian Schuler <[email protected]>

add a feature that allows the user to generate an XUnit xml-file. This file shows if the ptests run correctly or not. e.g. bash, zlib. It doesn't list the underlaying tests of the package.
The feature is activated by console input -x <filepath>. Unit-tests of the feature are included.

Quoted 7 lines
---
 README.md     |  1 +
 main.c        | 15 +++++++++++----
 tests/utils.c | 46 +++++++++++++++++++++++++++++++++++++++++++--
 utils.c       | 60

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-

Quoted 20 lines
 utils.h       |  7 ++++++-
 5 files changed, 121 insertions(+), 8 deletions(-)
README.md +1 -0
index ed7a589..fedab04 100644
@@ -14,6 +14,7 @@ Now the ptest-runner2 support the next features:
 - List available ptests.
 - Specify the timeout for avoid blocking indefinetly.
 - Only run certain ptests.
+- XML-ouput
 
 Proposed features:
 
main.c +0 -0
index 31bf3b5..8dfdad6 100644

main.c line 43

Quoted 4 lines
main.c +1 -1
@@ -41,7 +41,7 @@
 static inline void
 print_usage(FILE *stream, char *progname)  {
-	fprintf(stream, "Usage: %s [-d directory] [-l list] [-t timeout] "
+	fprintf(stream, "Usage: %s [-d directory] [-l list] [-t timeout] [-x xml-

filename]"

Quoted 22 lines
main.c +3 -1
 			"[-h] [ptest1 ptest2 ...]\n", progname);  }
 
@@ -50,6 +50,7 @@ static struct {
 	int list;
 	int timeout;
 	char **ptests;
+	char * xml_filename;
 } opts;
 
 int
@@ -70,8 +71,9 @@ main(int argc, char *argv[])
 	opts.list = 0;
 	opts.timeout = DEFAULT_TIMEOUT;
 	opts.ptests = NULL;
+	opts.xml_filename = NULL;
 
-	while ((opt = getopt(argc, argv, "d:lt:h")) != -1) {
+	while ((opt = getopt(argc, argv, "d:ltx:h")) != -1) {
 		switch (opt) {
 			case 'd':
 				free(opts.directory);

main.c main(int argc, char *argv[]) · line 96

Quoted 7 lines
main.c +4 -0
@@ -88,6 +90,11 @@ main(int argc, char *argv[])
 				print_usage(stdout, argv[0]);
 				exit(0);
 			break;
+			case 'x':
+				free(opts.xml_filename);
+				opts.xml_filename = strdup(optarg);
+				CHECK_ALLOCATION(opts.xml_filename, 1,

1);

Quoted 5 lines
main.c +1 -0
+			break;
 			default:
 				print_usage(stdout, argv[0]);
 				exit(1);

main.c main(int argc, char *argv[]) · line 144

Quoted 9 lines
main.c +3 -2
@@ -131,9 +138,9 @@ main(int argc, char *argv[])
 		run = filter_ptests(head, opts.ptests, ptest_num);
 		CHECK_ALLOCATION(run, ptest_num, 1);
 		ptest_list_free_all(head);
-	}
+	}
 
-	rc = run_ptests(run, opts.timeout, argv[0], stdout, stderr);
+	rc = run_ptests(run, opts.timeout, argv[0], stdout, stderr,
+opts.xml_filename);

Will be a good idea modify the run_ptest signature to pass the whole options to it.

I mean:

run_ptests(run, opts, argv[0], stdout, stderr)

If you could do a first patch with this change and then add your functionality realted to xml_filename will be good.

tests/utils.c START_TEST(test_run_ptests) · line 176

Quoted 12 lines
main.c +0 -0
 	ptest_list_free_all(run);
 
tests/utils.c index 1332798..dd869e9 renamed from tests/utils.c +0 -0

100644

tests/utils.c +0 -1
@@ -173,7 +173,7 @@ START_TEST(test_run_ptests)
 	ptest_list_remove(head, "hang", 1);
 	ptest_list_remove(head, "fail", 1);
 
-	rc = run_ptests(head, timeout, "test_run_ptests", fp_stdout,

fp_stderr);

tests/utils.c START_TEST(test_run_fail_ptest) · line 238

Quoted 11 lines
tests/utils.c +4 -0
+	rc = run_ptests(head, timeout, "test_run_ptests", fp_stdout,
+fp_stderr, NULL);
 	ck_assert(rc == 0);
 	ptest_list_free_all(head);
@@ -234,6 +234,46 @@ START_TEST(test_run_fail_ptest)
 	ptest_list_free_all(head);
 END_TEST
 
+START_TEST(test_xml_pass)
+	char ref[] = "<?xml version='1.0' encoding='UTF-8'?>\n<testsuite

name='ptests' tests='2'>\n"

tests/utils.c START_TEST(test_run_fail_ptest) · line 239

Quoted 1 line
tests/utils.c +1 -0
+			"<testcase name='.'>\n<nodes expected='/'

result='/'>\n"

tests/utils.c START_TEST(test_run_fail_ptest)

Quoted 9 lines
tests/utils.c +9 -0
+			"<nodes expected='0' result='0'>\n"
+			"</nodes>\n"
+			"</nodes>\n"
+			"</testcase>\n"
+			"<testcase name='.'>\n"
+			"<nodes expected='/' result='/'>\n"
+			"<nodes expected='0' result='1'>\n"
+			"<error type='Timeout/Unexpected error'>\n"
+			"A Timeout has occured or more tests than expected

failed.\n"

tests/utils.c test_ptest_expected_failure(struct ptest_list

Quoted 41 lines
tests/utils.c +30 -0
+			"</error>\n"
+			"</nodes>\n"
+			"</nodes>\n"
+			"</testcase>\n"
+			"</testsuite>";
+	char buffer[strlen(ref)];
+
+	FILE *fp;
+	fp = xml_create(2, "./test_xml");
+	xml_add_case(fp, 0,".");
+	xml_add_case(fp, 1,".");
+	xml_finish(fp);
+
+	fp = fopen("./test_xml", "a+");
+	fseek(fp, 0, SEEK_SET);
+
+	fread(buffer, strlen(ref), 1, fp);
+	ck_assert(strncmp(ref, buffer, strlen(ref)) == 0);
+	fclose(fp);
+	unlink("./test_xml");
+
+END_TEST
+
+START_TEST(test_xml_fail)
+	ck_assert(xml_create(2, "./") == NULL);
+
+END_TEST
+
 Suite *
 utils_suite()
 {
@@ -249,6 +289,8 @@ utils_suite()
 	tcase_add_test(tc_core, test_run_ptests);
 	tcase_add_test(tc_core, test_run_timeout_ptest);
 	tcase_add_test(tc_core, test_run_fail_ptest);
+	tcase_add_test(tc_core, test_xml_pass);
+	tcase_add_test(tc_core, test_xml_fail);
 
 	suite_add_tcase(s, tc_core);
 
@@ -276,7 +318,7 @@ test_ptest_expected_failure(struct ptest_list

*head, const int timeout, char *pr

tests/utils.c test_ptest_expected_failure(struct ptest_list *head, const int timeout, char *pr

Quoted 4 lines
tests/utils.c +0 -1
 		ck_assert(ptest_list_length(filtered) == 1);
 
 		h_analizer(
-			run_ptests(filtered, timeout, progname, fp_stdout,

fp_stderr),

tests/utils.c test_ptest_expected_failure(struct ptest_list · line 321

Quoted 1 line
tests/utils.c +1 -0
+			run_ptests(filtered, timeout, progname, fp_stdout,

fp_stderr,

utils.c run_ptests(struct ptest_list *head, int timeout,

Quoted 22 lines
tests/utils.c +1 -0
+NULL),
 			fp_stdout, fp_stderr
 		);
utils.c +2 -1
index 77427e0..430fb7a 100644
@@ -303,9 +303,10 @@ wait_child(const char *ptest_dir, const char
 *run_ptest, pid_t pid,
 
 int
 run_ptests(struct ptest_list *head, int timeout, const char *progname,
-		FILE *fp, FILE *fp_stderr)
+		FILE *fp, FILE *fp_stderr, char *xml_filename)
 {
 	int rc = 0;
+	XML *xh;
 
 	struct ptest_list *p;
utils.c +0 -0
 	char stime[GET_STIME_BUF_SIZE];
@@ -314,6 +315,12 @@ run_ptests(struct ptest_list *head, int timeout,

const char *progname,

utils.c run_ptests(struct ptest_list *head, int timeout, const char *progname,

Quoted 12 lines
utils.c +6 -0
 	int pipefd_stdout[2];
 	int pipefd_stderr[2];
 
+	if(xml_filename) {
+		xh = xml_create(ptest_list_length(head), xml_filename);
+		if(!xh)
+			exit(EXIT_FAILURE);
+	}
+
 	do
 	{
 		if ((rc = pipe2(pipefd_stdout, O_NONBLOCK)) == -1) @@ -

355,6 +362,9

Quoted 1 line

@@ run_ptests(struct ptest_list *head, int timeout, const char

*progname,

Quoted 1 line

fprintf(fp, "ERROR: Exit status is

%d\n", status);

utils.c run_ptests(struct ptest_list *head, int timeout, const char *progname,

Quoted 7 lines
utils.c +3 -0
 					rc += 1;
 				}
+				if (xml_filename)
+					xml_add_case(xh, status, ptest_dir);
+
 				fprintf(fp, "END: %s\n", ptest_dir);
 				fprintf(fp, "%s\n", get_stime(stime,

GET_STIME_BUF_SIZE));

utils.c run_ptests(struct ptest_list *head, int timeout,

Quoted 2 lines
utils.c +0 -0
 			}
@@ -368,5 +378,53 @@ run_ptests(struct ptest_list *head, int timeout,

const char *progname,

Quoted 6 lines
utils.c +3 -0
 	if (rc == -1)
 		fprintf(fp_stderr, "run_ptests fails: %s", strerror(errno));
 
+	if (xml_filename)
+		xml_finish(xh);
+

utils.c run_ptests(struct ptest_list *head, int timeout, const char *progname,

Quoted 10 lines
utils.c +8 -0
 	return rc;
 }
+
+FILE *
+xml_create(int test_count, char *xml_filename) {
+	FILE *xh;
+
+	if ((xh = fopen(xml_filename, "w"))) {
+		fprintf(xh, "<?xml version='1.0' encoding='UTF-8'?>\n");
+		fprintf(xh, "<testsuite name='ptests' tests='%d'>\n",

test_count);

utils.c run_ptests(struct ptest_list *head, int timeout, const char *progname,

Quoted 3 lines
utils.c +3 -0
+	}
+	else {
+		fprintf(stderr, "File could not be created. Make sure the path

is correct and you have the right permissions.");

Quoted 9 lines
utils.c +9 -0
+		return NULL;
+	}
+
+	return xh;
+}
+
+void
+xml_add_case(FILE *xh, int status, const char *ptest_dir) {
+	fprintf(xh, "<testcase name='%s'>\n", ptest_dir);

utils.c run_ptests(struct ptest_list *head, int timeout, const char *progname,

Quoted 10 lines
utils.c +10 -0
+	fprintf(xh, "<nodes expected='/' result='/'>\n");
+
+	if(status == 0){
+		fprintf(xh, "<nodes expected='0' result='0'>\n");
+		fprintf(xh, "</nodes>\n");
+	}
+	else{
+		fprintf(xh, "<nodes expected='0' result='%d'>\n", status);
+		fprintf(xh, "<error type='Timeout/Unexpected error'>\n");
+		fprintf(xh, "A Timeout has occured or more tests than

expected failed.\n");

Quoted 29 lines
utils.c +13 -0
+		fprintf(xh, "</error>\n");
+		fprintf(xh, "</nodes>\n");
+	}
+	fprintf(xh, "</nodes>\n");
+	fprintf(xh, "</testcase>\n");
+}
+
+void
+xml_finish(FILE *xh)
+{
+	fprintf(xh, "</testsuite>");
+	fclose(xh);
+}
utils.h +2 -0
index 4dc23ef..99f6100 100644
@@ -30,10 +30,15 @@
 #define CHECK_ALLOCATION(p, size, exit_on_null) \
 	check_allocation1(p, size, __FILE__, __LINE__, exit_on_null)
 
+typedef FILE XML;
+
 extern void check_allocation1(void *, size_t, char *, int, int);

extern struct ptest_list *get_available_ptests(const char *); extern int print_ptests(struct ptest_list *, FILE *); extern struct ptest_list *filter_ptests(struct ptest_list *, char **, int); -extern int run_ptests(struct ptest_list *, int, const char *progname, FILE *, FILE *);

utils.h

Quoted 4 lines
utils.h +4 -0
+extern int run_ptests(struct ptest_list *, int, const char *progname,
+FILE *, FILE *, char *xml_filename); extern XML * xml_create(int
+test_count, char *filename); extern void xml_add_case(XML *, int
+status, const char *ptest_dir); extern void xml_finish(XML *);

I'm trying to follow BSD code-style so please remove variable names from prototypes. Also i make a mistake with progname that was before on the run_ptests prototype.

Also i don't wrote about code style into README, i will put a section into it, sorry for that.

Best regards,
alimon

Quoted 3 lines

#endif

#3 lore raw

Hi Benjamin and Anibal

See inline repsonse.

Quoted 15 lines · Benjamin

Sure Anibal, see my response inline.

Quoted 13 lines

-----Original Message-----
From: Aníbal Limón [mailto:[email protected]]
Sent: Thursday, January 19, 2017 11:42 AM
To: Pascal Bach <[email protected]>; [email protected]; Christian Schuler <[email protected]>; Esquivel, Benjamin <[email protected]>
Subject: Re: [yocto] [ptest-runner][PATCH] feat: generate xml-file

Hi Pascal and Christian,

Your patch looks good at first look, only a few comments about the code inline.

Quoted 6 lines
Quoted 5 lines

We are trying to standardize the results output format across our testing components in order to build up-on a Test reporting tool, so let us review the XML format.

Benjamin do you have a wiki page link with test result format information?

https://wiki.yoctoproject.org/wiki/QA/xUnit_XML_Template

Thanks, the current XML is just a minimal set but it should comply to the xUnit spec. But enhancements are of course welcome.

Quoted 297 lines
Quoted 297 lines

Cheers,
alimon

Quoted 8 lines · Pascal Bach

From: Christian Schuler <[email protected]>

add a feature that allows the user to generate an XUnit xml-file. This file shows if the ptests run correctly or not. e.g. bash, zlib. It doesn't list the underlaying tests of the package.
The feature is activated by console input -x <filepath>. Unit-tests of the feature are included.

Quoted 7 lines
---
 README.md     |  1 +
 main.c        | 15 +++++++++++----
 tests/utils.c | 46 +++++++++++++++++++++++++++++++++++++++++++--
 utils.c       | 60

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-

Quoted 20 lines
 utils.h       |  7 ++++++-
 5 files changed, 121 insertions(+), 8 deletions(-)
README.md +1 -0
index ed7a589..fedab04 100644
@@ -14,6 +14,7 @@ Now the ptest-runner2 support the next features:
 - List available ptests.
 - Specify the timeout for avoid blocking indefinetly.
 - Only run certain ptests.
+- XML-ouput
 
 Proposed features:
 
main.c +0 -0
index 31bf3b5..8dfdad6 100644

main.c line 43

Quoted 4 lines
main.c +1 -1
@@ -41,7 +41,7 @@
 static inline void
 print_usage(FILE *stream, char *progname)  {
-	fprintf(stream, "Usage: %s [-d directory] [-l list] [-t timeout] "
+	fprintf(stream, "Usage: %s [-d directory] [-l list] [-t timeout] [-x xml-

filename]"

Quoted 22 lines
main.c +3 -1
 			"[-h] [ptest1 ptest2 ...]\n", progname);  }
 
@@ -50,6 +50,7 @@ static struct {
 	int list;
 	int timeout;
 	char **ptests;
+	char * xml_filename;
 } opts;
 
 int
@@ -70,8 +71,9 @@ main(int argc, char *argv[])
 	opts.list = 0;
 	opts.timeout = DEFAULT_TIMEOUT;
 	opts.ptests = NULL;
+	opts.xml_filename = NULL;
 
-	while ((opt = getopt(argc, argv, "d:lt:h")) != -1) {
+	while ((opt = getopt(argc, argv, "d:ltx:h")) != -1) {
 		switch (opt) {
 			case 'd':
 				free(opts.directory);

main.c main(int argc, char *argv[]) · line 96

Quoted 7 lines
main.c +4 -0
@@ -88,6 +90,11 @@ main(int argc, char *argv[])
 				print_usage(stdout, argv[0]);
 				exit(0);
 			break;
+			case 'x':
+				free(opts.xml_filename);
+				opts.xml_filename = strdup(optarg);
+				CHECK_ALLOCATION(opts.xml_filename, 1,

1);

Quoted 5 lines
main.c +1 -0
+			break;
 			default:
 				print_usage(stdout, argv[0]);
 				exit(1);

main.c main(int argc, char *argv[]) · line 144

Quoted 9 lines
main.c +3 -2
@@ -131,9 +138,9 @@ main(int argc, char *argv[])
 		run = filter_ptests(head, opts.ptests, ptest_num);
 		CHECK_ALLOCATION(run, ptest_num, 1);
 		ptest_list_free_all(head);
-	}
+	}
 
-	rc = run_ptests(run, opts.timeout, argv[0], stdout, stderr);
+	rc = run_ptests(run, opts.timeout, argv[0], stdout, stderr,
+opts.xml_filename);

Will be a good idea modify the run_ptest signature to pass the whole options to it.

I mean:

run_ptests(run, opts, argv[0], stdout, stderr)

If you could do a first patch with this change and then add your functionality realted to xml_filename will be good.

tests/utils.c START_TEST(test_run_ptests) · line 176

Quoted 11 lines
main.c +0 -0
 	ptest_list_free_all(run);
 
tests/utils.c index 1332798..dd869e9 renamed from tests/utils.c +0 -0

100644

tests/utils.c +0 -1
@@ -173,7 +173,7 @@ START_TEST(test_run_ptests)
 	ptest_list_remove(head, "hang", 1);
 	ptest_list_remove(head, "fail", 1);
 
-	rc = run_ptests(head, timeout, "test_run_ptests", fp_stdout,

fp_stderr);

tests/utils.c START_TEST(test_run_fail_ptest) · line 238

Quoted 11 lines
tests/utils.c +4 -0
+	rc = run_ptests(head, timeout, "test_run_ptests", fp_stdout,
+fp_stderr, NULL);
 	ck_assert(rc == 0);
 	ptest_list_free_all(head);
@@ -234,6 +234,46 @@ START_TEST(test_run_fail_ptest)
 	ptest_list_free_all(head);
 END_TEST
 
+START_TEST(test_xml_pass)
+	char ref[] = "<?xml version='1.0' encoding='UTF-8'?>\n<testsuite

name='ptests' tests='2'>\n"

tests/utils.c START_TEST(test_run_fail_ptest) · line 239

Quoted 1 line
tests/utils.c +1 -0
+			"<testcase name='.'>\n<nodes expected='/'

result='/'>\n"

tests/utils.c START_TEST(test_run_fail_ptest)

Quoted 9 lines
tests/utils.c +9 -0
+			"<nodes expected='0' result='0'>\n"
+			"</nodes>\n"
+			"</nodes>\n"
+			"</testcase>\n"
+			"<testcase name='.'>\n"
+			"<nodes expected='/' result='/'>\n"
+			"<nodes expected='0' result='1'>\n"
+			"<error type='Timeout/Unexpected error'>\n"
+			"A Timeout has occured or more tests than expected

failed.\n"

tests/utils.c test_ptest_expected_failure(struct ptest_list

Quoted 41 lines
tests/utils.c +30 -0
+			"</error>\n"
+			"</nodes>\n"
+			"</nodes>\n"
+			"</testcase>\n"
+			"</testsuite>";
+	char buffer[strlen(ref)];
+
+	FILE *fp;
+	fp = xml_create(2, "./test_xml");
+	xml_add_case(fp, 0,".");
+	xml_add_case(fp, 1,".");
+	xml_finish(fp);
+
+	fp = fopen("./test_xml", "a+");
+	fseek(fp, 0, SEEK_SET);
+
+	fread(buffer, strlen(ref), 1, fp);
+	ck_assert(strncmp(ref, buffer, strlen(ref)) == 0);
+	fclose(fp);
+	unlink("./test_xml");
+
+END_TEST
+
+START_TEST(test_xml_fail)
+	ck_assert(xml_create(2, "./") == NULL);
+
+END_TEST
+
 Suite *
 utils_suite()
 {
@@ -249,6 +289,8 @@ utils_suite()
 	tcase_add_test(tc_core, test_run_ptests);
 	tcase_add_test(tc_core, test_run_timeout_ptest);
 	tcase_add_test(tc_core, test_run_fail_ptest);
+	tcase_add_test(tc_core, test_xml_pass);
+	tcase_add_test(tc_core, test_xml_fail);
 
 	suite_add_tcase(s, tc_core);
 
@@ -276,7 +318,7 @@ test_ptest_expected_failure(struct ptest_list

*head, const int timeout, char *pr

tests/utils.c test_ptest_expected_failure(struct ptest_list *head, const int timeout, char *pr

Quoted 4 lines
tests/utils.c +0 -1
 		ck_assert(ptest_list_length(filtered) == 1);
 
 		h_analizer(
-			run_ptests(filtered, timeout, progname, fp_stdout,

fp_stderr),

tests/utils.c test_ptest_expected_failure(struct ptest_list · line 321

Quoted 1 line
tests/utils.c +1 -0
+			run_ptests(filtered, timeout, progname, fp_stdout,

fp_stderr,

utils.c run_ptests(struct ptest_list *head, int timeout,

Quoted 22 lines
tests/utils.c +1 -0
+NULL),
 			fp_stdout, fp_stderr
 		);
utils.c +2 -1
index 77427e0..430fb7a 100644
@@ -303,9 +303,10 @@ wait_child(const char *ptest_dir, const char
 *run_ptest, pid_t pid,
 
 int
 run_ptests(struct ptest_list *head, int timeout, const char *progname,
-		FILE *fp, FILE *fp_stderr)
+		FILE *fp, FILE *fp_stderr, char *xml_filename)
 {
 	int rc = 0;
+	XML *xh;
 
 	struct ptest_list *p;
utils.c +0 -0
 	char stime[GET_STIME_BUF_SIZE];
@@ -314,6 +315,12 @@ run_ptests(struct ptest_list *head, int timeout,

const char *progname,

utils.c run_ptests(struct ptest_list *head, int timeout, const char *progname,

Quoted 12 lines
utils.c +6 -0
 	int pipefd_stdout[2];
 	int pipefd_stderr[2];
 
+	if(xml_filename) {
+		xh = xml_create(ptest_list_length(head), xml_filename);
+		if(!xh)
+			exit(EXIT_FAILURE);
+	}
+
 	do
 	{
 		if ((rc = pipe2(pipefd_stdout, O_NONBLOCK)) == -1) @@ -

355,6 +362,9

Quoted 1 line

@@ run_ptests(struct ptest_list *head, int timeout, const char

*progname,

Quoted 1 line

fprintf(fp, "ERROR: Exit status is

%d\n", status);

utils.c run_ptests(struct ptest_list *head, int timeout, const char *progname,

Quoted 7 lines
utils.c +3 -0
 					rc += 1;
 				}
+				if (xml_filename)
+					xml_add_case(xh, status, ptest_dir);
+
 				fprintf(fp, "END: %s\n", ptest_dir);
 				fprintf(fp, "%s\n", get_stime(stime,

GET_STIME_BUF_SIZE));

utils.c run_ptests(struct ptest_list *head, int timeout,

Quoted 2 lines
utils.c +0 -0
 			}
@@ -368,5 +378,53 @@ run_ptests(struct ptest_list *head, int timeout,

const char *progname,

Quoted 6 lines
utils.c +3 -0
 	if (rc == -1)
 		fprintf(fp_stderr, "run_ptests fails: %s", strerror(errno));
 
+	if (xml_filename)
+		xml_finish(xh);
+

utils.c run_ptests(struct ptest_list *head, int timeout, const char *progname,

Quoted 10 lines
utils.c +8 -0
 	return rc;
 }
+
+FILE *
+xml_create(int test_count, char *xml_filename) {
+	FILE *xh;
+
+	if ((xh = fopen(xml_filename, "w"))) {
+		fprintf(xh, "<?xml version='1.0' encoding='UTF-8'?>\n");
+		fprintf(xh, "<testsuite name='ptests' tests='%d'>\n",

test_count);

utils.c run_ptests(struct ptest_list *head, int timeout, const char *progname,

Quoted 3 lines
utils.c +3 -0
+	}
+	else {
+		fprintf(stderr, "File could not be created. Make sure the path

is correct and you have the right permissions.");

Quoted 9 lines
utils.c +9 -0
+		return NULL;
+	}
+
+	return xh;
+}
+
+void
+xml_add_case(FILE *xh, int status, const char *ptest_dir) {
+	fprintf(xh, "<testcase name='%s'>\n", ptest_dir);

utils.c run_ptests(struct ptest_list *head, int timeout, const char *progname,

Quoted 10 lines
utils.c +10 -0
+	fprintf(xh, "<nodes expected='/' result='/'>\n");
+
+	if(status == 0){
+		fprintf(xh, "<nodes expected='0' result='0'>\n");
+		fprintf(xh, "</nodes>\n");
+	}
+	else{
+		fprintf(xh, "<nodes expected='0' result='%d'>\n", status);
+		fprintf(xh, "<error type='Timeout/Unexpected error'>\n");
+		fprintf(xh, "A Timeout has occured or more tests than

expected failed.\n");

Quoted 21 lines
utils.c +13 -0
+		fprintf(xh, "</error>\n");
+		fprintf(xh, "</nodes>\n");
+	}
+	fprintf(xh, "</nodes>\n");
+	fprintf(xh, "</testcase>\n");
+}
+
+void
+xml_finish(FILE *xh)
+{
+	fprintf(xh, "</testsuite>");
+	fclose(xh);
+}
utils.h +0 -0
index 4dc23ef..99f6100 100644
@@ -30,10 +30,15 @@
 #define CHECK_ALLOCATION(p, size, exit_on_null) \
 	check_allocation1(p, size, __FILE__, __LINE__, exit_on_null)
 
Quoted 15 lines
Quoted 7 lines
Quoted 7 lines
utils.h +2 -0
+typedef FILE XML;
+
 extern void check_allocation1(void *, size_t, char *, int, int);

extern struct ptest_list *get_available_ptests(const char *); extern int print_ptests(struct ptest_list *, FILE *); extern struct ptest_list *filter_ptests(struct ptest_list *, char **, int); -extern int run_ptests(struct ptest_list *, int, const char *progname, FILE *,

Quoted 8 lines

utils.h

Quoted 5 lines

FILE *);

utils.h +4 -0
+extern int run_ptests(struct ptest_list *, int, const char *progname,
+FILE *, FILE *, char *xml_filename); extern XML * xml_create(int
+test_count, char *filename); extern void xml_add_case(XML *, int
+status, const char *ptest_dir); extern void xml_finish(XML *);

I'm trying to follow BSD code-style so please remove variable names from prototypes. Also i make a mistake with progname that was before on the run_ptests prototype.

We will do a rework of the patch that addresses the style issue. The XML we leave untouched for the moment.

Pascal

Quoted 8 lines
Quoted 8 lines

Also i don't wrote about code style into README, i will put a section into it, sorry for that.

Best regards,
alimon

Quoted 2 lines

#endif