未验证 提交 b45e2c53 编写于 作者: C Cleber Rosa

Merge remote-tracking branch 'ldoktor/loader-failures'

Signed-off-by: NCleber Rosa <crosa@redhat.com>
...@@ -75,17 +75,6 @@ class TestError(TestBaseException): ...@@ -75,17 +75,6 @@ class TestError(TestBaseException):
status = "ERROR" status = "ERROR"
class NotATestError(TestBaseException):
"""
Indicates that the file is not a test.
Causes: Non executable, non python file or python module without
an avocado test class in it.
"""
status = "NOT_A_TEST"
class TestNotFoundError(TestBaseException): class TestNotFoundError(TestBaseException):
""" """
......
...@@ -43,6 +43,12 @@ AVAILABLE = None ...@@ -43,6 +43,12 @@ AVAILABLE = None
ALL = True ALL = True
class MissingTest(object):
"""
Class representing reference which failed to be discovered
"""
def filter_test_tags(test_suite, filter_by_tags, include_empty=False): def filter_test_tags(test_suite, filter_by_tags, include_empty=False):
""" """
Filter the existing (unfiltered) test suite based on tags Filter the existing (unfiltered) test suite based on tags
...@@ -209,10 +215,10 @@ class TestLoaderProxy(object): ...@@ -209,10 +215,10 @@ class TestLoaderProxy(object):
Update the mappings according the current initialized plugins Update the mappings according the current initialized plugins
""" """
# Plugins are initialized, let's update mappings # Plugins are initialized, let's update mappings
self._label_mapping = {test.MissingTest: "MISSING"} self._label_mapping = {MissingTest: "MISSING"}
for plugin in self._initialized_plugins: for plugin in self._initialized_plugins:
self._label_mapping.update(plugin.get_type_label_mapping()) self._label_mapping.update(plugin.get_type_label_mapping())
self._decorator_mapping = {test.MissingTest: self._decorator_mapping = {MissingTest:
output.TERM_SUPPORT.fail_header_str} output.TERM_SUPPORT.fail_header_str}
for plugin in self._initialized_plugins: for plugin in self._initialized_plugins:
self._decorator_mapping.update(plugin.get_decorator_mapping()) self._decorator_mapping.update(plugin.get_decorator_mapping())
...@@ -275,7 +281,7 @@ class TestLoaderProxy(object): ...@@ -275,7 +281,7 @@ class TestLoaderProxy(object):
unhandled_references.append(reference) unhandled_references.append(reference)
if unhandled_references: if unhandled_references:
if which_tests: if which_tests:
tests.extend([(test.MissingTest, {'name': reference}) tests.extend([(MissingTest, {'name': reference})
for reference in unhandled_references]) for reference in unhandled_references])
else: else:
raise LoaderUnhandledReferenceError(unhandled_references, raise LoaderUnhandledReferenceError(unhandled_references,
...@@ -453,6 +459,12 @@ def add_loader_options(parser): ...@@ -453,6 +459,12 @@ def add_loader_options(parser):
'run tests from files')) 'run tests from files'))
class NotATest(object):
"""
Class representing something that is not a test
"""
class FileLoader(TestLoader): class FileLoader(TestLoader):
""" """
...@@ -460,6 +472,8 @@ class FileLoader(TestLoader): ...@@ -460,6 +472,8 @@ class FileLoader(TestLoader):
""" """
name = 'file' name = 'file'
__not_test_str = (": Does not look like an INSTRUMENTED test, nor is "
"it executable")
def __init__(self, args, extra_params): def __init__(self, args, extra_params):
test_type = extra_params.pop('allowed_test_types', None) test_type = extra_params.pop('allowed_test_types', None)
...@@ -469,8 +483,8 @@ class FileLoader(TestLoader): ...@@ -469,8 +483,8 @@ class FileLoader(TestLoader):
@staticmethod @staticmethod
def get_type_label_mapping(): def get_type_label_mapping():
return {test.SimpleTest: 'SIMPLE', return {test.SimpleTest: 'SIMPLE',
test.NotATest: 'NOT_A_TEST', NotATest: 'NOT_A_TEST',
test.MissingTest: 'MISSING', MissingTest: 'MISSING',
BrokenSymlink: 'BROKEN_SYMLINK', BrokenSymlink: 'BROKEN_SYMLINK',
AccessDeniedPath: 'ACCESS_DENIED', AccessDeniedPath: 'ACCESS_DENIED',
test.Test: 'INSTRUMENTED'} test.Test: 'INSTRUMENTED'}
...@@ -478,8 +492,8 @@ class FileLoader(TestLoader): ...@@ -478,8 +492,8 @@ class FileLoader(TestLoader):
@staticmethod @staticmethod
def get_decorator_mapping(): def get_decorator_mapping():
return {test.SimpleTest: output.TERM_SUPPORT.healthy_str, return {test.SimpleTest: output.TERM_SUPPORT.healthy_str,
test.NotATest: output.TERM_SUPPORT.warn_header_str, NotATest: output.TERM_SUPPORT.warn_header_str,
test.MissingTest: output.TERM_SUPPORT.fail_header_str, MissingTest: output.TERM_SUPPORT.fail_header_str,
BrokenSymlink: output.TERM_SUPPORT.fail_header_str, BrokenSymlink: output.TERM_SUPPORT.fail_header_str,
AccessDeniedPath: output.TERM_SUPPORT.fail_header_str, AccessDeniedPath: output.TERM_SUPPORT.fail_header_str,
test.Test: output.TERM_SUPPORT.healthy_str} test.Test: output.TERM_SUPPORT.healthy_str}
...@@ -705,7 +719,8 @@ class FileLoader(TestLoader): ...@@ -705,7 +719,8 @@ class FileLoader(TestLoader):
else: else:
# Module does not have an avocado test class inside, and # Module does not have an avocado test class inside, and
# it's not executable. Not a Test. # it's not executable. Not a Test.
return make_broken(test.NotATest, test_path) return make_broken(NotATest,
test_path + self.__not_test_str)
# Since a lot of things can happen here, the broad exception is # Since a lot of things can happen here, the broad exception is
# justified. The user will get it unadulterated anyway, and avocado # justified. The user will get it unadulterated anyway, and avocado
...@@ -718,7 +733,7 @@ class FileLoader(TestLoader): ...@@ -718,7 +733,7 @@ class FileLoader(TestLoader):
# execute it. # execute it.
return self._make_test(test.SimpleTest, test_path) return self._make_test(test.SimpleTest, test_path)
else: else:
return make_broken(test.NotATest, test_path) return make_broken(NotATest, test_path + self.__not_test_str)
@staticmethod @staticmethod
def _make_test(klass, uid): def _make_test(klass, uid):
...@@ -747,7 +762,8 @@ class FileLoader(TestLoader): ...@@ -747,7 +762,8 @@ class FileLoader(TestLoader):
test_name = test_path test_name = test_path
if os.path.exists(test_path): if os.path.exists(test_path):
if os.access(test_path, os.R_OK) is False: if os.access(test_path, os.R_OK) is False:
return make_broken(AccessDeniedPath, test_path) return make_broken(AccessDeniedPath, test_path + ": Is not "
"readable")
path_analyzer = path.PathInspector(test_path) path_analyzer = path.PathInspector(test_path)
if path_analyzer.is_python(): if path_analyzer.is_python():
return self._make_avocado_tests(test_path, make_broken, return self._make_avocado_tests(test_path, make_broken,
...@@ -757,14 +773,17 @@ class FileLoader(TestLoader): ...@@ -757,14 +773,17 @@ class FileLoader(TestLoader):
return self._make_test(test.SimpleTest, return self._make_test(test.SimpleTest,
test_path) test_path)
else: else:
return make_broken(test.NotATest, test_path) return make_broken(NotATest,
test_path + self.__not_test_str)
else: else:
if os.path.islink(test_path): if os.path.islink(test_path):
try: try:
if not os.path.isfile(os.readlink(test_path)): if not os.path.isfile(os.readlink(test_path)):
return make_broken(BrokenSymlink, test_path) return make_broken(BrokenSymlink, test_path + ": Is "
"a broken symlink")
except OSError: except OSError:
return make_broken(AccessDeniedPath, test_path) return make_broken(AccessDeniedPath, test_path + ": Is "
"not accessible.")
# Try to resolve test ID (keep compatibility) # Try to resolve test ID (keep compatibility)
test_path = os.path.join(data_dir.get_test_dir(), test_name) test_path = os.path.join(data_dir.get_test_dir(), test_name)
...@@ -781,7 +800,7 @@ class FileLoader(TestLoader): ...@@ -781,7 +800,7 @@ class FileLoader(TestLoader):
return self._make_avocado_tests(test_path, make_broken, return self._make_avocado_tests(test_path, make_broken,
subtests_filter, subtests_filter,
test_name) test_name)
return make_broken(test.MissingTest, test_name) return make_broken(NotATest, test_name + self.__not_test_str)
class ExternalLoader(TestLoader): class ExternalLoader(TestLoader):
......
...@@ -561,6 +561,10 @@ class Paginator(object): ...@@ -561,6 +561,10 @@ class Paginator(object):
except Exception: except Exception:
pass pass
def flush(self):
if not self.pipe.closed:
self.pipe.flush()
def add_log_handler(logger, klass=logging.StreamHandler, stream=sys.stdout, def add_log_handler(logger, klass=logging.StreamHandler, stream=sys.stdout,
level=logging.INFO, fmt='%(name)s: %(message)s'): level=logging.INFO, fmt='%(name)s: %(message)s'):
......
...@@ -931,34 +931,6 @@ class ExternalRunnerTest(SimpleTest): ...@@ -931,34 +931,6 @@ class ExternalRunnerTest(SimpleTest):
os.chdir(pre_cwd) os.chdir(pre_cwd)
class MissingTest(Test):
"""
Handle when there is no such test module in the test directory.
"""
def test(self):
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)
class NotATest(Test):
"""
The file is not a test.
Either a non executable python module with no avocado test class in it,
or a regular, non executable file.
"""
def test(self):
e_msg = ('File %s is not executable and does not contain an avocado '
'test class in it ' % self.name)
raise exceptions.NotATestError(e_msg)
class MockingTest(Test): class MockingTest(Test):
""" """
......
...@@ -67,6 +67,13 @@ class RobotTest(test.SimpleTest): ...@@ -67,6 +67,13 @@ class RobotTest(test.SimpleTest):
'non-0 exit code (%s)' % result) 'non-0 exit code (%s)' % result)
class NotRobotTest(object):
"""
Not a robot test (for reporting purposes)
"""
class RobotLoader(loader.TestLoader): class RobotLoader(loader.TestLoader):
""" """
Robot loader class Robot loader class
...@@ -91,7 +98,9 @@ class RobotLoader(loader.TestLoader): ...@@ -91,7 +98,9 @@ class RobotLoader(loader.TestLoader):
source=url, source=url,
include_suites=SuiteNamePatterns()) include_suites=SuiteNamePatterns())
robot_suite = self._find_tests(test_data, test_suite={}) robot_suite = self._find_tests(test_data, test_suite={})
except DataError: except Exception as data:
if which_tests == loader.ALL:
return [(NotRobotTest, {"name": "%s: %s" % (url, data)})]
return [] return []
for item in robot_suite: for item in robot_suite:
...@@ -102,6 +111,9 @@ class RobotLoader(loader.TestLoader): ...@@ -102,6 +111,9 @@ class RobotLoader(loader.TestLoader):
if subtests_filter and not subtests_filter.search(test_name): if subtests_filter and not subtests_filter.search(test_name):
continue continue
avocado_suite.append((RobotTest, {'name': test_name})) avocado_suite.append((RobotTest, {'name': test_name}))
if which_tests is loader.ALL and not avocado_suite:
return [(NotRobotTest, {"name": "%s: No robot-like tests found"
% url})]
return avocado_suite return avocado_suite
def _find_tests(self, data, test_suite): def _find_tests(self, data, test_suite):
...@@ -115,11 +127,13 @@ class RobotLoader(loader.TestLoader): ...@@ -115,11 +127,13 @@ class RobotLoader(loader.TestLoader):
@staticmethod @staticmethod
def get_type_label_mapping(): def get_type_label_mapping():
return {RobotTest: 'ROBOT'} return {RobotTest: 'ROBOT',
NotRobotTest: "!ROBOT"}
@staticmethod @staticmethod
def get_decorator_mapping(): def get_decorator_mapping():
return {RobotTest: output.TERM_SUPPORT.healthy_str} return {RobotTest: output.TERM_SUPPORT.healthy_str,
NotRobotTest: output.TERM_SUPPORT.fail_header_str}
class RobotCLI(CLI): class RobotCLI(CLI):
......
...@@ -5,7 +5,6 @@ import tempfile ...@@ -5,7 +5,6 @@ import tempfile
import unittest import unittest
from avocado.core import test from avocado.core import test
from avocado.core import exceptions
from avocado.core import loader from avocado.core import loader
from avocado.utils import script from avocado.utils import script
...@@ -235,13 +234,8 @@ class LoaderTest(unittest.TestCase): ...@@ -235,13 +234,8 @@ class LoaderTest(unittest.TestCase):
'avocado_loader_unittest', 'avocado_loader_unittest',
mode=DEFAULT_NON_EXEC_MODE) mode=DEFAULT_NON_EXEC_MODE)
simple_test.save() simple_test.save()
test_class, test_parameters = ( test_class, _ = self.loader.discover(simple_test.path, loader.ALL)[0]
self.loader.discover(simple_test.path, loader.ALL)[0]) self.assertTrue(test_class == loader.NotATest, test_class)
self.assertTrue(test_class == test.NotATest, test_class)
test_parameters['name'] = test.TestName(0, test_parameters['name'])
test_parameters['base_logdir'] = self.tmpdir
tc = test_class(**test_parameters)
self.assertRaises(exceptions.NotATestError, tc.test)
simple_test.remove() simple_test.remove()
def test_load_pass(self): def test_load_pass(self):
...@@ -249,8 +243,8 @@ class LoaderTest(unittest.TestCase): ...@@ -249,8 +243,8 @@ class LoaderTest(unittest.TestCase):
AVOCADO_TEST_OK, AVOCADO_TEST_OK,
'avocado_loader_unittest') 'avocado_loader_unittest')
avocado_pass_test.save() avocado_pass_test.save()
test_class, test_parameters = ( test_class, _ = self.loader.discover(avocado_pass_test.path,
self.loader.discover(avocado_pass_test.path, loader.ALL)[0]) loader.ALL)[0]
self.assertTrue(test_class == 'PassTest', test_class) self.assertTrue(test_class == 'PassTest', test_class)
avocado_pass_test.remove() avocado_pass_test.remove()
...@@ -260,13 +254,9 @@ class LoaderTest(unittest.TestCase): ...@@ -260,13 +254,9 @@ class LoaderTest(unittest.TestCase):
'avocado_loader_unittest', 'avocado_loader_unittest',
mode=DEFAULT_NON_EXEC_MODE) mode=DEFAULT_NON_EXEC_MODE)
avocado_not_a_test.save() avocado_not_a_test.save()
test_class, test_parameters = ( test_class, _ = self.loader.discover(avocado_not_a_test.path,
self.loader.discover(avocado_not_a_test.path, loader.ALL)[0]) loader.ALL)[0]
self.assertTrue(test_class == test.NotATest, test_class) self.assertTrue(test_class == loader.NotATest, test_class)
test_parameters['name'] = test.TestName(0, test_parameters['name'])
test_parameters['base_logdir'] = self.tmpdir
tc = test_class(**test_parameters)
self.assertRaises(exceptions.NotATestError, tc.test)
avocado_not_a_test.remove() avocado_not_a_test.remove()
def test_load_not_a_test_exec(self): def test_load_not_a_test_exec(self):
...@@ -304,13 +294,9 @@ class LoaderTest(unittest.TestCase): ...@@ -304,13 +294,9 @@ class LoaderTest(unittest.TestCase):
'avocado_loader_unittest', 'avocado_loader_unittest',
mode=DEFAULT_NON_EXEC_MODE) mode=DEFAULT_NON_EXEC_MODE)
avocado_simple_test.save() avocado_simple_test.save()
test_class, test_parameters = ( test_class, _ = self.loader.discover(avocado_simple_test.path,
self.loader.discover(avocado_simple_test.path, loader.ALL)[0]) loader.ALL)[0]
self.assertTrue(test_class == test.NotATest) self.assertTrue(test_class == loader.NotATest)
test_parameters['name'] = test.TestName(0, test_parameters['name'])
test_parameters['base_logdir'] = self.tmpdir
tc = test_class(**test_parameters)
self.assertRaises(exceptions.NotATestError, tc.test)
avocado_simple_test.remove() avocado_simple_test.remove()
def test_multiple_methods(self): def test_multiple_methods(self):
...@@ -373,7 +359,7 @@ class LoaderTest(unittest.TestCase): ...@@ -373,7 +359,7 @@ class LoaderTest(unittest.TestCase):
avocado_pass_test.save() avocado_pass_test.save()
test_class, test_parameters = ( test_class, test_parameters = (
self.loader.discover(avocado_pass_test.path, loader.ALL)[0]) self.loader.discover(avocado_pass_test.path, loader.ALL)[0])
self.assertTrue(test_class == test.NotATest) self.assertTrue(test_class == loader.NotATest)
avocado_pass_test.remove() avocado_pass_test.remove()
def test_load_tagged_nested(self): def test_load_tagged_nested(self):
...@@ -382,10 +368,9 @@ class LoaderTest(unittest.TestCase): ...@@ -382,10 +368,9 @@ class LoaderTest(unittest.TestCase):
'avocado_loader_unittest', 'avocado_loader_unittest',
DEFAULT_NON_EXEC_MODE) DEFAULT_NON_EXEC_MODE)
avocado_nested_test.save() avocado_nested_test.save()
test_class, test_parameters = ( test_class, _ = self.loader.discover(avocado_nested_test.path,
self.loader.discover(avocado_nested_test.path, loader.ALL)[0]) loader.ALL)[0]
results = self.loader.discover(avocado_nested_test.path, loader.ALL) self.assertTrue(test_class == loader.NotATest)
self.assertTrue(test_class == test.NotATest)
avocado_nested_test.remove() avocado_nested_test.remove()
def test_load_multiple_imports(self): def test_load_multiple_imports(self):
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册