提交 5973e898 编写于 作者: L Lukáš Doktor 提交者: Amador Pahim

avocado: Implement serialized test ids

This commit implements the serialized test ids described in the
Introduce proper test IDs RFC.

https://www.redhat.com/archives/avocado-devel/2016-March/msg00024.html

It implements `TestName` class, which contains the test uid, test name
and the variant uid and allows querying for the file-system-friendly
name.

The workflow is:

1. tests are discovered, name is translated to "Test Name" by loader
2. test_suite is passed to the runner (new) along with the number of
   tests+variants to be executed (used to get number of digits)
3. the Mux (params generator) yields the template + (new) variant id
4. the runner replaces template['name'] to TestName(uid, test_name,
   variant_id); where uid is currently no executed tests, test_name is
   the original name from Loader and variant_id is either None or the
   variant index.

This commit makes the `tag` argument unused. To avoid problems a warning
is issued on it's usage so we can remove it in the upcoming releases.
Signed-off-by: NLukáš Doktor <ldoktor@redhat.com>
上级 c7b6b68b
......@@ -217,7 +217,7 @@ class HTMLTestResult(TestResult):
:type state: dict
"""
TestResult.end_test(self, state)
t = {'test': state.get('tagged_name', "<unknown>"),
t = {'test': str(state.get('name', "<unknown>")),
'url': state.get('name', "<unknown>"),
'time_start': state.get('time_start', -1),
'time_end': state.get('time_end', -1),
......
......@@ -499,9 +499,9 @@ class Job(object):
self._log_job_debug_info(mux)
replay.record(self.args, self.logdir, mux, self.urls)
replay_map = getattr(self.args, 'replay_map', None)
summary = self.test_runner.run_suite(test_suite, mux,
timeout=self.timeout,
replay_map=replay_map)
summary = self.test_runner.run_suite(test_suite, mux, self.timeout,
replay_map,
self.args.test_result_total)
self.__stop_job_logging()
# If it's all good so far, set job status to 'PASS'
if self.status == 'RUNNING':
......
......@@ -61,8 +61,8 @@ class JSONTestResult(TestResult):
TestResult.end_test(self, state)
if 'job_id' not in self.json:
self.json['job_id'] = state.get('job_unique_id', "<unknown>")
t = {'test': state.get('tagged_name', "<unknown>"),
'url': state.get('name', "<unknown>"),
t = {'test': str(state.get('name', "<unknown>")),
'url': str(state.get('name', "<unknown>")),
'start': state.get('time_start', -1),
'end': state.get('time_end', -1),
'time': state.get('time_elapsed', -1),
......
......@@ -415,18 +415,16 @@ class Mux(object):
"""
if self.variants: # Copy template and modify it's params
i = None
for i, variant in enumerate(self.variants):
for i, variant in enumerate(self.variants, 1):
test_factory = [template[0], template[1].copy()]
if self._has_multiple_variants:
test_factory[1]['tag'] = "variant%s" % (i + 1)
if "params" in test_factory[1]:
msg = ("Unable to multiplex test %s, params are already "
"present in test factory: %s"
% (test_factory[0], test_factory[1]))
raise ValueError(msg)
test_factory[1]['params'] = (variant, self._mux_path)
yield test_factory
yield test_factory, i if self._has_multiple_variants else None
if i is None: # No variants, use template
yield template
yield template, None
else: # No variants, use template
yield template
yield template, None
......@@ -29,6 +29,7 @@ from .. import virt
from .. import exceptions
from .. import status
from ..runner import TestRunner
from ..test import TestName
from ...utils import astring
from ...utils import archive
from ...utils import stacktrace
......@@ -180,7 +181,7 @@ class RemoteTestRunner(TestRunner):
return json_result
def run_suite(self, test_suite, mux, timeout, replay_map=None):
def run_suite(self, test_suite, mux, timeout, replay_map=None, test_result_total=0):
"""
Run one or more tests and report with test result.
......@@ -191,6 +192,7 @@ class RemoteTestRunner(TestRunner):
"""
del test_suite # using self.job.urls instead
del mux # we're not using multiplexation here
del test_result_total # evaluated by the remote avocado
if not timeout: # avoid timeout = 0
timeout = None
summary = set()
......@@ -229,7 +231,10 @@ class RemoteTestRunner(TestRunner):
remote_log_dir = os.path.dirname(results['debuglog'])
self.result.start_tests()
for tst in results['tests']:
test = RemoteTest(name=tst['test'],
name = tst['test'].split('-', 1)
name = [name[0]] + name[1].split(';')
name = TestName(*name, no_digits=-1)
test = RemoteTest(name=name,
time=tst['time'],
start=tst['start'],
end=tst['end'],
......
......@@ -25,7 +25,6 @@ class RemoteTest(object):
logfile):
note = "Not supported yet"
self.name = name
self.tagged_name = name
self.status = status
self.time_elapsed = time
self.time_start = start
......
......@@ -235,8 +235,14 @@ class HumanTestResult(TestResult):
def start_test(self, state):
super(HumanTestResult, self).start_test(state)
self.log.debug(' (%s/%s) %s: ', self.tests_run, self.tests_total,
state.get("tagged_name", "<missing>"),
if "name" in state:
name = state["name"]
uid = name.str_uid
name = name.name + name.str_variant
else:
name = "<unknown>"
uid = '?'
self.log.debug(' (%s/%s) %s: ', uid, self.tests_total, name,
extra={"skip_newline": True})
def end_test(self, state):
......
......@@ -403,7 +403,8 @@ class TestRunner(object):
return False
return True
def run_suite(self, test_suite, mux, timeout=0, replay_map=None):
def run_suite(self, test_suite, mux, timeout=0, replay_map=None,
test_result_total=0):
"""
Run one or more tests and report with test result.
......@@ -423,14 +424,20 @@ class TestRunner(object):
else:
deadline = None
no_digits = len(str(test_result_total))
index = -1
for test_template in test_suite:
test_template[1]['base_logdir'] = self.job.logdir
test_template[1]['job'] = self.job
break_loop = False
for test_factory in mux.itertests(test_template):
for test_factory, variant in mux.itertests(test_template):
index += 1
test_parameters = test_factory[1]
name = test_parameters.get("name")
test_parameters["name"] = test.TestName(index + 1, name,
variant,
no_digits)
if deadline is not None and time.time() > deadline:
summary.add('INTERRUPTED')
if 'methodName' in test_parameters:
......
......@@ -46,6 +46,65 @@ else:
import unittest
class TestName(object):
"""
Test name representation
"""
def __init__(self, uid, name, variant=None, no_digits=None):
"""
Test name according to avocado specification
:param uid: unique test id (within the job)
:param name: test name (identifies the executed test)
:param variant: variant id
:param no_digits: number of digits of the test uid
"""
self.uid = uid
if no_digits >= 0:
self.str_uid = str(uid).zfill(no_digits if no_digits else 3)
else:
self.str_uid = str(uid)
self.name = name or "<unknown>"
self.variant = variant
self.str_variant = "" if variant is None else ";" + str(variant)
def __str__(self):
return "%s-%s%s" % (self.str_uid, self.name, self.str_variant)
def __repr__(self):
return repr(str(self))
def __eq__(self, other):
if isinstance(other, basestring):
return str(self) == other
else:
return self.__dict__ == other.__dict__
def str_filesystem(self):
"""
File-system friendly representation of the test name
"""
name = str(self)
fsname = astring.string_to_safe_path(name)
if len(name) == len(fsname): # everything fits in
return fsname
# 001-mytest;aaa
# 001-mytest;a
# 001-myte;aaa
idx_fit_variant = len(fsname) - len(self.str_variant)
if idx_fit_variant > len(self.str_uid): # full uid+variant
return (fsname[:idx_fit_variant] +
astring.string_to_safe_path(self.str_variant))
elif len(self.str_uid) <= len(fsname): # full uid
return astring.string_to_safe_path(self.str_uid + self.str_variant)
else: # not even uid could be stored in fs
raise AssertionError("Test uid is too long to be stored on the "
"filesystem: %s\nFull test name is %s"
% (self.str_uid, str(self)))
class Test(unittest.TestCase):
"""
......@@ -81,10 +140,14 @@ class Test(unittest.TestCase):
self.__log_warn_used = True
return original_log_warn(*args, **kwargs)
if name is not None:
_incorrect_name = None
if isinstance(name, basestring): # TODO: Remove in release 0.37
_incorrect_name = True
self.name = TestName(0, name)
elif name is not None:
self.name = name
else:
self.name = self.__class__.__name__
self.name = TestName(0, self.__class__.__name__)
self.tag = tag
self.job = job
......@@ -101,7 +164,12 @@ class Test(unittest.TestCase):
if base_logdir is None:
base_logdir = data_dir.create_job_logs_dir()
base_logdir = os.path.join(base_logdir, 'test-results')
self.tagged_name, self.logdir = self._init_logdir(base_logdir)
logdir = os.path.join(base_logdir, self.name.str_filesystem())
if os.path.exists(logdir):
raise exceptions.TestSetupFail("Log dir already exists, this "
"should never happen: %s"
% logdir)
self.logdir = utils_path.init_dir(logdir)
# Replace '/' with '_' to avoid splitting name into multiple dirs
genio.set_log_file_dir(self.logdir)
......@@ -119,6 +187,13 @@ class Test(unittest.TestCase):
original_log_warn = self.log.warning
self.__log_warn_used = False
self.log.warn = self.log.warning = record_and_warn
if _incorrect_name is not None:
self.log.warn("The 'name' argument has to be TestName instance, "
"not string. In the upcomming releases this will "
"become an exception. (%s)", self.name.name)
if tag is not None: # TODO: Remove in release 0.37
self.log.warn("The 'tag' argument is not supported and will be "
"removed in the upcoming releases. (%s)", tag)
mux_path = ['/test/*']
if isinstance(params, dict):
......@@ -135,7 +210,7 @@ class Test(unittest.TestCase):
default_timeout = getattr(self, "timeout", None)
self.timeout = self.params.get("timeout", default=default_timeout)
self.log.info('START %s', self.tagged_name)
self.log.info('START %s', self.name)
self.debugdir = None
self.resultsdir = None
......@@ -209,7 +284,7 @@ class Test(unittest.TestCase):
return str(self.name)
def __repr__(self):
return "Test(%r)" % self.tagged_name
return "Test(%r)" % self.name
def _tag_start(self):
self.running = True
......@@ -245,7 +320,7 @@ class Test(unittest.TestCase):
preserve_attr = ['basedir', 'debugdir', 'depsdir',
'fail_reason', 'logdir', 'logfile', 'name',
'resultsdir', 'srcdir', 'status', 'sysinfodir',
'tag', 'tagged_name', 'text_output', 'time_elapsed',
'tag', 'text_output', 'time_elapsed',
'traceback', 'workdir', 'whiteboard', 'time_start',
'time_end', 'running', 'paused', 'paused_msg',
'fail_class', 'params', "timeout"]
......@@ -296,39 +371,6 @@ class Test(unittest.TestCase):
self.log.removeHandler(self.file_handler)
logging.getLogger('paramiko').removeHandler(self._ssh_fh)
def _init_logdir(self, logdir):
"""
Initialize log dir
Combines name + tag (if present) to obtain unique name. When associated
directory already exists, appends ".$number" until unused name
is generated to avoid clashes.
:param logdir: Log directory being in use for result storage.
:return: Unique test name and the logdir
"""
name = self.name
if self.tag is not None:
name += ".%s" % self.tag
tag = 0
tagged_name = name
# The maximal length on ext4+python2.7 is 255 chars.
safe_tagged_name = astring.string_to_safe_path(tagged_name[:250])
for i in xrange(9999):
if not os.path.isdir(os.path.join(logdir, safe_tagged_name)):
break
tag += 1
tagged_name = "%s.%s" % (name, tag)
safe_tagged_name = astring.string_to_safe_path("%s.%s"
% (name[:250], tag))
else:
raise exceptions.TestSetupFail("Unable to find unique name in %s "
"iterations (%s).", i,
safe_tagged_name)
self.tag = "%s.%s" % (self.tag, tag) if self.tag else str(tag)
return tagged_name, utils_path.init_dir(logdir, safe_tagged_name)
def _record_reference_stdout(self):
if self.datadir is not None:
utils_path.init_dir(self.datadir)
......@@ -520,7 +562,7 @@ class Test(unittest.TestCase):
"""
if self.fail_reason is not None:
self.log.error("%s %s -> %s: %s", self.status,
self.tagged_name,
self.name,
self.fail_class,
self.fail_reason)
......@@ -528,7 +570,7 @@ class Test(unittest.TestCase):
if self.status is None:
self.status = 'INTERRUPTED'
self.log.info("%s %s", self.status,
self.tagged_name)
self.name)
def fail(self, message=None):
"""
......@@ -608,7 +650,7 @@ class SimpleTest(Test):
"""
Returns the name of the file (path) that holds the current test
"""
return os.path.abspath(self.name)
return os.path.abspath(self.name.name)
def _log_detailed_cmd_info(self, result):
"""
......@@ -654,7 +696,7 @@ class ExternalRunnerTest(SimpleTest):
self.external_runner = external_runner
super(ExternalRunnerTest, self).__init__(name, params, base_logdir,
tag, job)
self._command = external_runner.runner + " " + name
self._command = external_runner.runner + " " + self.name.name
@property
def filename(self):
......
......@@ -88,7 +88,7 @@ class XmlResult(object):
"""
tc = '\t<testcase classname={class} name={name} time="{time}"/>'
values = {'class': self._escape_attr(state.get('class_name', "<unknown>")),
'name': self._escape_attr(state.get('tagged_name', "<unknown>")),
'name': self._escape_attr(state.get('name', "<unknown>")),
'time': state.get('time_elapsed', -1)}
self.testcases.append(tc.format(**values))
......@@ -103,7 +103,7 @@ class XmlResult(object):
\t\t<skipped />
\t</testcase>'''
values = {'class': self._escape_attr(state.get('class_name', "<unknown>")),
'name': self._escape_attr(state.get('tagged_name', "<unknown>")),
'name': self._escape_attr(state.get('name', "<unknown>")),
'time': state.get('time_elapsed', -1)}
self.testcases.append(tc.format(**values))
......@@ -119,7 +119,7 @@ class XmlResult(object):
\t\t<system-out><![CDATA[{systemout}]]></system-out>
\t</testcase>'''
values = {'class': self._escape_attr(state.get('class_name', "<unknown>")),
'name': self._escape_attr(state.get('tagged_name', "<unknown>")),
'name': self._escape_attr(state.get('name', "<unknown>")),
'time': state.get('time_elapsed', -1),
'type': self._escape_attr(state.get('fail_class', "<unknown>")),
'traceback': self._escape_cdata(state.get('traceback', "<unknown>")),
......@@ -139,7 +139,7 @@ class XmlResult(object):
\t\t<system-out><![CDATA[{systemout}]]></system-out>
\t</testcase>'''
values = {'class': self._escape_attr(state.get('class_name', "<unknown>")),
'name': self._escape_attr(state.get('tagged_name', "<unknown>")),
'name': self._escape_attr(state.get('name', "<unknown>")),
'time': state.get('time_elapsed', -1),
'type': self._escape_attr(state.get('fail_class', "<unknown>")),
'traceback': self._escape_cdata(state.get('traceback', "<unknown>")),
......
......@@ -91,7 +91,7 @@ class TestResultJournal(TestResult):
status = None
self.journal_cursor.execute(sql,
(state['tagged_name'],
(str(state['name']),
datetime.datetime(1, 1, 1).now().isoformat(),
action,
status))
......
......@@ -385,7 +385,8 @@ class RunnerOperationTest(unittest.TestCase):
self.assertEqual(result.exit_status, expected_rc,
"Avocado did not return rc %d:\n%s" %
(expected_rc, result))
self.assertIn('MyTest.test_my_name -> TestError', result.stdout)
self.assertIn('1-%s:MyTest.test_my_name -> TestError' % test,
result.stdout)
def tearDown(self):
shutil.rmtree(self.tmpdir)
......@@ -452,7 +453,7 @@ class RunnerHumanOutputTest(unittest.TestCase):
self.assertIn('[stdout] foo', result.stdout, result)
self.assertIn('[stdout] \'"', result.stdout, result)
self.assertIn('[stdout] bar/baz', result.stdout, result)
self.assertIn('PASS /bin/echo -ne foo\\\\n\\\'\\"\\\\nbar/baz',
self.assertIn('PASS 1-/bin/echo -ne foo\\\\n\\\'\\"\\\\nbar/baz',
result.stdout, result)
# logdir name should escape special chars (/)
test_dirs = glob.glob(os.path.join(self.tmpdir, 'latest',
......@@ -461,7 +462,7 @@ class RunnerHumanOutputTest(unittest.TestCase):
" test-results dir, but only one test was executed: "
"%s" % (test_dirs))
self.assertEqual(os.path.basename(test_dirs[0]),
'_bin_echo -ne foo\\\\n\\\'\\"\\\\nbar_baz')
'1-_bin_echo -ne foo\\\\n\\\'\\"\\\\nbar_baz')
def test_replay_skip_skipped(self):
result = process.run("./scripts/avocado run skiponsetup --json -")
......@@ -913,10 +914,10 @@ class PluginsJSONTest(AbsPluginsTest, unittest.TestCase):
0, 0)
# The executed test should be this
self.assertEqual(data['tests'][0]['url'],
'/bin/echo -ne foo\\\\n\\\'\\"\\\\nbar/baz')
'1-/bin/echo -ne foo\\\\n\\\'\\"\\\\nbar/baz')
# logdir name should escape special chars (/)
self.assertEqual(os.path.basename(data['tests'][0]['logdir']),
'_bin_echo -ne foo\\\\n\\\'\\"\\\\nbar_baz')
'1-_bin_echo -ne foo\\\\n\\\'\\"\\\\nbar_baz')
def tearDown(self):
shutil.rmtree(self.tmpdir)
......
......@@ -82,8 +82,9 @@ class StreamsTest(unittest.TestCase):
result.stderr)
self.assertIn("Command line: %s" % cmd,
result.stdout)
self.assertIn("START passtest", result.stdout)
self.assertIn("PASS passtest", result.stdout)
self.assertIn("\nSTART 1-passtest.py:PassTest.test",
result.stdout)
self.assertIn("PASS 1-passtest.py:PassTest.test", result.stdout)
self.assertEqual('', result.stderr)
def test_none_success(self):
......
......@@ -148,6 +148,7 @@ class LoaderTest(unittest.TestCase):
test_class, test_parameters = (
self.loader.discover(simple_test.path, True)[0])
self.assertTrue(test_class == test.SimpleTest, test_class)
test_parameters['name'] = test.TestName(0, test_parameters['name'])
tc = test_class(**test_parameters)
tc.test()
# Load with params
......@@ -165,6 +166,7 @@ class LoaderTest(unittest.TestCase):
test_class, test_parameters = (
self.loader.discover(simple_test.path, True)[0])
self.assertTrue(test_class == test.NotATest, test_class)
test_parameters['name'] = test.TestName(0, test_parameters['name'])
tc = test_class(**test_parameters)
self.assertRaises(exceptions.NotATestError, tc.test)
simple_test.remove()
......@@ -188,6 +190,7 @@ class LoaderTest(unittest.TestCase):
test_class, test_parameters = (
self.loader.discover(avocado_not_a_test.path, True)[0])
self.assertTrue(test_class == test.NotATest, test_class)
test_parameters['name'] = test.TestName(0, test_parameters['name'])
tc = test_class(**test_parameters)
self.assertRaises(exceptions.NotATestError, tc.test)
avocado_not_a_test.remove()
......@@ -199,6 +202,7 @@ class LoaderTest(unittest.TestCase):
test_class, test_parameters = (
self.loader.discover(avocado_not_a_test.path, True)[0])
self.assertTrue(test_class == test.SimpleTest, test_class)
test_parameters['name'] = test.TestName(0, test_parameters['name'])
tc = test_class(**test_parameters)
# The test can't be executed (no shebang), raising an OSError
# (OSError: [Errno 8] Exec format error)
......@@ -213,6 +217,7 @@ class LoaderTest(unittest.TestCase):
test_class, test_parameters = (
self.loader.discover(avocado_simple_test.path, True)[0])
self.assertTrue(test_class == test.SimpleTest)
test_parameters['name'] = test.TestName(0, test_parameters['name'])
tc = test_class(**test_parameters)
tc.test()
avocado_simple_test.remove()
......@@ -226,6 +231,7 @@ class LoaderTest(unittest.TestCase):
test_class, test_parameters = (
self.loader.discover(avocado_simple_test.path, True)[0])
self.assertTrue(test_class == test.NotATest)
test_parameters['name'] = test.TestName(0, test_parameters['name'])
tc = test_class(**test_parameters)
self.assertRaises(exceptions.NotATestError, tc.test)
avocado_simple_test.remove()
......
......@@ -13,7 +13,7 @@ import logging
cwd = os.getcwd()
JSON_RESULTS = ('Something other than json\n'
'{"tests": [{"test": "sleeptest.1", "url": "sleeptest", '
'{"tests": [{"test": "1-sleeptest;0", "url": "sleeptest", '
'"fail_reason": "None", '
'"status": "PASS", "time": 1.23, "start": 0, "end": 1.23}],'
'"debuglog": "/home/user/avocado/logs/run-2014-05-26-15.45.'
......@@ -44,7 +44,7 @@ class RemoteTestRunnerTest(unittest.TestCase):
log.should_receive("info")
job = flexmock(args=Args, log=log,
urls=['/tests/sleeptest', '/tests/other/test',
'passtest'], unique_id='sleeptest.1',
'passtest'], unique_id='1-sleeptest;0',
logdir="/local/path")
flexmock(remote.RemoteTestRunner).should_receive('__init__')
......@@ -56,7 +56,7 @@ class RemoteTestRunnerTest(unittest.TestCase):
flexmock(logging).should_receive("FileHandler").and_return(filehandler)
test_results = flexmock(stdout=JSON_RESULTS, exit_status=0)
stream = flexmock(job_unique_id='sleeptest.1',
stream = flexmock(job_unique_id='1-sleeptest;0',
debuglog='/local/path/dirname')
Remote = flexmock()
Remoter = flexmock(remoter.Remote)
......@@ -102,7 +102,7 @@ _=/usr/bin/env''', exit_status=0)
.with_args(args, ignore_status=True, timeout=60)
.once().and_return(urls_result))
args = ("cd ~/avocado/tests; avocado run --force-job-id sleeptest.1 "
args = ("cd ~/avocado/tests; avocado run --force-job-id 1-sleeptest;0 "
"--json - --archive /tests/sleeptest /tests/other/test "
"passtest --multiplex ~/avocado/tests/foo.yaml "
"~/avocado/tests/bar/baz.yaml --dry-run")
......@@ -116,14 +116,14 @@ _=/usr/bin/env''', exit_status=0)
dry_run=True))
Results.should_receive('start_tests').once().ordered()
args = {'status': u'PASS', 'whiteboard': '', 'time_start': 0,
'name': u'sleeptest.1', 'class_name': 'RemoteTest',
'name': '1-sleeptest;0', 'class_name': 'RemoteTest',
'traceback': 'Not supported yet',
'text_output': 'Not supported yet', 'time_end': 1.23,
'tagged_name': u'sleeptest.1', 'time_elapsed': 1.23,
'time_elapsed': 1.23,
'fail_class': 'Not supported yet', 'job_unique_id': '',
'fail_reason': 'None',
'logdir': '/local/path/test-results/sleeptest.1',
'logfile': '/local/path/test-results/sleeptest.1/debug.log'}
'fail_reason': u'None',
'logdir': u'/local/path/test-results/1-sleeptest;0',
'logfile': u'/local/path/test-results/1-sleeptest;0/debug.log'}
Results.should_receive('start_test').once().with_args(args).ordered()
Results.should_receive('check_test').once().with_args(args).ordered()
(Remote.should_receive('receive_files')
......
......@@ -39,19 +39,20 @@ class TestClassTestUnit(unittest.TestCase):
def testUglyName(self):
def run(name, path_name):
""" Initialize test and check the dirs were created """
test = DummyTest("test", name, base_logdir=self.tmpdir)
self.assertEqual(os.path.basename(test.logdir), path_name)
self.assertTrue(os.path.exists(test.logdir))
self.assertEqual(os.path.dirname(os.path.dirname(test.logdir)),
tst = DummyTest("test", test.TestName(1, name),
base_logdir=self.tmpdir)
self.assertEqual(os.path.basename(tst.logdir), path_name)
self.assertTrue(os.path.exists(tst.logdir))
self.assertEqual(os.path.dirname(os.path.dirname(tst.logdir)),
self.tmpdir)
run("/absolute/path", "_absolute_path")
run("./relative/path", "__relative_path")
run("/absolute/path", "1-_absolute_path")
run("./relative/path", "1-._relative_path")
run("../../multi_level/relative/path",
"_._.._multi_level_relative_path")
"1-.._.._multi_level_relative_path")
# Greek word 'kosme'
run("\xce\xba\xe1\xbd\xb9\xcf\x83\xce\xbc\xce\xb5",
"\xce\xba\xe1\xbd\xb9\xcf\x83\xce\xbc\xce\xb5")
"1-\xce\xba\xe1\xbd\xb9\xcf\x83\xce\xbc\xce\xb5")
# Particularly problematic noncharacters in 16-bit applications
name = ("\xb7\x95\xef\xb7\x96\xef\xb7\x97\xef\xb7\x98\xef\xb7\x99"
"\xef\xb7\x9a\xef\xb7\x9b\xef\xb7\x9c\xef\xb7\x9d\xef\xb7"
......@@ -59,31 +60,48 @@ class TestClassTestUnit(unittest.TestCase):
"\xb7\xa3\xef\xb7\xa4\xef\xb7\xa5\xef\xb7\xa6\xef\xb7\xa7"
"\xef\xb7\xa8\xef\xb7\xa9\xef\xb7\xaa\xef\xb7\xab\xef\xb7"
"\xac\xef\xb7\xad\xef\xb7\xae\xef\xb7\xaf")
run(name, name)
run(name, "1-" + name)
def testLongName(self):
test = DummyTest("test", "a" * 256, base_logdir=self.tmpdir)
self.assertEqual(os.path.basename(test.logdir), "a" * 250)
test = DummyTest("test", "a" * 256, base_logdir=self.tmpdir)
self.assertEqual(os.path.basename(test.logdir), "a" * 250 + ".1")
self.assertEqual(os.path.basename(test.workdir),
os.path.basename(test.logdir))
flexmock(test)
test.should_receive('filename').and_return(os.path.join(self.tmpdir,
"a"*250))
def check(uid, name, variant, exp_logdir):
tst = DummyTest("test", test.TestName(uid, name, variant))
self.assertEqual(os.path.basename(tst.logdir), exp_logdir)
return tst
# Everything fits
check(1, "a" * 253, None, "1-" + ("a" * 253))
check(2, "a" * 251, 1, "2-" + ("a" * 251) + ";1")
check(99, "a" * 249, 88, "99-" + ("a" * 249) + ";88")
# Shrink name
check(3, "a" * 252, 1, "3-" + ('a' * 251) + ";1")
# Shrink variant
check("a" * 253, "whatever", 99, "a" * 253 + ";9")
check("a" * 254, "whatever", 99, "a" * 254 + ";")
# No variant
tst = check("a" * 255, "whatever", "whatever-else", "a" * 255)
# Impossible to store (uid does not fit
self.assertRaises(AssertionError, check, "a" * 256, "whatever", "else",
None)
self.assertEqual(os.path.basename(tst.workdir),
os.path.basename(tst.logdir))
flexmock(tst)
tst.should_receive('filename').and_return(os.path.join(self.tmpdir,
"a"*250))
self.assertEqual(os.path.join(self.tmpdir, "a"*250 + ".data"),
test.datadir)
test.should_receive('filename').and_return("a"*251)
self.assertFalse(test.datadir)
test._record_reference_stdout # Should does nothing
test._record_reference_stderr # Should does nothing
test._record_reference_stdout()
test._record_reference_stderr()
tst.datadir)
tst.should_receive('filename').and_return("a"*251)
self.assertFalse(tst.datadir)
tst._record_reference_stdout # Should does nothing
tst._record_reference_stderr # Should does nothing
tst._record_reference_stdout()
tst._record_reference_stderr()
def testAllDirsExistsNoHang(self):
flexmock(os.path)
os.path.should_receive('isdir').and_return(True)
self.assertRaises(exceptions.TestSetupFail, DummyTest, "test", "name")
os.path.should_receive('exists').and_return(True)
self.assertRaises(exceptions.TestSetupFail, DummyTest, "test",
test.TestName(1, "name"))
class TestClassTest(unittest.TestCase):
......@@ -99,11 +117,9 @@ class TestClassTest(unittest.TestCase):
self.base_logdir = tempfile.mkdtemp(prefix='avocado_' + __name__)
self.tst_instance_pass = AvocadoPass(base_logdir=self.base_logdir)
self.tst_instance_pass.run_avocado()
self.tst_instance_pass_new = AvocadoPass(base_logdir=self.base_logdir)
self.tst_instance_pass_new.run_avocado()
def testClassAttributesName(self):
self.assertEqual(self.tst_instance_pass.name, 'AvocadoPass')
self.assertEqual(self.tst_instance_pass.name, '0-AvocadoPass')
def testClassAttributesStatus(self):
self.assertEqual(self.tst_instance_pass.status, 'PASS')
......@@ -112,10 +128,7 @@ class TestClassTest(unittest.TestCase):
self.assertIsInstance(self.tst_instance_pass.time_elapsed, float)
def testClassAttributesTag(self):
self.assertEqual(self.tst_instance_pass.tag, "0")
def testClassAttributesTaggedName(self):
self.assertEqual(self.tst_instance_pass.tagged_name, "AvocadoPass")
self.assertEqual(self.tst_instance_pass.tag, None)
def testWhiteboardSave(self):
whiteboard_file = os.path.join(
......@@ -125,13 +138,14 @@ class TestClassTest(unittest.TestCase):
whiteboard_contents = whiteboard_file_obj.read().strip()
self.assertTrue(whiteboard_contents, 'foo')
def testTaggedNameNewTests(self):
"""
New test instances should have crescent tag instances.
"""
self.assertEqual(
self.tst_instance_pass_new.tagged_name, "AvocadoPass.1")
self.assertEqual(self.tst_instance_pass_new.tag, "1")
def testRunningTestTwiceWithTheSameUidFailure(self):
class AvocadoPass(test.Test):
def test(self):
pass
self.assertRaises(exceptions.TestSetupFail, AvocadoPass,
base_logdir=self.base_logdir)
def tearDown(self):
shutil.rmtree(self.base_logdir)
......@@ -154,12 +168,12 @@ class SimpleTestClassTest(unittest.TestCase):
self.fail_script.save()
self.tst_instance_pass = test.SimpleTest(
name=self.pass_script.path,
name=test.TestName(1, self.pass_script.path),
base_logdir=self.tmpdir)
self.tst_instance_pass.run_avocado()
self.tst_instance_fail = test.SimpleTest(
name=self.fail_script.path,
name=test.TestName(1, self.fail_script.path),
base_logdir=self.tmpdir)
self.tst_instance_fail.run_avocado()
......@@ -186,47 +200,46 @@ class SkipTest(unittest.TestCase):
self.assertRaises(exceptions.TestSkipError, self.tests[-1].setUp)
self.assertRaises(RuntimeError, self.tests[-1].test)
# Positional
self.tests.append(test.SkipTest("test", "my_name", {}, None, "1",
self.tests.append(test.SkipTest("test", test.TestName(1, "my_name"),
{}, None, "1",
None, None, "extra_param1",
"extra_param2"))
self.assertEqual(self.tests[-1].name, "my_name")
self.assertEqual(self.tests[-1].tagged_name, "my_name.1")
self.assertEqual(self.tests[-1].name, "1-my_name")
# Kwargs
self.tests.append(test.SkipTest(methodName="test", name="my_name2",
self.tests.append(test.SkipTest(methodName="test",
name=test.TestName(1, "my_name2"),
params={}, base_logdir=None,
tag="a", job=None, runner_queue=None,
extra1="extra_param1",
extra2="extra_param2"))
self.assertEqual(self.tests[-1].name, "my_name2")
self.assertEqual(self.tests[-1].tagged_name, "my_name2.a")
self.assertEqual(self.tests[-1].name, "1-my_name2")
# both (theoretically impossible in python, but valid for nasty tests)
# keyword args are used as they explicitly represent what they mean
self.tests.append(test.SkipTest("not used", "who cares", {}, None, "0",
None, None, "extra_param1",
"extra_param2",
methodName="test", name="my_name3",
methodName="test",
name=test.TestName(1, "my_name3"),
params={}, base_logdir=None,
tag="3", job=None, runner_queue=None,
extra1="extra_param3",
extra2="extra_param4"))
self.assertEqual(self.tests[-1].name, "my_name3")
self.assertEqual(self.tests[-1].tagged_name, "my_name3.3")
self.assertEqual(self.tests[-1].name, "1-my_name3")
# combination
self.tests.append(test.SkipTest("test", "my_name4", tag="321",
self.tests.append(test.SkipTest("test", test.TestName(1, "my_name4"),
tag="321",
other_param="Whatever"))
self.assertEqual(self.tests[-1].name, "my_name4")
self.assertEqual(self.tests[-1].tagged_name, "my_name4.321")
self.assertEqual(self.tests[-1].name, "1-my_name4")
# ugly combination (positional argument overrides kwargs, this only
# happens when the substituted class reorders the positional arguments.
# We try to first match keyword args and then fall-back to positional
# ones.
name = "positional_method_name_becomes_test_name"
tag = "positional_base_logdir_becomes_tag"
self.tests.append(test.SkipTest(name, None, None, tag,
self.tests.append(test.SkipTest(test.TestName(1, name), None, None, tag,
methodName="test",
other_param="Whatever"))
self.assertEqual(self.tests[-1].name, name)
self.assertEqual(self.tests[-1].tagged_name, "%s.%s" % (name, tag))
self.assertEqual(self.tests[-1].name, "1-" + name)
def tearDown(self):
for tst in self.tests:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册