From 7063d0a88e75b03ccaf3a3675e1fb2ce80762fb9 Mon Sep 17 00:00:00 2001 From: Jan Richter Date: Thu, 29 Aug 2024 17:31:55 +0200 Subject: [PATCH] Avocado instrumented timeout in setUp and tearDown fix This commit is a fix for avocado-instrumented timeouts. When the tests are interrupted due to timeout during `setUp` or `tearDown` method, those tests would result in `ERROR` instead of `INTERRUPTED`. This commit updates the exception handling of this method to fix this issue. Reference: #6013 Signed-off-by: Jan Richter --- avocado/core/test.py | 4 +-- examples/tests/timeouttest.py | 19 +++++------ selftests/check.py | 2 +- selftests/functional/basic.py | 64 +++++++++++++++++++++++++++++++++++ 4 files changed, 76 insertions(+), 13 deletions(-) diff --git a/avocado/core/test.py b/avocado/core/test.py index eb79e2960e..763cf705bb 100644 --- a/avocado/core/test.py +++ b/avocado/core/test.py @@ -585,7 +585,7 @@ def _run_test(self): self.__skip_test = True stacktrace.log_exc_info(sys.exc_info(), logger=self.log) raise exceptions.TestSkipError(details) - except exceptions.TestCancel: + except (exceptions.TestCancel, exceptions.TestInterrupt): stacktrace.log_exc_info(sys.exc_info(), logger=self.log) raise except: # Old-style exceptions are not inherited from Exception() @@ -633,7 +633,7 @@ def _tearDown(self): f"test. Original skip exception: {details}" ) raise exceptions.TestError(skip_illegal_msg) - except exceptions.TestCancel: + except (exceptions.TestCancel, exceptions.TestInterrupt): stacktrace.log_exc_info(sys.exc_info(), logger=self.log) raise except: # avoid old-style exception failures pylint: disable=W0702 diff --git a/examples/tests/timeouttest.py b/examples/tests/timeouttest.py index 2a5402c552..2c41eb46db 100644 --- a/examples/tests/timeouttest.py +++ b/examples/tests/timeouttest.py @@ -4,18 +4,17 @@ class TimeoutTest(Test): - """ - Functional test for avocado. Throw a TestTimeoutError. - - :param sleep_time: How long should the test sleep - """ timeout = 3 + def setUp(self): + sleep_time = float(self.params.get("sleep_time_setup", default=0.0)) + time.sleep(sleep_time) + def test(self): - """ - This should throw a TestTimeoutError. - """ - sleep_time = float(self.params.get("sleep_time", default=5.0)) - self.log.info("Sleeping for %.2f seconds (2 more than the timeout)", sleep_time) + sleep_time = float(self.params.get("sleep_time", default=0.0)) + time.sleep(sleep_time) + + def tearDown(self): + sleep_time = float(self.params.get("sleep_time_teardown", default=0.0)) time.sleep(sleep_time) diff --git a/selftests/check.py b/selftests/check.py index ea81932dfa..5fc19d20e0 100755 --- a/selftests/check.py +++ b/selftests/check.py @@ -29,7 +29,7 @@ "nrunner-requirement": 28, "unit": 678, "jobs": 11, - "functional-parallel": 307, + "functional-parallel": 309, "functional-serial": 7, "optional-plugins": 0, "optional-plugins-golang": 2, diff --git a/selftests/functional/basic.py b/selftests/functional/basic.py index cf47d72f10..9cb3e147d3 100644 --- a/selftests/functional/basic.py +++ b/selftests/functional/basic.py @@ -110,6 +110,28 @@ def test(self): fi """ +TIMEOUT_TEST = """import time + +from avocado import Test + + +class TimeoutTest(Test): + + timeout = 3 + + def setUp(self): + sleep_time = float(self.params.get("sleep_time_setup", default=0.0)) + time.sleep(sleep_time) + + def test(self): + sleep_time = float(self.params.get("sleep_time", default=0.0)) + time.sleep(sleep_time) + + def tearDown(self): + sleep_time = float(self.params.get("sleep_time_teardown", default=0.0)) + time.sleep(sleep_time) +""" + def probe_binary(binary): try: @@ -545,6 +567,48 @@ def test_runner_timeout_factor(self): ) self.assertNotIn("timeout", result_json["tests"][0]["fail_reason"]) + def test_runner_timeout_setup(self): + with script.TemporaryScript( + "timeout.py", + TIMEOUT_TEST, + ) as tst: + cmd_line = ( + f"{AVOCADO} run --disable-sysinfo --job-results-dir " + f"{self.tmpdir.name} -p sleep_time_setup=5 -- {tst}" + ) + result = process.run(cmd_line, ignore_status=True) + json_path = os.path.join(self.tmpdir.name, "latest", "results.json") + with open(json_path, encoding="utf-8") as json_file: + result_json = json.load(json_file) + expected_rc = exit_codes.AVOCADO_JOB_INTERRUPTED + self.assertEqual( + result.exit_status, + expected_rc, + f"Avocado did not return rc {expected_rc}:\n{result}", + ) + self.assertNotIn("timeout", result_json["tests"][0]["fail_reason"]) + + def test_runner_timeout_teardown(self): + with script.TemporaryScript( + "timeout.py", + TIMEOUT_TEST, + ) as tst: + cmd_line = ( + f"{AVOCADO} run --disable-sysinfo --job-results-dir " + f"{self.tmpdir.name} -p sleep_time_teardown=5 -- {tst}" + ) + result = process.run(cmd_line, ignore_status=True) + json_path = os.path.join(self.tmpdir.name, "latest", "results.json") + with open(json_path, encoding="utf-8") as json_file: + result_json = json.load(json_file) + expected_rc = exit_codes.AVOCADO_JOB_INTERRUPTED + self.assertEqual( + result.exit_status, + expected_rc, + f"Avocado did not return rc {expected_rc}:\n{result}", + ) + self.assertNotIn("timeout", result_json["tests"][0]["fail_reason"]) + def test_silent_output(self): cmd_line = ( f"{AVOCADO} --show=none run --disable-sysinfo "