From b296846535ab7df1d1fd1136db757dd1196c96cb Mon Sep 17 00:00:00 2001 From: melanie witt Date: Thu, 10 Nov 2016 18:13:26 +0000 Subject: [PATCH] Track failures during sorting of test results The current logic only considers the first occurrence of a test class and doesn't update a class's pass/fail status after that. So a test class, for example: TestClass test_1 pass test_2 fail test_3 pass is counted as a passing test class even though it has a failure. This adds failure tracking to the test result sorting so that any failure in a test class will make it considered a failing test class and be sorted at the top of the HTML result page. Closes-Bug: #1640889 Change-Id: I06919336a09c4afda8ec3a9e7d64d305fbd169c3 --- os_testr/subunit2html.py | 26 ++++++++++++++++++++------ os_testr/tests/test_subunit2html.py | 4 +++- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/os_testr/subunit2html.py b/os_testr/subunit2html.py index a710b9f..e53e29e 100755 --- a/os_testr/subunit2html.py +++ b/os_testr/subunit2html.py @@ -617,18 +617,31 @@ class HtmlOutput(testtools.TestResult): # unittest does not seems to run in any particular order. # Here at least we want to group them together by class. rmap = {} + classes = [] # Differentiate between classes that have test failures so we can sort # them at the top of the html page for easier troubleshooting - failclasses = [] - passclasses = [] + clsmap_has_failure = collections.defaultdict(bool) + + def track_has_failure(name, n): + if n == 1 or n == 2: + clsmap_has_failure[name] = True + for n, t, o, e in result_list: - classes = failclasses if n == 1 or n == 2 else passclasses if hasattr(t, '_tests'): for inner_test in t._tests: - self._add_cls(rmap, classes, inner_test, - (n, inner_test, o, e)) + name = self._add_cls(rmap, classes, inner_test, + (n, inner_test, o, e)) + track_has_failure(name, n) else: - self._add_cls(rmap, classes, t, (n, t, o, e)) + name = self._add_cls(rmap, classes, t, (n, t, o, e)) + track_has_failure(name, n) + + failclasses = [] + passclasses = [] + for cls in classes: + append_to = (failclasses if clsmap_has_failure[str(cls)] + else passclasses) + append_to.append(cls) classort = lambda s: str(s) sortedfailclasses = sorted(failclasses, key=classort) sortedpassclasses = sorted(passclasses, key=classort) @@ -649,6 +662,7 @@ class HtmlOutput(testtools.TestResult): rmap[str(cls)] = [] classes.append(cls) rmap[str(cls)].append(data_tuple) + return str(cls) def _generate_report_test(self, rows, cid, tid, n, t, o, e): # e.g. 'pt1.1', 'ft1.1', etc diff --git a/os_testr/tests/test_subunit2html.py b/os_testr/tests/test_subunit2html.py index 994eed6..57e92bb 100644 --- a/os_testr/tests/test_subunit2html.py +++ b/os_testr/tests/test_subunit2html.py @@ -54,8 +54,10 @@ class TestSubunit2html(base.TestCase): # example.path.to.test4 has a failure obj.addFailure(tests[4], err) obj.addSuccess(tests[7]) - # example.path.to.test6 has a failure + # example.path.to.test6 has a success, a failure, and a success + obj.addSuccess(tests[6]) obj.addFailure(tests[6], err) + obj.addSuccess(tests[6]) sorted_result = obj._sortResult(obj.result) # _sortResult returns a list of results of format: # [(class, [test_result_tuple, ...]), ...]