Add a script to parse the make test output into XML file so it can be consumed by CITE/Sponge.
Change-Id: I3870d7522d1d25a09575f82e6ef6a29988cbf5fb
diff --git a/Makefile b/Makefile
index add2bfd..edb2d06 100644
--- a/Makefile
+++ b/Makefile
@@ -14,8 +14,8 @@
wvtest/wvtestrun $(MAKE) runtests
test_with_output:
- $(MAKE) runtests > result.txt
- result_parser.py result.txt result.xml
+ $(MAKE) runtests &> result.txt
+ wvtest_result_converter.py result.txt result.xml
#TODO(apenwarr): use a smarter allocator.
# We could enable parallelism by depending on $(addsuffix ...) instead of
diff --git a/result_parser.py b/wvtest_result_converter.py
similarity index 60%
rename from result_parser.py
rename to wvtest_result_converter.py
index 01c6c0a..4463f7b 100755
--- a/result_parser.py
+++ b/wvtest_result_converter.py
@@ -1,9 +1,29 @@
#!/usr/bin/python
-"""Parse the wvtest results from the output of 'make test_with_output'.
+"""Convert the wvtest results into standard gunit xml output.'.
^Testing ".+" in .+:$ marks starts of a test file
^! .+$ marks a test case status
+Examples:
+Testing "cwmpd" in unknown:
+ ! unknown:0 running cwmpd ok
+ ! unknown:0 grep X_CATAWAMPUS-ORG_CATAWAMPUS ok
+ ! unknown:0 NOT(grep NON_EXISTENT_NAME) ok
+ make[2]: Leaving directory
+ `/usr/local/google/brucefan/bruno-git/vendor/google/test'
+ make[2]: Entering directory
+ `/usr/local/google/brucefan/bruno-git/vendor/google/test'
+ echo "Testing 002-pytest.py"
+ Testing 002-pytest.py
+ ssh -l root 192.168.1.3 \
+ 'cd /tmp/tests && python ./wvtest/wvtest.py 002-pytest.py' </dev/null
+Importing: 002-pytest
+
+Testing "TestBasicPython" in 002-pytest.py:
+ ! 002-pytest.py:14 True ok
+ ! 002-pytest.py:15 1 == 1 ok
+ ! 002-pytest.py:16 1 != 2 ok
+
The test result will be saved to a .xml file that can be used by our dashboard
system to stream the data into Sponge easily.
"""
@@ -11,50 +31,12 @@
__author__ = 'brucefan@google.com (Chun Fan)'
+from lxml import etree
import os
import re
import sys
-SUITES_TEMPLATE = """
-<testsuites disabled="0" errors="{num_of_errors}"
- failures="{num_of_failures}" tests="{num_of_tests}"
- name="{suites_name}" time="0.0">
- {test_suites}
-</testsuites>
-"""
-
-SUITE_TEMPLATE = """
-<testsuite disabled="0" errors="{suite_errors}"
- failures="{suite_failures}" name="{suite_name}"
- tests="{suite_tests}" time="0.0">
- {test_cases}
-</testsuite>
-"""
-
-TEST_CASE_PASS_TEMPLATE = """
-<testcase classname="{class_name}" name="{test_case_name}"
- status="run" time="0.0"/>
-"""
-
-TEST_CASE_FAILURE_TEMPLATE = """
-<testcase classname="{class_name}" name="{test_case_name}"
- status="run" time="0.0">
- <failure>
- {result_msg}
- </failure>
-</testcase>
-"""
-
-TEST_CASE_ERROR_TEMPLATE = """
-<testcase classname="%(class_name)s" name="%(test_case_name)s"
- status="run" time="0.0">
- <error>
- {result_msg}
- </error>
-</testcase>
-"""
-
class TestSuitesResult(object):
def __init__(self, name):
@@ -65,18 +47,20 @@
self.test_suite_results.append(test_suite_result)
def ToXml(self):
- self.test_suites_xml = '\n'.join(
- [ts.ToXml() for ts in self.test_suite_results])
+ el = etree.Element('testsuites')
+ el.set('name', self.name)
+ el.set('disabled', '0')
+ el.set('time', '0.0')
+ el.set('errors', '0')
+ for ts in self.test_suite_results:
+ el.append(ts.ToXml())
self.total_tests = sum(
[ts.total_tests for ts in self.test_suite_results])
self.failures = sum(
[ts.failures for ts in self.test_suite_results])
- return SUITES_TEMPLATE.format(
- suites_name=self.name,
- num_of_errors=0,
- num_of_failures=self.failures,
- num_of_tests=self.total_tests,
- test_suites=self.test_suites_xml)
+ el.set('failures', str(self.failures))
+ el.set('tests', str(self.total_tests))
+ return el
class TestSuiteResult(object):
@@ -89,21 +73,23 @@
self.test_case_results.append(test_case_result)
def ToXml(self):
- self.test_cases_xml = '\n'.join(
- [tc.ToXml() for tc in self.test_case_results])
+ el = etree.Element('testsuite')
+ el.set('name', self.name)
+ el.set('disabled', '0')
+ el.set('time', '0.0')
+ el.set('errors', '0')
+ for tc in self.test_case_results:
+ el.append(tc.ToXml())
self.total_tests = len(self.test_case_results)
self.failures = len([tc for tc in self.test_case_results if tc.result])
- return SUITE_TEMPLATE.format(
- suite_name=self.name,
- suite_errors=0,
- suite_failures=self.failures,
- suite_tests=self.total_tests,
- test_cases=self.test_cases_xml)
+ el.set('failures', str(self.failures))
+ el.set('tests', str(self.total_tests))
+ return el
class TestCaseResult(object):
- PASS = 0
+ PASSED = 0
FAILED = 1
ERROR = 2
@@ -112,23 +98,21 @@
self.class_name = class_name
self.result = result
self.result_msg = result_msg
- self.result_template_map = {
- TestCaseResult.PASS: TEST_CASE_PASS_TEMPLATE,
- TestCaseResult.FAILED: TEST_CASE_FAILURE_TEMPLATE,
- TestCaseResult.ERROR: TEST_CASE_ERROR_TEMPLATE}
def ToXml(self):
- template = self.result_template_map.get(
- self.result, TEST_CASE_FAILURE_TEMPLATE)
+ el = etree.Element('testcase')
+ el.set('name', self.name)
+ el.set('classname', self.class_name)
+ el.set('time', '0')
+ el.set('status', 'run')
if self.result:
print 'Test case: ', self.name, 'FAILED with result code', self.result
- return template.format(class_name=self.class_name,
- test_case_name=self.name,
- result_msg=self.result_msg)
+ failure = etree.Element('failure')
+ failure.text = self.result_msg
+ el.append(failure)
else:
print 'Test case: ', self.name, 'PASSED with result code', self.result
- return template.format(class_name=self.class_name,
- test_case_name=self.name)
+ return el
def ParseTestResult(result_file, output_xml_file):
@@ -158,7 +142,7 @@
test_case_name = ' '.join(parts[2:-2]).strip()
test_case_class_name = '%s-%s' % (
current_test_suite.name, test_case_name)
- test_case_result = TestCaseResult.PASS
+ test_case_result = TestCaseResult.PASSED
test_case_result_msg = ''
if parts[-1] != 'ok':
test_case_result = TestCaseResult.FAILED
@@ -172,7 +156,7 @@
result_msg=test_case_result_msg))
# Now it is time to write the xml output
with open(output_xml_file, 'w') as f:
- f.write(test_suites.ToXml())
+ f.write(etree.tostring(test_suites.ToXml(), pretty_print=True))
def main(argv):