diff --git a/avocado/core/exceptions.py b/avocado/core/exceptions.py index 74ad5e100120cf022311e5448df435f093d7de59..20edc123e2a951d4ba23e2801aa0c806ef3c19a8 100644 --- a/avocado/core/exceptions.py +++ b/avocado/core/exceptions.py @@ -75,6 +75,16 @@ class TestError(TestBaseException): status = "ERROR" +class TestNotFoundError(TestBaseException): + + """ + Indicates that the test was not found. + + Causes: non existing path or could not resolve alias. + """ + status = "NOT_FOUND" + + class TestTimeoutError(TestBaseException): """ diff --git a/avocado/core/output.py b/avocado/core/output.py index 8f9dc95353a99264a58ff8acf919bcd6b895831e..c61a325ca23822dceea5ddf7e6d737a223864460 100644 --- a/avocado/core/output.py +++ b/avocado/core/output.py @@ -100,6 +100,7 @@ class TermSupport(object): self.SKIP = self.COLOR_YELLOW self.FAIL = self.COLOR_RED self.ERROR = self.COLOR_RED + self.NOT_FOUND = self.COLOR_YELLOW self.WARN = self.COLOR_YELLOW self.ENDC = self.CONTROL_END term = os.environ.get("TERM") @@ -115,6 +116,7 @@ class TermSupport(object): self.SKIP = '' self.FAIL = '' self.ERROR = '' + self.NOT_FOUND = '' self.WARN = '' self.ENDC = '' @@ -168,12 +170,20 @@ class TermSupport(object): def error_str(self): """ - Print an error string (red colored). + Print a not found string (yellow colored). If the output does not support colors, just return the original string. """ return self.MOVE_BACK + self.ERROR + 'ERROR' + self.ENDC + def not_found_str(self): + """ + Print an error string (red colored). + + If the output does not support colors, just return the original string. + """ + return self.MOVE_BACK + self.NOT_FOUND + 'NOT_FOUND' + self.ENDC + def warn_str(self): """ Print an warning string (yellow colored). @@ -313,6 +323,15 @@ class OutputManager(object): normal_error_msg = term_support.error_str() + " (%.2f s)" % t_elapsed self.error(normal_error_msg) + def log_not_found(self, t_elapsed): + """ + Log a NOT_FOUND message. + + :param t_elapsed: Time it took for the operation to complete. + """ + normal_error_msg = term_support.not_found_str() + " (%.2f s)" % t_elapsed + self.error(normal_error_msg) + def log_fail(self, t_elapsed): """ Log a FAIL message. diff --git a/avocado/core/status.py b/avocado/core/status.py index d21fe2671bce874743dcfd16b5d4a550fe14afbb..045043428fa53bf7e44c4089871f692b87926356 100644 --- a/avocado/core/status.py +++ b/avocado/core/status.py @@ -19,6 +19,7 @@ a test or a job in avocado PASSed or FAILed. mapping = {"TEST_NA": True, "ABORT": False, "ERROR": False, + "NOT_FOUND": False, "FAIL": False, "WARN": False, "PASS": True, diff --git a/avocado/plugins/vm.py b/avocado/plugins/vm.py index 21782fa26600f14045b2c4babf280be496f5b19b..e123b6fd12ff0064480d9871651ddda868934b1b 100644 --- a/avocado/plugins/vm.py +++ b/avocado/plugins/vm.py @@ -196,19 +196,20 @@ class VMTestResult(TestResult): Called once before any tests are executed. """ TestResult.start_tests(self) - self.stream.log_header("TESTS: %s" % self.tests_total) + self.stream.log_header("TESTS : %s" % self.tests_total) def end_tests(self): """ Called once after all tests are executed. """ - self.stream.log_header("PASS : %d" % len(self.passed)) - self.stream.log_header("ERROR: %d" % len(self.errors)) - self.stream.log_header("FAIL : %d" % len(self.failed)) - self.stream.log_header("SKIP : %d" % len(self.skipped)) - self.stream.log_header("WARN : %d" % len(self.warned)) - self.stream.log_header("TIME : %.2f s" % self.total_time) - self.stream.log_header("DEBUG LOG: %s" % self.stream.logfile) + self.stream.log_header("PASS : %d" % len(self.passed)) + self.stream.log_header("ERROR : %d" % len(self.errors)) + self.stream.log_header("NOT FOUND : %d" % len(self.not_found)) + self.stream.log_header("FAIL : %d" % len(self.failed)) + self.stream.log_header("SKIP : %d" % len(self.skipped)) + self.stream.log_header("WARN : %d" % len(self.warned)) + self.stream.log_header("TIME : %.2f s" % self.total_time) + self.stream.log_header("JOB LOG : %s" % self.stream.logfile) def start_test(self, test): """ @@ -248,6 +249,15 @@ class VMTestResult(TestResult): TestResult.add_error(self, test) self.stream.log_error(test.time_elapsed) + def add_not_found(self, test): + """ + Called when a test had a setup error. + + :param test: :class:`avocado.test.Test` instance. + """ + TestResult.add_not_found(self, test) + self.stream.log_not_found(test.time_elapsed) + def add_fail(self, test): """ Called when a test fails. diff --git a/avocado/result.py b/avocado/result.py index ae65fcc35c0dd2043248536dbfde470de580c916..f28a4097b5e2232ee128ac3050d410fdabd84447 100644 --- a/avocado/result.py +++ b/avocado/result.py @@ -73,6 +73,10 @@ class TestResultProxy(object): for output_plugin in self.output_plugins: output_plugin.add_error(state) + def add_not_found(self, state): + for output_plugin in self.output_plugins: + output_plugin.add_not_found(state) + def add_fail(self, state): for output_plugin in self.output_plugins: output_plugin.add_fail(state) @@ -110,6 +114,7 @@ class TestResult(object): self.total_time = 0.0 self.passed = [] self.errors = [] + self.not_found = [] self.failed = [] self.skipped = [] self.warned = [] @@ -191,6 +196,17 @@ class TestResult(object): """ self.errors.append(state) + def add_not_found(self, state): + """ + Called when a test was not found. + + Causes: non existing path or could not resolve alias. + + :param state: result of :class:`avocado.test.Test.get_state`. + :type state: dict + """ + self.not_found.append(state) + def add_fail(self, state): """ Called when a test fails. @@ -225,6 +241,7 @@ class TestResult(object): """ status_map = {'PASS': self.add_pass, 'ERROR': self.add_error, + 'NOT_FOUND': self.add_not_found, 'FAIL': self.add_fail, 'TEST_NA': self.add_skip, 'WARN': self.add_warn} @@ -244,20 +261,21 @@ class HumanTestResult(TestResult): Called once before any tests are executed. """ TestResult.start_tests(self) - self.stream.log_header("JOB ID : %s" % self.stream.job_unique_id) - self.stream.log_header("JOB LOG: %s" % self.stream.logfile) - self.stream.log_header("TESTS : %s" % self.tests_total) + self.stream.log_header("JOB ID : %s" % self.stream.job_unique_id) + self.stream.log_header("JOB LOG : %s" % self.stream.logfile) + self.stream.log_header("TESTS : %s" % self.tests_total) def end_tests(self): """ Called once after all tests are executed. """ - self.stream.log_header("PASS : %d" % len(self.passed)) - self.stream.log_header("ERROR: %d" % len(self.errors)) - self.stream.log_header("FAIL : %d" % len(self.failed)) - self.stream.log_header("SKIP : %d" % len(self.skipped)) - self.stream.log_header("WARN : %d" % len(self.warned)) - self.stream.log_header("TIME : %.2f s" % self.total_time) + self.stream.log_header("PASS : %d" % len(self.passed)) + self.stream.log_header("ERROR : %d" % len(self.errors)) + self.stream.log_header("FAIL : %d" % len(self.failed)) + self.stream.log_header("SKIP : %d" % len(self.skipped)) + self.stream.log_header("WARN : %d" % len(self.warned)) + self.stream.log_header("NOT FOUND : %d" % len(self.not_found)) + self.stream.log_header("TIME : %.2f s" % self.total_time) def start_test(self, state): """ @@ -300,6 +318,16 @@ class HumanTestResult(TestResult): TestResult.add_error(self, state) self.stream.log_error(state['time_elapsed']) + def add_not_found(self, state): + """ + Called when a test was not found. + + :param state: result of :class:`avocado.test.Test.get_state`. + :type state: dict + """ + TestResult.add_not_found(self, state) + self.stream.log_not_found(state['time_elapsed']) + def add_fail(self, state): """ Called when a test fails. diff --git a/avocado/test.py b/avocado/test.py index 563497e9997c175d1cc927d68545626b2ac2ea82..970398b2727a84216e8f7dae11572bb1edf4aaa2 100644 --- a/avocado/test.py +++ b/avocado/test.py @@ -455,6 +455,7 @@ class MissingTest(Test): tag=tag, job=job) def action(self): - raise exceptions.TestError('Test %s could not be found in the test ' - 'dir %s' % - (self.name, data_dir.get_test_dir())) + e_msg = ('Test %s could not be found in the test dir %s' + '(or test path does not exist)' % + (self.name, data_dir.get_test_dir())) + raise exceptions.TestNotFoundError(e_msg) diff --git a/selftests/all/functional/avocado/basic_tests.py b/selftests/all/functional/avocado/basic_tests.py index 2b99d304f970c06ffa54c8e1ec30e78c7c6c522a..5906991fedaafb4428bce6e5d5534634bd32a62b 100644 --- a/selftests/all/functional/avocado/basic_tests.py +++ b/selftests/all/functional/avocado/basic_tests.py @@ -162,6 +162,15 @@ class RunnerOperationTest(unittest.TestCase): self.assertEqual(result.exit_status, expected_rc) self.assertIn(expected_output, result.stderr) + def test_not_found(self): + os.chdir(basedir) + cmd_line = './scripts/avocado run sbrubles' + result = process.run(cmd_line, ignore_status=True) + expected_rc = 1 + self.assertEqual(result.exit_status, expected_rc) + self.assertIn('NOT_FOUND', result.stderr) + self.assertIn('NOT FOUND : 1', result.stderr) + class RunnerDropinTest(unittest.TestCase): diff --git a/selftests/all/functional/avocado/multiplex_tests.py b/selftests/all/functional/avocado/multiplex_tests.py index 5e684a1dbe82aedff4e2c1ac56958f05b91258b3..54d1ee6f0c8fe01278a93301278c03969a38f543 100644 --- a/selftests/all/functional/avocado/multiplex_tests.py +++ b/selftests/all/functional/avocado/multiplex_tests.py @@ -45,7 +45,7 @@ class MultiplexTests(unittest.TestCase): output = result.stdout + result.stderr if expected_lines is not None: for line in output.splitlines(): - if 'JOB LOG:' in line: + if 'JOB LOG :' in line: debug_log = line.split()[-1] debug_log_obj = open(debug_log, 'r') job_log_lines = debug_log_obj.readlines()