提交 c9e11fa1 编写于 作者: L Lucas Meneghel Rodrigues

Merge pull request #722 from ldoktor/discover_url3

avocado.core.loader: Refactor the loader to be consistent [v3]
......@@ -114,7 +114,6 @@ class Job(object):
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)
......@@ -151,18 +150,6 @@ class Job(object):
def _remove_job_results(self):
shutil.rmtree(self.logdir, ignore_errors=True)
def _make_test_loader(self):
for key in self.args.__dict__.keys():
loader_class_candidate = getattr(self.args, key)
try:
if issubclass(loader_class_candidate, loader.TestLoader):
loader_plugin = loader_class_candidate(self)
self.test_loader.add_loader_plugin(loader_plugin)
except TypeError:
pass
filesystem_loader = loader.TestLoader(self)
self.test_loader.add_loader_plugin(filesystem_loader)
def _make_test_runner(self):
if hasattr(self.args, 'test_runner'):
test_runner_class = self.args.test_runner
......@@ -244,10 +231,6 @@ class Job(object):
if isinstance(urls, str):
urls = urls.split()
if not urls:
e_msg = "Empty test ID. A test path or alias must be provided"
raise exceptions.OptionValidationError(e_msg)
return urls
def _make_test_suite(self, urls=None):
......@@ -259,27 +242,15 @@ class Job(object):
:returns: a test suite (a list of test factories)
"""
urls = self._handle_urls(urls)
self._make_test_loader()
return self.test_loader.discover(urls)
def _validate_test_suite(self, test_suite):
loader.loader.load_plugins(self.args)
try:
# Do not attempt to validate the tests given on the command line if
# the tests will not be copied from this system to a remote one
# using the remote plugin features
if not getattr(self.args, 'remote_no_copy', False):
error_msg_parts = self.test_loader.validate_ui(test_suite)
else:
error_msg_parts = []
return loader.loader.discover(urls)
except loader.LoaderUnhandledUrlError, details:
self._remove_job_results()
raise exceptions.OptionValidationError(details)
except KeyboardInterrupt:
raise exceptions.JobError('Command interrupted by user...')
if error_msg_parts:
self._remove_job_results()
e_msg = '\n'.join(error_msg_parts)
raise exceptions.OptionValidationError(e_msg)
raise exceptions.JobError('Command interrupted by user...')
def _filter_test_suite(self, test_suite):
# Filter tests methods with params.filter and methodName
......@@ -441,14 +412,14 @@ class Job(object):
that configure a job failure.
"""
self._setup_job_results()
self.view.start_file_logging(self.logfile,
self.loglevel,
self.unique_id)
test_suite = self._make_test_suite(urls)
self._validate_test_suite(test_suite)
test_suite = self._filter_test_suite(test_suite)
if not test_suite:
e_msg = ("No tests found within the specified path(s) "
"(Possible reasons: File ownership, permissions, "
"filters, typos)")
self._remove_job_results()
e_msg = ("No tests found for given urls, try 'avocado list -V %s' "
"for details" % (" ".join(urls) if urls else "\b"))
raise exceptions.OptionValidationError(e_msg)
try:
......@@ -461,10 +432,6 @@ class Job(object):
self._make_test_runner()
self._start_sysinfo()
self.view.start_file_logging(self.logfile,
self.loglevel,
self.unique_id)
self._log_job_debug_info(mux)
self.view.logfile = self.logfile
......
此差异已折叠。
......@@ -78,6 +78,11 @@ DEFAULT_LOGGING = {
'level': 'INFO',
'propagate': False,
},
'avocado.app.tracebacks': {
'handlers': ['null'], # change this to 'error' to see tracebacks
'level': 'ERROR',
'propagate': False,
},
'avocado.test': {
'handlers': ['null'],
'level': 'DEBUG',
......
......@@ -421,7 +421,7 @@ class Mux(object):
i = None
for i, variant in enumerate(self.variants):
test_factory = [template[0], template[1].copy()]
inject_params = test_factory[1]['params'].get(
inject_params = test_factory[1].get('params', {}).get(
'avocado_inject_params', False)
# Test providers might want to keep their original params and
# only append avocado parameters to a special 'avocado_params'
......
......@@ -609,15 +609,17 @@ class View(object):
self.file_handler = logging.FileHandler(filename=logfile)
self.file_handler.setLevel(loglevel)
fmt = ('%(asctime)s %(module)-10.10s L%(lineno)-.4d %('
fmt = ('%(asctime)s %(module)-16.16s L%(lineno)-.4d %('
'levelname)-5.5s| %(message)s')
formatter = logging.Formatter(fmt=fmt, datefmt='%H:%M:%S')
self.file_handler.setFormatter(formatter)
test_logger = logging.getLogger('avocado.test')
linux_logger = logging.getLogger('avocado.linux')
test_logger.addHandler(self.file_handler)
linux_logger.addHandler(self.file_handler)
test_logger.setLevel(loglevel)
root_logger = logging.getLogger()
root_logger.addHandler(self.file_handler)
root_logger.setLevel(loglevel)
def stop_file_logging(self):
"""
......@@ -625,6 +627,8 @@ class View(object):
"""
test_logger = logging.getLogger('avocado.test')
linux_logger = logging.getLogger('avocado.linux')
root_logger = logging.getLogger()
test_logger.removeHandler(self.file_handler)
linux_logger.removeHandler(self.file_handler)
root_logger.removeHandler(self.file_handler)
self.file_handler.close()
......@@ -46,7 +46,7 @@ class TestRunner(plugin.Plugin):
'run',
help='Run one or more tests (native test, test alias, binary or script)')
self.parser.add_argument('url', type=str, default=[], nargs='+',
self.parser.add_argument('url', type=str, default=[], nargs='*',
help='List of test IDs (aliases or paths)')
self.parser.add_argument('-z', '--archive', action='store_true', default=False,
......
......@@ -32,38 +32,27 @@ class TestLister(object):
use_paginator = args.paginator == 'on'
self.view = output.View(app_args=args, use_paginator=use_paginator)
self.term_support = output.TermSupport()
self.test_loader = loader.TestLoaderProxy()
self.test_loader.load_plugins(args)
loader.loader.load_plugins(args)
self.args = args
def _extra_listing(self):
self.test_loader.get_extra_listing(self.args)
def _get_keywords(self):
keywords = self.test_loader.get_base_keywords()
if self.args.keywords:
keywords = self.args.keywords
return keywords
loader.loader.get_extra_listing()
def _get_test_suite(self, paths):
return self.test_loader.discover(paths, list_non_tests=self.args.verbose)
def _validate_test_suite(self, test_suite):
error_msg_parts = self.test_loader.validate_ui(test_suite,
ignore_not_test=True,
ignore_access_denied=True,
ignore_broken_symlinks=True)
if error_msg_parts:
for error_msg in error_msg_parts:
self.view.notify(event='error', msg=error_msg)
list_tests = loader.ALL if self.args.verbose else loader.AVAILABLE
try:
return loader.loader.discover(paths,
list_tests=list_tests)
except loader.LoaderUnhandledUrlError, details:
self.view.notify(event="error", msg=str(details))
self.view.cleanup()
sys.exit(exit_codes.AVOCADO_FAIL)
def _get_test_matrix(self, test_suite):
test_matrix = []
type_label_mapping = self.test_loader.get_type_label_mapping()
decorator_mapping = self.test_loader.get_decorator_mapping()
type_label_mapping = loader.loader.get_type_label_mapping()
decorator_mapping = loader.loader.get_decorator_mapping()
stats = {}
for value in type_label_mapping.values():
......@@ -115,7 +104,6 @@ class TestLister(object):
def _list(self):
self._extra_listing()
test_suite = self._get_test_suite(self.args.keywords)
self._validate_test_suite(test_suite)
test_matrix, stats = self._get_test_matrix(test_suite)
self._display(test_matrix, stats)
......
......@@ -30,6 +30,7 @@ from . import exceptions
from . import output
from . import status
from . import exit_codes
from .loader import loader
from ..utils import wait
from ..utils import stacktrace
from ..utils import runtime
......@@ -78,7 +79,7 @@ class TestRunner(object):
sys.stderr = output.LoggingFile(logger=logger_list_stderr)
try:
instance = self.job.test_loader.load_test(test_factory)
instance = loader.load_test(test_factory)
if instance.runner_queue is None:
instance.runner_queue = queue
runtime.CURRENT_TEST = instance
......@@ -261,6 +262,8 @@ class TestRunner(object):
deadline = None
for test_template in test_suite:
test_template[1]['base_logdir'] = self.job.logdir
test_template[1]['job'] = self.job
for test_factory in mux.itertests(test_template):
if deadline is not None and time.time() > deadline:
test_parameters = test_factory[1]
......
......@@ -17,6 +17,7 @@ This file contains tools for (not only) Avocado developers.
"""
import logging
import time
import os
# Use this for debug logging
......@@ -43,3 +44,49 @@ def measure_duration(func):
LOGGER.debug("PERF: %s: (%ss, %ss)", func, duration,
__MEASURE_DURATION[func])
return wrapper
def log_calls_class(length=None):
"""
Use this as decorator to log the function methods' calls.
:param length: Max message length
"""
def wrap(orig_cls):
for key, attr in orig_cls.__dict__.iteritems():
if callable(attr):
setattr(orig_cls, key,
_log_calls(attr, length, orig_cls.__name__))
return orig_cls
return wrap
def _log_calls(func, length=None, cls_name=None):
"""
log_calls wrapper function
"""
def wrapper(*args, **kwargs):
""" Wrapper function """
msg = ("CALL: %s:%s%s(%s, %s)"
% (os.path.relpath(func.func_code.co_filename),
cls_name, func.func_name,
", ".join([str(_) for _ in args]),
", ".join(["%s=%s" % (key, value)
for key, value in kwargs.iteritems()])))
if length:
msg = msg[:length]
LOGGER.debug(msg)
return func(*args, **kwargs)
if cls_name:
cls_name = cls_name + "."
return wrapper
def log_calls(length=None, cls_name=None):
"""
Use this as decorator to log the function call altogether with arguments.
:param length: Max message length
:param cls_name: Optional class name prefix
"""
def wrap(func):
return _log_calls(func, length, cls_name)
return wrap
......@@ -56,3 +56,6 @@ password =
# avocado.core.plugins.htmlresult ImportError No module named pystache
# add 'avocado.core.plugins.htmlresult' as an element of the list below.
skip_broken_plugin_notification = []
# Optionally you can specify the priority of loader plugins. Unspecified
# plugins will be sorted accordingly to the plugin priorities.
loader_plugins_priority = ['file']
......@@ -190,7 +190,7 @@ class RunnerOperationTest(unittest.TestCase):
cmd_line = './scripts/avocado run --sysinfo=off'
result = process.run(cmd_line, ignore_status=True)
expected_rc = 2
expected_output = 'too few arguments'
expected_output = 'No tests found for given urls'
self.assertEqual(result.exit_status, expected_rc)
self.assertIn(expected_output, result.stderr)
......@@ -200,8 +200,8 @@ class RunnerOperationTest(unittest.TestCase):
result = process.run(cmd_line, ignore_status=True)
expected_rc = 2
self.assertEqual(result.exit_status, expected_rc)
self.assertIn('File not found', result.stderr)
self.assertNotIn('File not found', result.stdout)
self.assertIn('Unable to discover url', result.stderr)
self.assertNotIn('Unable to discover url', result.stdout)
def test_invalid_unique_id(self):
cmd_line = './scripts/avocado run --sysinfo=off --force-job-id foobar passtest'
......@@ -411,7 +411,7 @@ class PluginsTest(unittest.TestCase):
self.assertEqual(result.exit_status, expected_rc,
"Avocado did not return rc %d:\n%s" %
(expected_rc, result))
self.assertIn("File not found", output)
self.assertIn("Unable to discover url", output)
def test_plugin_list(self):
os.chdir(basedir)
......
......@@ -63,100 +63,39 @@ true
class LoaderTestFunctional(unittest.TestCase):
def setUp(self):
os.chdir(basedir)
self.tmpdir = tempfile.mkdtemp()
def _test(self, name, content, exp_str, mode=0664):
test_script = script.TemporaryScript(name, content,
'avocado_loader_test',
mode=mode)
test_script.save()
cmd_line = ('./scripts/avocado list -V %s' % test_script.path)
result = process.run(cmd_line)
self.assertIn('%s: 1' % exp_str, result.stdout)
test_script.remove()
def test_simple(self):
os.chdir(basedir)
simple_test = script.TemporaryScript('simpletest.sh', SIMPLE_TEST,
'avocado_loader_test')
simple_test.save()
cmd_line = './scripts/avocado run --job-results-dir %s --sysinfo=off %s' % (self.tmpdir, simple_test.path)
process.run(cmd_line)
simple_test.remove()
self._test('simpletest.sh', SIMPLE_TEST, 'SIMPLE', 0775)
def test_simple_not_exec(self):
os.chdir(basedir)
simple_test = script.TemporaryScript('simpletest.sh', SIMPLE_TEST,
'avocado_loader_test',
mode=0664)
simple_test.save()
cmd_line = './scripts/avocado run --job-results-dir %s --sysinfo=off %s' % (self.tmpdir, simple_test.path)
result = process.run(cmd_line, ignore_status=True)
expected_rc = 2
self.assertEqual(result.exit_status, expected_rc,
"Avocado did not return rc %d:\n%s" %
(expected_rc, result))
self.assertIn('is not an avocado test', result.stderr)
self.assertNotIn('is not an avocado test', result.stdout)
simple_test.remove()
self._test('simpletest.sh', SIMPLE_TEST, 'NOT_A_TEST')
def test_pass(self):
avocado_pass_test = script.TemporaryScript('passtest.py',
AVOCADO_TEST_OK,
'avocado_loader_test')
avocado_pass_test.save()
cmd_line = './scripts/avocado run --job-results-dir %s --sysinfo=off %s' % (self.tmpdir, avocado_pass_test.path)
result = process.run(cmd_line, ignore_status=True)
expected_rc = 0
self.assertEqual(result.exit_status, expected_rc,
"Avocado did not return rc %d:\n%s" %
(expected_rc, result))
self._test('passtest.py', AVOCADO_TEST_OK, 'INSTRUMENTED')
def test_buggy_exec(self):
avocado_buggy_test = script.TemporaryScript('buggytest.py',
AVOCADO_TEST_BUGGY,
'avocado_loader_test')
avocado_buggy_test.save()
cmd_line = ('./scripts/avocado run --job-results-dir %s --sysinfo=off %s' %
(self.tmpdir, avocado_buggy_test.path))
result = process.run(cmd_line, ignore_status=True)
expected_rc = 1
self.assertEqual(result.exit_status, expected_rc,
"Avocado did not return rc %d:\n%s" %
(expected_rc, result))
self._test('buggytest.py', AVOCADO_TEST_BUGGY, 'SIMPLE', 0775)
def test_buggy_not_exec(self):
avocado_buggy_test = script.TemporaryScript('buggytest.py',
AVOCADO_TEST_BUGGY,
'avocado_loader_test',
mode=0664)
avocado_buggy_test.save()
cmd_line = ('./scripts/avocado run --job-results-dir %s --sysinfo=off %s' %
(self.tmpdir, avocado_buggy_test.path))
result = process.run(cmd_line, ignore_status=True)
expected_rc = 1
self.assertEqual(result.exit_status, expected_rc,
"Avocado did not return rc %d:\n%s" %
(expected_rc, result))
avocado_buggy_test.remove()
self._test('buggytest.py', AVOCADO_TEST_BUGGY, 'BUGGY')
def test_load_not_a_test(self):
avocado_not_a_test = script.TemporaryScript('notatest.py', NOT_A_TEST,
'avocado_loader_test')
avocado_not_a_test.save()
cmd_line = ('./scripts/avocado run --job-results-dir %s --sysinfo=off %s' %
(self.tmpdir, avocado_not_a_test.path))
result = process.run(cmd_line, ignore_status=True)
expected_rc = 1
self.assertEqual(result.exit_status, expected_rc,
"Avocado did not return rc %d:\n%s" %
(expected_rc, result))
avocado_not_a_test.remove()
self._test('notatest.py', NOT_A_TEST, 'SIMPLE', 0775)
def test_load_not_a_test_not_exec(self):
avocado_not_a_test = script.TemporaryScript('notatest.py', NOT_A_TEST,
'avocado_loader_test',
mode=0664)
avocado_not_a_test.save()
cmd_line = ('./scripts/avocado run --job-results-dir %s --sysinfo=off %s' %
(self.tmpdir, avocado_not_a_test.path))
result = process.run(cmd_line, ignore_status=True)
expected_rc = 2
self.assertEqual(result.exit_status, expected_rc,
"Avocado did not return rc %d:\n%s" %
(expected_rc, result))
self.assertIn('is not an avocado test', result.stderr)
avocado_not_a_test.remove()
self._test('notatest.py', NOT_A_TEST, 'NOT_A_TEST')
def tearDown(self):
shutil.rmtree(self.tmpdir)
......
......@@ -17,6 +17,7 @@ from avocado.core import exceptions
from avocado.core import loader
from avocado.utils import script
# We need to access protected members pylint: disable=W0212
AVOCADO_TEST_OK = """#!/usr/bin/python
from avocado import Test
......@@ -84,15 +85,10 @@ class MultipleMethods(Test):
"""
class _DebugJob(object):
logdir = tempfile.mkdtemp()
class LoaderTest(unittest.TestCase):
def setUp(self):
self.job = _DebugJob
self.loader = loader.TestLoader(job=self.job)
self.loader = loader.FileLoader({})
self.queue = multiprocessing.Queue()
def test_load_simple(self):
......@@ -100,7 +96,7 @@ class LoaderTest(unittest.TestCase):
'avocado_loader_unittest')
simple_test.save()
test_class, test_parameters = (
self.loader.discover_tests(params={'id': simple_test.path})[0])
self.loader.discover(simple_test.path, True)[0])
self.assertTrue(test_class == test.SimpleTest, test_class)
tc = test_class(**test_parameters)
tc.test()
......@@ -112,7 +108,7 @@ class LoaderTest(unittest.TestCase):
mode=0664)
simple_test.save()
test_class, test_parameters = (
self.loader.discover_tests(params={'id': simple_test.path})[0])
self.loader.discover(simple_test.path, True)[0])
self.assertTrue(test_class == test.NotATest, test_class)
tc = test_class(**test_parameters)
self.assertRaises(exceptions.NotATestError, tc.test)
......@@ -124,7 +120,7 @@ class LoaderTest(unittest.TestCase):
'avocado_loader_unittest')
avocado_pass_test.save()
test_class, test_parameters = (
self.loader.discover_tests(params={'id': avocado_pass_test.path})[0])
self.loader.discover(avocado_pass_test.path, True)[0])
self.assertTrue(str(test_class) == "<class 'passtest.PassTest'>",
str(test_class))
self.assertTrue(issubclass(test_class, test.Test))
......@@ -138,7 +134,7 @@ class LoaderTest(unittest.TestCase):
'avocado_loader_unittest')
avocado_base_test.save()
test_class, test_parameters = (
self.loader.discover_tests(params={'id': avocado_base_test.path})[0])
self.loader.discover(avocado_base_test.path, True)[0])
self.assertTrue(str(test_class) == "<class 'base.MyBaseTest'>",
str(test_class))
......@@ -147,7 +143,7 @@ class LoaderTest(unittest.TestCase):
'avocado_loader_unittest')
avocado_inherited_test.save()
test_class, test_parameters = (
self.loader.discover_tests(params={'id': avocado_inherited_test.path})[0])
self.loader.discover(avocado_inherited_test.path, True)[0])
self.assertTrue(str(test_class) == "<class 'inherited.MyInheritedTest'>",
str(test_class))
avocado_base_test.remove()
......@@ -159,7 +155,7 @@ class LoaderTest(unittest.TestCase):
'avocado_loader_unittest')
avocado_buggy_test.save()
test_class, test_parameters = (
self.loader.discover_tests(params={'id': avocado_buggy_test.path})[0])
self.loader.discover(avocado_buggy_test.path, True)[0])
self.assertTrue(test_class == test.SimpleTest, test_class)
tc = test_class(**test_parameters)
self.assertRaises(exceptions.TestFail, tc.test)
......@@ -172,7 +168,7 @@ class LoaderTest(unittest.TestCase):
mode=0664)
avocado_buggy_test.save()
test_class, test_parameters = (
self.loader.discover_tests(params={'id': avocado_buggy_test.path})[0])
self.loader.discover(avocado_buggy_test.path, True)[0])
self.assertTrue(test_class == test.BuggyTest, test_class)
tc = test_class(**test_parameters)
self.assertRaises(ImportError, tc.test)
......@@ -185,7 +181,7 @@ class LoaderTest(unittest.TestCase):
mode=0664)
avocado_not_a_test.save()
test_class, test_parameters = (
self.loader.discover_tests(params={'id': avocado_not_a_test.path})[0])
self.loader.discover(avocado_not_a_test.path, True)[0])
self.assertTrue(test_class == test.NotATest, test_class)
tc = test_class(**test_parameters)
self.assertRaises(exceptions.NotATestError, tc.test)
......@@ -196,7 +192,7 @@ class LoaderTest(unittest.TestCase):
'avocado_loader_unittest')
avocado_not_a_test.save()
test_class, test_parameters = (
self.loader.discover_tests(params={'id': avocado_not_a_test.path})[0])
self.loader.discover(avocado_not_a_test.path, True)[0])
self.assertTrue(test_class == test.SimpleTest, test_class)
tc = test_class(**test_parameters)
# The test can't be executed (no shebang), raising an OSError
......@@ -210,7 +206,7 @@ class LoaderTest(unittest.TestCase):
'avocado_loader_unittest')
avocado_simple_test.save()
test_class, test_parameters = (
self.loader.discover_tests(params={'id': avocado_simple_test.path})[0])
self.loader.discover(avocado_simple_test.path, True)[0])
self.assertTrue(test_class == test.SimpleTest)
tc = test_class(**test_parameters)
tc.test()
......@@ -223,7 +219,7 @@ class LoaderTest(unittest.TestCase):
mode=0664)
avocado_simple_test.save()
test_class, test_parameters = (
self.loader.discover_tests(params={'id': avocado_simple_test.path})[0])
self.loader.discover(avocado_simple_test.path, True)[0])
self.assertTrue(test_class == test.NotATest)
tc = test_class(**test_parameters)
self.assertRaises(exceptions.NotATestError, tc.test)
......@@ -235,13 +231,10 @@ class LoaderTest(unittest.TestCase):
'avocado_multiple_tests_unittest',
mode=0664)
avocado_multiple_tests.save()
suite = self.loader.discover_tests(params={'id': avocado_multiple_tests.path})
suite = self.loader.discover(avocado_multiple_tests.path, True)
self.assertEqual(len(suite), 2)
avocado_multiple_tests.remove()
def tearDown(self):
if os.path.isdir(self.job.logdir):
shutil.rmtree(self.job.logdir)
if __name__ == '__main__':
unittest.main()
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册