Skip to content

Commit

Permalink
Merge remote-tracking branch 'lmr/virt-test-compat-layer-v12'
Browse files Browse the repository at this point in the history
  • Loading branch information
clebergnu committed Jun 5, 2015
2 parents bd9c9dd + bd43ca9 commit 3f661b6
Show file tree
Hide file tree
Showing 7 changed files with 300 additions and 126 deletions.
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ clean:
test -L avocado/virt && rm -f avocado/virt || true
test -L avocado/core/plugins/virt.py && rm -f avocado/core/plugins/virt.py || true
test -L avocado/core/plugins/virt_bootstrap.py && rm -f avocado/core/plugins/virt_bootstrap.py || true
test -L avocado/core/plugins/virt_test.py && rm -f avocado/core/plugins/virt_test.py || true
test -L avocado/core/plugins/virt_test_list.py && rm -f avocado/core/plugins/virt_test_list.py || true
test -L etc/avocado/conf.d/virt-test.conf && rm -f etc/avocado/conf.d/virt-test.conf || true

check:
selftests/checkall
Expand All @@ -73,6 +76,9 @@ link:
test -d ../avocado-virt/avocado/virt && ln -s ../../avocado-virt/avocado/virt avocado || true
test -f ../avocado-virt/avocado/core/plugins/virt.py && ln -s ../../../../avocado-virt/avocado/core/plugins/virt.py avocado/core/plugins/ || true
test -f ../avocado-virt/avocado/core/plugins/virt_bootstrap.py && ln -s ../../../../avocado-virt/avocado/core/plugins/virt_bootstrap.py avocado/core/plugins/ || true
test -f ../avocado-vt/etc/avocado/conf.d/virt-test.conf && ln -s ../../../../avocado-vt/etc/avocado/conf.d/virt-test.conf etc/avocado/conf.d/ || true
test -f ../avocado-vt/avocado/core/plugins/virt_test.py && ln -s ../../../../avocado-vt/avocado/core/plugins/virt_test.py avocado/core/plugins/ || true
test -f ../avocado-vt/avocado/core/plugins/virt_test_list.py && ln -s ../../../../avocado-vt/avocado/core/plugins/virt_test_list.py avocado/core/plugins/ || true

man: man/avocado.1 man/avocado-rest-client.1

Expand Down
8 changes: 8 additions & 0 deletions avocado/core/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,14 @@ class NotATestError(TestBaseException):
status = "NOT_A_TEST"


class TestNotFoundError(TestBaseException):

"""
Indicates that the test was not found in the test directory.
"""
status = "ERROR"


class TestTimeoutError(TestBaseException):

