Include more details in XML log for tests.
Include skipped tests, hftest output for failed tests, and full logs.
Change-Id: I566724ffbf0a3a89955e879bf499d24abc21e08f
diff --git a/test/hftest/hftest.py b/test/hftest/hftest.py
index a84dda5..22d2c42 100755
--- a/test/hftest/hftest.py
+++ b/test/hftest/hftest.py
@@ -419,6 +419,7 @@
TestRunnerResult = collections.namedtuple("TestRunnerResult", [
"tests_run",
"tests_failed",
+ "tests_skipped",
])
@@ -464,15 +465,18 @@
Insert "tests" and "failures" nodes to `xml_node`."""
tests_run = 0
tests_failed = 0
+ tests_skipped = 0
for i in it:
sub_result = fn(i)
assert(sub_result.tests_run >= sub_result.tests_failed)
tests_run += sub_result.tests_run
tests_failed += sub_result.tests_failed
+ tests_skipped += sub_result.tests_skipped
- xml_node.set("tests", str(tests_run))
+ xml_node.set("tests", str(tests_run + tests_skipped))
xml_node.set("failures", str(tests_failed))
- return TestRunnerResult(tests_run, tests_failed)
+ xml_node.set("skipped", str(tests_skipped))
+ return TestRunnerResult(tests_run, tests_failed, tests_skipped)
def is_passed_test(self, test_out):
"""Parse the output of a test and return True if it passed."""
@@ -481,6 +485,16 @@
test_out[-1] == HFTEST_LOG_FINISHED and \
not any(l.startswith(HFTEST_LOG_FAILURE_PREFIX) for l in test_out)
+ def get_failure_message(self, test_out):
+ """Parse the output of a test and return the message of the first
+ assertion failure."""
+ for i, line in enumerate(test_out):
+ if line.startswith(HFTEST_LOG_FAILURE_PREFIX) and i + 1 < len(test_out):
+ # The assertion message is on the line after the 'Failure:'
+ return test_out[i + 1].strip()
+
+ return None
+
def get_log_name(self, suite, test):
"""Returns a string with a generated log name for the test."""
log_name = ""
@@ -498,40 +512,49 @@
`suite`. Create a new XML node with results under `suite_xml`.
Test only invoked if it matches the regex given to constructor."""
if not self.test_re.match(test["name"]):
- return TestRunnerResult(tests_run=0, tests_failed=0)
-
- if self.skip_long_running_tests and test["is_long_running"]:
- print(" SKIP", test["name"])
- return TestRunnerResult(tests_run=0, tests_failed=0)
-
- print(" RUN", test["name"])
- log_name = self.get_log_name(suite, test)
+ return TestRunnerResult(tests_run=0, tests_failed=0, tests_skipped=0)
test_xml = ET.SubElement(suite_xml, "testcase")
test_xml.set("name", test["name"])
test_xml.set("classname", suite["name"])
+
+ if self.skip_long_running_tests and test["is_long_running"]:
+ print(" SKIP", test["name"])
+ test_xml.set("status", "notrun")
+ skipped_xml = ET.SubElement(test_xml, "skipped")
+ skipped_xml.set("message", "Long running")
+ return TestRunnerResult(tests_run=0, tests_failed=0, tests_skipped=1)
+
+ print(" RUN", test["name"])
+ log_name = self.get_log_name(suite, test)
+
test_xml.set("status", "run")
- out = self.extract_hftest_lines(self.driver.run(
+ out = self.driver.run(
log_name, "run {} {}".format(suite["name"], test["name"]),
- test["is_long_running"] or self.force_long_running))
+ test["is_long_running"] or self.force_long_running)
+ hftest_out = self.extract_hftest_lines(out)
- if self.is_passed_test(out):
+ system_out_xml = ET.SubElement(test_xml, "system-out")
+ system_out_xml.text = out
+
+ if self.is_passed_test(hftest_out):
print(" PASS")
- return TestRunnerResult(tests_run=1, tests_failed=0)
+ return TestRunnerResult(tests_run=1, tests_failed=0, tests_skipped=0)
else:
print("[x] FAIL --", self.driver.get_run_log(log_name))
failure_xml = ET.SubElement(test_xml, "failure")
- # TODO: set a meaningful message and put log in CDATA
- failure_xml.set("message", "Test failed")
- return TestRunnerResult(tests_run=1, tests_failed=1)
+ failure_message = self.get_failure_message(hftest_out) or "Test failed"
+ failure_xml.set("message", failure_message)
+ failure_xml.text = '\n'.join(hftest_out)
+ return TestRunnerResult(tests_run=1, tests_failed=1, tests_skipped=0)
def run_suite(self, suite, xml):
"""Invoke the test platform and request to run all matching tests in
`suite`. Create new XML nodes with results under `xml`.
Suite skipped if it does not match the regex given to constructor."""
if not self.suite_re.match(suite["name"]):
- return TestRunnerResult(tests_run=0, tests_failed=0)
+ return TestRunnerResult(tests_run=0, tests_failed=0, tests_skipped=0)
print(" SUITE", suite["name"])
suite_xml = ET.SubElement(xml, "testsuite")