Fix stacktrace logging for when both test body and teardown throw
exceptions.
Actually fulfill the promise of TestRecord.add_error: if extra error
was added to the record, something went wrong, the test result should
be UNKNOWN (error) as opposed to the original result of the test body.
Also remove a duplicate test result log line.
Bug=28942818
Change-Id: Id8a48244732eed3dfa4d6fdb07224b2ea8ca418c
diff --git a/acts/framework/acts/base_test.py b/acts/framework/acts/base_test.py
index 8da846f..570a537 100644
--- a/acts/framework/acts/base_test.py
+++ b/acts/framework/acts/base_test.py
@@ -15,6 +15,7 @@
# limitations under the License.
import os
+import traceback
from acts import asserts
from acts import keys
@@ -262,7 +263,6 @@
test_name = record.test_name
self.log.exception(record.details)
begin_time = logger.epoch_to_log_line_timestamp(record.begin_time)
- self.log.info(RESULT_LINE_TEMPLATE, test_name, record.result)
self.on_exception(test_name, begin_time)
def on_exception(self, test_name, begin_time):
@@ -327,8 +327,15 @@
else:
verdict = test_func()
finally:
- self._teardown_test(test_name)
+ try:
+ self._teardown_test(test_name)
+ except signals.TestAbortAll:
+ raise
+ except Exception as e:
+ self.log.error(traceback.format_exc())
+ tr_record.add_error("teardown_test", e)
except (signals.TestFailure, AssertionError) as e:
+ self.log.error(traceback.format_exc())
tr_record.test_fail(e)
self._exec_procedure_func(self._on_fail, tr_record)
except signals.TestSkip as e:
@@ -348,6 +355,7 @@
is_generate_trigger = True
self.results.requested.remove(test_name)
except Exception as e:
+ self.log.error(traceback.format_exc())
# Exception happened during test.
tr_record.test_unknown(e)
self._exec_procedure_func(self._on_exception, tr_record)
diff --git a/acts/framework/acts/records.py b/acts/framework/acts/records.py
index 0a09b387..dce3faf 100644
--- a/acts/framework/acts/records.py
+++ b/acts/framework/acts/records.py
@@ -87,6 +87,8 @@
"""
self.end_time = utils.get_current_epoch_time()
self.result = result
+ if self.extra_errors:
+ self.result = TestResultEnums.TEST_RESULT_UNKNOWN
if isinstance(e, signals.TestSignal):
self.details = e.details
self.extras = e.extras
diff --git a/acts/framework/tests/acts_base_class_test.py b/acts/framework/tests/acts_base_class_test.py
index 12d57b9..a42443b 100755
--- a/acts/framework/tests/acts_base_class_test.py
+++ b/acts/framework/tests/acts_base_class_test.py
@@ -212,12 +212,12 @@
pass
bt_cls = MockBaseTest(self.mock_test_cls_configs)
bt_cls.run()
- actual_record = bt_cls.results.failed[0]
+ actual_record = bt_cls.results.unknown[0]
self.assertEqual(actual_record.test_name, self.mock_test_name)
- self.assertEqual(actual_record.details, MSG_EXPECTED_EXCEPTION)
+ self.assertIsNone(actual_record.details)
self.assertIsNone(actual_record.extras)
- expected_summary = ("Executed 1, Failed 1, Passed 0, Requested 1, "
- "Skipped 0, Unknown 0")
+ expected_summary = ("Executed 1, Failed 0, Passed 0, Requested 1, "
+ "Skipped 0, Unknown 1")
self.assertEqual(bt_cls.results.summary_str(), expected_summary)
def test_teardown_test_raise_exception(self):
@@ -230,12 +230,50 @@
bt_cls.run()
actual_record = bt_cls.results.unknown[0]
self.assertEqual(actual_record.test_name, self.mock_test_name)
- self.assertEqual(actual_record.details, MSG_EXPECTED_EXCEPTION)
+ self.assertIsNone(actual_record.details)
self.assertIsNone(actual_record.extras)
expected_summary = ("Executed 1, Failed 0, Passed 0, Requested 1, "
"Skipped 0, Unknown 1")
self.assertEqual(bt_cls.results.summary_str(), expected_summary)
+ def test_both_teardown_and_test_body_raise_exceptions(self):
+ class MockBaseTest(base_test.BaseTestClass):
+ def teardown_test(self):
+ asserts.assert_true(False, MSG_EXPECTED_EXCEPTION)
+ def test_something(self):
+ raise Exception("Test Body Exception.")
+ bt_cls = MockBaseTest(self.mock_test_cls_configs)
+ bt_cls.run()
+ actual_record = bt_cls.results.unknown[0]
+ self.assertEqual(actual_record.test_name, self.mock_test_name)
+ self.assertEqual(actual_record.details, "Test Body Exception.")
+ self.assertIsNone(actual_record.extras)
+ self.assertEqual(actual_record.extra_errors["teardown_test"],
+ "Details=This is an expected exception., Extras=None")
+ expected_summary = ("Executed 1, Failed 0, Passed 0, Requested 1, "
+ "Skipped 0, Unknown 1")
+ self.assertEqual(bt_cls.results.summary_str(), expected_summary)
+
+ def test_explicit_pass_but_teardown_test_raises_an_exception(self):
+ """Test record result should be marked as UNKNOWN as opposed to PASS.
+ """
+ class MockBaseTest(base_test.BaseTestClass):
+ def teardown_test(self):
+ asserts.assert_true(False, MSG_EXPECTED_EXCEPTION)
+ def test_something(self):
+ asserts.explicit_pass("Test Passed!")
+ bt_cls = MockBaseTest(self.mock_test_cls_configs)
+ bt_cls.run()
+ actual_record = bt_cls.results.unknown[0]
+ self.assertEqual(actual_record.test_name, self.mock_test_name)
+ self.assertEqual(actual_record.details, "Test Passed!")
+ self.assertIsNone(actual_record.extras)
+ self.assertEqual(actual_record.extra_errors["teardown_test"],
+ "Details=This is an expected exception., Extras=None")
+ expected_summary = ("Executed 1, Failed 0, Passed 0, Requested 1, "
+ "Skipped 0, Unknown 1")
+ self.assertEqual(bt_cls.results.summary_str(), expected_summary)
+
def test_on_pass_raise_exception(self):
class MockBaseTest(base_test.BaseTestClass):
def on_pass(self, test_name, begin_time):