"""
Expand Down
19 changes: 10 additions & 9 deletions avocado/core/job.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ def __init__(self, args=None):
self.test_index = 1
self.status = "RUNNING"
self.result_proxy = result.TestResultProxy()
self.test_loader = loader.TestLoaderProxy()
self.sysinfo = None
self.timeout = getattr(self.args, 'job_timeout', 0)

Expand Down Expand Up @@ -148,12 +149,14 @@ def _remove_job_results(self):
shutil.rmtree(self.logdir, ignore_errors=True)

def _make_test_loader(self):
if hasattr(self.args, 'test_loader'):
test_loader_class = self.args.test_loader
else:
test_loader_class = loader.TestLoader

self.test_loader = test_loader_class(job=self)
for key in self.args.__dict__.keys():
if key.endswith('_loader'):
loader_class = getattr(self.args, key)
if issubclass(loader_class, loader.TestLoader):
loader_plugin = loader_class(self)
self.test_loader.add_loader_plugin(loader_plugin)
filesystem_loader = loader.TestLoader(self)
self.test_loader.add_loader_plugin(filesystem_loader)

def _make_test_runner(self):
if hasattr(self.args, 'test_runner'):
Expand Down Expand Up @@ -252,9 +255,7 @@ def _make_test_suite(self, urls=None):

self._make_test_loader()

params_list = self.test_loader.discover_urls(urls)
test_suite = self.test_loader.discover(params_list)
return test_suite
return self.test_loader.discover(urls)

def _validate_test_suite(self, test_suite):
try:
Expand Down
153 changes: 150 additions & 3 deletions avocado/core/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from avocado import test
from avocado import data_dir
from avocado.utils import path
from avocado.core import output

try:
import cStringIO as StringIO
Expand All @@ -35,8 +36,9 @@

class _DebugJob(object):

def __init__(self):
def __init__(self, args=None):
self.logdir = '.'
self.args = args


class BrokenSymlink(object):
Expand All @@ -47,17 +49,162 @@ class AccessDeniedPath(object):
pass


class InvalidLoaderPlugin(Exception):
pass


class TestLoaderProxy(object):

def __init__(self):
self.loader_plugins = []
self.url_plugin_mapping = {}

def add_loader_plugin(self, plugin):
if not isinstance(plugin, TestLoader):
raise InvalidLoaderPlugin("Object %s is not an instance of "
"TestLoader" % plugin)
self.loader_plugins.append(plugin)

def load_plugins(self, args):
for key in args.__dict__.keys():
if key.endswith('_loader'):
loader_class = getattr(args, key)
if issubclass(loader_class, TestLoader):
loader_plugin = loader_class(args=args)
self.add_loader_plugin(loader_plugin)
filesystem_loader = TestLoader()
self.add_loader_plugin(filesystem_loader)

def get_extra_listing(self, args):
for loader_plugin in self.loader_plugins:
loader_plugin.get_extra_listing(args)

def get_base_keywords(self):
base_path = []
for loader_plugin in self.loader_plugins:
base_path += loader_plugin.get_base_keywords()
return base_path

def get_type_label_mapping(self):
mapping = {}
for loader_plugin in self.loader_plugins:
mapping.update(loader_plugin.get_type_label_mapping())
return mapping

def get_decorator_mapping(self):
mapping = {}
for loader_plugin in self.loader_plugins:
mapping.update(loader_plugin.get_decorator_mapping())
return mapping

def discover(self, urls, list_non_tests=False):
"""
Discover (possible) tests from test urls.
:param urls: a list of tests urls.
:type urls: list
:param list_non_tests: Whether to list non tests (for listing methods)
:type list_non_tests: bool
:return: A list of test factories (tuples (TestClass, test_params))
"""
test_factories = []
for url in urls:
for loader_plugin in self.loader_plugins:
try:
params_list_from_url = loader_plugin.discover_url(url)
if list_non_tests:
for params in params_list_from_url:
params['omit_non_tests'] = False
if params_list_from_url:
if url not in self.url_plugin_mapping:
self.url_plugin_mapping[url] = loader_plugin
if loader_plugin == self.url_plugin_mapping[url]:
test_factories += loader_plugin.discover(params_list_from_url)
except Exception:
continue
return test_factories

def validate_ui(self, test_suite, ignore_missing=False,
ignore_not_test=False, ignore_broken_symlinks=False,
ignore_access_denied=False):
e_msg = []
for tuple_class_params in test_suite:
for key in self.url_plugin_mapping:
if tuple_class_params[1]['params']['id'].startswith(key):
loader_plugin = self.url_plugin_mapping[key]
e_msg += loader_plugin.validate_ui(test_suite=[tuple_class_params], ignore_missing=ignore_missing,
ignore_not_test=ignore_not_test,
ignore_broken_symlinks=ignore_broken_symlinks,
ignore_access_denied=ignore_access_denied)
return e_msg

def load_test(self, test_factory):
"""
Load test from the test factory.
:param test_factory: a pair of test class and parameters.
:type params: tuple
:return: an instance of :class:`avocado.test.Testself`.
"""
test_class, test_parameters = test_factory
test_instance = test_class(**test_parameters)
return test_instance


class TestLoader(object):

"""
Test loader class.
"""

def __init__(self, job=None):
def __init__(self, job=None, args=None):

if job is None:
job = _DebugJob()
job = _DebugJob(args=args)
self.job = job

def get_extra_listing(self, args):
pass

def get_base_keywords(self):
"""
Get base keywords to locate tests (path to test dir in this case).
Used to list all tests available in virt-test.
:return: list with path strings.
"""
return [data_dir.get_test_dir()]

def get_type_label_mapping(self):
"""
Get label mapping for display in test listing.
:return: Dict {TestClass: 'TEST_LABEL_STRING'}
"""
return {test.SimpleTest: 'SIMPLE',
test.BuggyTest: 'BUGGY',
test.NotATest: 'NOT_A_TEST',
test.MissingTest: 'MISSING',
BrokenSymlink: 'BROKEN_SYMLINK',
AccessDeniedPath: 'ACCESS_DENIED',
test.Test: 'INSTRUMENTED'}

def get_decorator_mapping(self):
"""
Get label mapping for display in test listing.
:return: Dict {TestClass: decorator function}
"""
term_support = output.TermSupport()
return {test.SimpleTest: term_support.healthy_str,
test.BuggyTest: term_support.fail_header_str,
test.NotATest: term_support.warn_header_str,
test.MissingTest: term_support.fail_header_str,
BrokenSymlink: term_support.fail_header_str,
AccessDeniedPath: term_support.fail_header_str,
test.Test: term_support.healthy_str}

def _is_unittests_like(self, test_class, pattern='test'):
for name, _ in inspect.getmembers(test_class, inspect.ismethod):
if name.startswith(pattern):
Expand Down
20 changes: 10 additions & 10 deletions avocado/core/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,14 +403,14 @@ def cleanup(self):
if self.use_paginator:
self.paginator.close()

def notify(self, event='message', msg=None):
def notify(self, event='message', msg=None, skip_newline=False):
mapping = {'message': self._log_ui_header,
'minor': self._log_ui_minor,
'error': self._log_ui_error,
'warning': self._log_ui_warning,
'partial': self._log_ui_partial}
if msg is not None:
mapping[event](msg)
mapping[event](msg=msg, skip_newline=skip_newline)

def notify_progress(self, progress):
self._log_ui_throbber_progress(progress)
Expand Down Expand Up @@ -491,37 +491,37 @@ def _log_ui_partial(self, msg, skip_newline=False):
"""
self._log_ui_info(term_support.partial_str(msg), skip_newline)

