From 22737e276d2f7bd70064f723a3550250240a5609 Mon Sep 17 00:00:00 2001 From: Lucas Meneghel Rodrigues Date: Wed, 2 Apr 2014 11:11:51 -0300 Subject: [PATCH] avocado.job: Handle setup errors If we have an error at test setup stage, avocado will completely crash. This happens because the setup() method is not properly wrapped inside the avocado execution loop. So, trust exception handling to the job level, putting all test executions under a single try/except block with appropriate status and test attribute handling. Signed-off-by: Lucas Meneghel Rodrigues --- avocado/core/exceptions.py | 8 ++++++++ avocado/job.py | 41 ++++++++++++++++++++++++++++++-------- avocado/result.py | 1 + avocado/test.py | 29 --------------------------- 4 files changed, 42 insertions(+), 37 deletions(-) diff --git a/avocado/core/exceptions.py b/avocado/core/exceptions.py index 8481f57a..0ac735c4 100644 --- a/avocado/core/exceptions.py +++ b/avocado/core/exceptions.py @@ -11,6 +11,14 @@ class TestBaseException(Exception): status = "NEVER_RAISE_THIS" +class TestSetupFail(TestBaseException): + + """ + Indicates an error during a setup procedure. + """ + status = "FAIL" + + class TestError(TestBaseException): """ diff --git a/avocado/job.py b/avocado/job.py index a3da5cf5..6bdf6149 100644 --- a/avocado/job.py +++ b/avocado/job.py @@ -4,10 +4,13 @@ Class that describes a sequence of automated operations. import imp import logging import os +import sys import time +import traceback from avocado.core import data_dir from avocado.core import output +from avocado.core import exceptions from avocado import test from avocado import sysinfo from avocado import result @@ -84,14 +87,36 @@ class Job(object): :params test_instance: avocado.test.Test derived class instance. """ - sysinfo_logger = sysinfo.SysInfo(basedir=test_instance.sysinfodir) - test_instance.start_logging() - test_instance.setup() - sysinfo_logger.start_job_hook() - test_instance.run() - test_instance.cleanup() - test_instance.report() - test_instance.stop_logging() + start_time = time.time() + try: + sysinfo_logger = sysinfo.SysInfo(basedir=test_instance.sysinfodir) + test_instance.start_logging() + sysinfo_logger.start_job_hook() + try: + test_instance.setup() + except Exception, details: + raise exceptions.TestSetupFail(details) + test_instance.action() + test_instance.cleanup() + test_instance.status = 'PASS' + except exceptions.TestBaseException, detail: + test_instance.status = detail.status + test_instance.fail_reason = detail + except Exception, detail: + exc_type, exc_value, exc_traceback = sys.exc_info() + tb_info = traceback.format_exception(exc_type, exc_value, + exc_traceback.tb_next) + tb_info = "".join(tb_info) + for e_line in tb_info.splitlines(): + test_instance.log.error(e_line) + test_instance.status = 'FAIL' + test_instance.fail_reason = detail + finally: + end_time = time.time() + test_instance.time_elapsed = end_time - start_time + test_instance.report() + test_instance.stop_logging() + return test_instance def run_test(self, url): diff --git a/avocado/result.py b/avocado/result.py index d4b06e70..1b214585 100644 --- a/avocado/result.py +++ b/avocado/result.py @@ -70,6 +70,7 @@ class TestResult(object): 'Called once for a test to check status and report.' self.start_test(test) status_map = {'PASS': self.add_pass, + 'ERROR': self.add_fail, 'FAIL': self.add_fail, 'TEST_NA': self.add_skip, 'WARN': self.add_warn} diff --git a/avocado/test.py b/avocado/test.py index 1c9f3acc..b5d5f729 100644 --- a/avocado/test.py +++ b/avocado/test.py @@ -120,35 +120,6 @@ class Test(object): raise NotImplementedError('Test subclasses must implement an action ' 'method') - def run(self): - """ - Main test execution entry point. - - It'll run the action payload, taking into consideration profiling - requirements. After the test is done, it reports time and status. - """ - start_time = time.time() - try: - self.action() - self.status = 'PASS' - except exceptions.TestBaseException, detail: - self.status = detail.status - self.fail_reason = detail - except Exception, detail: - exc_type, exc_value, exc_traceback = sys.exc_info() - tb_info = traceback.format_exception(exc_type, exc_value, - exc_traceback.tb_next) - tb_info = "".join(tb_info) - for e_line in tb_info.splitlines(): - self.log.error(e_line) - self.status = 'FAIL' - self.fail_reason = detail - finally: - end_time = time.time() - self.time_elapsed = end_time - start_time - - return self.status == 'PASS' - def cleanup(self): """ Cleanup stage after the action is done. -- GitLab