def _log_ui_header(self, msg):
def _log_ui_header(self, msg, skip_newline=False):
"""
Log a header message.
:param msg: Message to write.
"""
self._log_ui_info(term_support.header_str(msg))
self._log_ui_info(term_support.header_str(msg), skip_newline)

def _log_ui_minor(self, msg):
def _log_ui_minor(self, msg, skip_newline=False):
"""
Log a minor message.
:param msg: Message to write.
"""
self._log_ui_info(msg)
self._log_ui_info(msg, skip_newline)

def _log_ui_error(self, msg):
def _log_ui_error(self, msg, skip_newline=False):
"""
Log an error message (useful for critical errors).
:param msg: Message to write.
"""
self._log_ui_error_base(term_support.fail_header_str(msg))
self._log_ui_error_base(term_support.fail_header_str(msg), skip_newline)

def _log_ui_warning(self, msg):
def _log_ui_warning(self, msg, skip_newline=False):
"""
Log a warning message (useful for warning messages).
:param msg: Message to write.
"""
self._log_ui_info(term_support.warn_header_str(msg))
self._log_ui_info(term_support.warn_header_str(msg), skip_newline)

def _log_ui_status_pass(self, t_elapsed):
"""
Expand Down

0 comments on commit 3f661b6

Please sign in to comment.