diff --git a/avocado/core/data_dir.py b/avocado/core/data_dir.py index 0ef2993d7e4098f466c821a2de0db0e86e83b061..86852045bad9da51688dd9e94e3fd4abbe2403d4 100755 --- a/avocado/core/data_dir.py +++ b/avocado/core/data_dir.py @@ -26,7 +26,6 @@ The general reasoning to find paths is: * The next best location is the default user specific one. """ import os -import sys import shutil import time import tempfile @@ -37,10 +36,6 @@ from .output import LOG_JOB from ..utils import path as utils_path from ..utils.data_structures import Borg -_BASE_DIR = os.path.join(sys.modules[__name__].__file__, "..", "..", "..") -_BASE_DIR = os.path.abspath(_BASE_DIR) -_IN_TREE_TESTS_DIR = os.path.join(_BASE_DIR, 'examples', 'tests') - SYSTEM_BASE_DIR = '/var/lib/avocado' if 'VIRTUAL_ENV' in os.environ: SYSTEM_BASE_DIR = os.environ['VIRTUAL_ENV'] @@ -109,7 +104,8 @@ def get_test_dir(): return configured if settings.settings.intree: - return _IN_TREE_TESTS_DIR + base_dir = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) + return os.path.join(base_dir, 'examples', 'tests') if utils_path.usable_ro_dir(SYSTEM_TEST_DIR): return SYSTEM_TEST_DIR diff --git a/avocado/core/runner.py b/avocado/core/runner.py index e6e0662178b46e04662c88df6d76cde67aab9952..06191e8d71cf0ef0b5f36b780e96bf90c799b232 100644 --- a/avocado/core/runner.py +++ b/avocado/core/runner.py @@ -580,9 +580,9 @@ class TestRunner(object): index += 1 test_parameters = test_factory[1] name = test_parameters.get("name") - test_parameters["name"] = test.TestName(index + 1, name, - variant, - no_digits) + test_parameters["name"] = test.TestID(index + 1, name, + variant, + no_digits) if deadline is not None and time.time() > deadline: summary.add('INTERRUPTED') if 'methodName' in test_parameters: diff --git a/avocado/core/test.py b/avocado/core/test.py index 03806f3e069a3fc462d1c5dca66870ff248b8aeb..eba1a346505e9ee252a1575831a52a2d061a9d42 100644 --- a/avocado/core/test.py +++ b/avocado/core/test.py @@ -52,30 +52,24 @@ from .output import LOG_JOB COMMON_TMPDIR_NAME = 'AVOCADO_TESTS_COMMON_TMPDIR' -class NameNotTestNameError(Exception): +class TestID(object): """ - The given test name is not a TestName instance + Test ID construction and representation according to specification - With the introduction of :class:`avocado.core.test.TestName`, it's - not allowed to use other types as the ``name`` parameter to a test - instance. This exception is raised when this is attempted. - """ - - -class TestName(object): - - """ - Test name representation + This class wraps the representation of both Avocado's Test ID + specification and Avocado's Test Name, which is part of a Test ID. """ def __init__(self, uid, name, variant=None, no_digits=None): """ - Test name according to avocado specification + Constructs a TestID instance :param uid: unique test id (within the job) - :param name: test name (identifies the executed test) - :param variant: variant id + :param name: test name, as returned by the Avocado test resolver + (AKA as test loader) + :param variant: the variant applied to this Test ID + :type variant: dict :param no_digits: number of digits of the test uid """ self.uid = uid @@ -84,12 +78,12 @@ class TestName(object): else: self.str_uid = str(uid) self.name = name or "" - self.variant = variant["variant_id"] if variant else None - if variant is None: + if variant is None or variant["variant_id"] is None: + self.variant = None self.str_variant = "" else: - self.str_variant = (";" + str(variant["variant_id"]) - if variant["variant_id"] else "") + self.variant = variant["variant_id"] + self.str_variant = ";%s" % self.variant def __str__(self): return "%s-%s%s" % (self.str_uid, self.name, self.str_variant) @@ -103,26 +97,39 @@ class TestName(object): else: return self.__dict__ == other.__dict__ + @property def str_filesystem(self): """ - File-system friendly representation of the test name + Test ID in a format suitable for use in file systems + + The string returned should be safe to be used as a file or + directory name. This file system version of the test ID may + have to shorten either the Test Name or the Variant ID. + + The first component of a Test ID, the numeric unique test id, + AKA "uid", will be used as a an stable identifier between the + Test ID and the file or directory created based on the return + value of this method. If the filesystem can not even + represent the "uid", than an exception will be raised. + + For Test ID "001-mytest;foo", examples of shortened file + system versions include "001-mytest;f" or "001-myte;foo". + + :raises: AssertionError """ - name = str(self) - fsname = astring.string_to_safe_path(name) - if len(name) == len(fsname): # everything fits in - return fsname - # 001-mytest;foo - # 001-mytest;f - # 001-myte;foo - idx_fit_variant = len(fsname) - len(self.str_variant) + test_id = str(self) + test_id_fs = astring.string_to_safe_path(test_id) + if len(test_id) == len(test_id_fs): # everything fits in + return test_id_fs + idx_fit_variant = len(test_id_fs) - len(self.str_variant) if idx_fit_variant > len(self.str_uid): # full uid+variant - return (fsname[:idx_fit_variant] + + return (test_id_fs[:idx_fit_variant] + astring.string_to_safe_path(self.str_variant)) - elif len(self.str_uid) <= len(fsname): # full uid + elif len(self.str_uid) <= len(test_id_fs): # 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" + raise AssertionError('Test uid is too long to be stored on the ' + 'filesystem: "%s"\nFull Test ID: "%s"' % (self.str_uid, str(self))) @@ -161,12 +168,11 @@ class Test(unittest.TestCase): written with the avocado API, this should not be set. This is reserved for internal Avocado use, such as when running random executables as tests. - :type name: :class:`avocado.core.test.TestName` + :type name: :class:`avocado.core.test.TestID` :param base_logdir: Directory where test logs should go. If None provided, it'll use :func:`avocado.data_dir.create_job_logs_dir`. :param job: The job that this test is part of. - :raises: :class:`avocado.core.test.NameNotTestNameError` """ def record_and_warn(*args, **kwargs): """ Record call to this function and log warning """ @@ -175,11 +181,9 @@ class Test(unittest.TestCase): return original_log_warn(*args, **kwargs) if name is not None: - if not isinstance(name, TestName): - raise NameNotTestNameError(name) self.__name = name else: - self.__name = TestName(0, self.__class__.__name__) + self.__name = TestID(0, self.__class__.__name__) self.__job = job @@ -195,7 +199,7 @@ 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') - logdir = os.path.join(base_logdir, self.name.str_filesystem()) + 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" @@ -262,7 +266,9 @@ class Test(unittest.TestCase): @property def name(self): """ - The test name (TestName instance) + Returns the Test ID, which includes the test name + + :rtype: TestID """ return self.__name @@ -321,7 +327,15 @@ class Test(unittest.TestCase): @property def datadir(self): """ - Returns the path to the directory that contains test data files + Returns the path to the directory that may contain test data files + + For test a test file hosted at /usr/share/avocado/tests/sleeptest.py + the datadir is /usr/share/avocado/tests/sleeptest.py.data. + + Note that this directory has no specific relation to the test + name, only to the file that contains the test. It can be used to + host data files that are generic enough to be used for all tests + contained in a given test file. """ # Maximal allowed file name length is 255 if (self.filename is not None and @@ -865,7 +879,7 @@ class SimpleTest(Test): self.log.info("Exit status: %s", result.exit_status) self.log.info("Duration: %s", result.duration) - def execute_cmd(self): + def _execute_cmd(self): """ Run the executable, and log its detailed execution. """ @@ -891,7 +905,7 @@ class SimpleTest(Test): """ Run the test and postprocess the results """ - self.execute_cmd() + self._execute_cmd() class ExternalRunnerTest(SimpleTest): @@ -929,7 +943,7 @@ class ExternalRunnerTest(SimpleTest): new_cwd) os.chdir(new_cwd) - self.execute_cmd() + self._execute_cmd() finally: if new_cwd is not None: diff --git a/avocado/utils/astring.py b/avocado/utils/astring.py index 1d6006ba6dc808e6d55436dd47619e7cea625fcc..b0c32d7a497f734b1be98068d5d82d516795b842 100644 --- a/avocado/utils/astring.py +++ b/avocado/utils/astring.py @@ -209,25 +209,30 @@ def tabular_output(matrix, header=None): return "\n".join(iter_tabular_output(matrix, header)) -def string_safe_encode(string): +def string_safe_encode(input_str): """ People tend to mix unicode streams with encoded strings. This function tries to replace any input with a valid utf-8 encoded ascii stream. + + :param input_str: possibly unsafe string or other object that can + be turned into a string + :returns: a utf-8 encoded ascii stream """ - if not isinstance(string, basestring): - string = str(string) + if not isinstance(input_str, basestring): + input_str = str(input_str) try: - return string.encode("utf-8") + return input_str.encode("utf-8") except UnicodeDecodeError: - return string.decode("utf-8", "replace").encode("utf-8") + return input_str.decode("utf-8", "replace").encode("utf-8") -def string_to_safe_path(string): +def string_to_safe_path(input_str): """ Convert string to a valid file/dir name. - :param string: String to be converted + + :param input_str: String to be converted :return: String which is safe to pass as a file/dir name (on recent fs) """ - if string.startswith("."): - string = "_" + string[1:] - return string.replace(os.path.sep, '_')[:255] + if input_str.startswith("."): + input_str = "_" + input_str[1:] + return input_str.replace(os.path.sep, '_')[:255] diff --git a/docs/source/ReferenceGuide.rst b/docs/source/ReferenceGuide.rst index 7bb69b8a67ee25194802374b7fa6e8bc684239a8..9de8f363a803c7e4d2bfd40298adb8acd50ba3c6 100644 --- a/docs/source/ReferenceGuide.rst +++ b/docs/source/ReferenceGuide.rst @@ -66,6 +66,14 @@ By definition, a Test Name is a Test Reference, but the reciprocal is not necessarily true, as the latter can represent more than one test. +Examples of Test Names:: + + '/bin/true' + 'passtest.py:Passtest.test' + 'file:///tmp/passtest.py:Passtest.test' + 'multiple_tests.py:MultipleTests.test_hello' + 'type_specific.io-github-autotest-qemu.systemtap_tracing.qemu.qemu_free' + Variant IDs ----------- @@ -108,15 +116,13 @@ Syntax:: -[;] -Examples of test-names:: - - '/bin/true' - '/bin/grep foobar /etc/passwd' - 'passtest.py:Passtest.test' - 'file:///tmp/passtest.py:Passtest.test' - 'multiple_tests.py:MultipleTests.test_hello' - 'type_specific.io-github-autotest-qemu.systemtap_tracing.qemu.qemu_free' +Example of Test IDs:: + '1-/bin/true' + '2-passtest.py:Passtest.test;quiet-' + '3-file:///tmp/passtest.py:Passtest.test' + '4-multiple_tests.py:MultipleTests.test_hello;maximum_debug-df2f' + '5-type_specific.io-github-autotest-qemu.systemtap_tracing.qemu.qemu_free' .. _test-types: diff --git a/docs/source/TestParameters.rst b/docs/source/TestParameters.rst index f557f21dff517bc90d1743d3ead0dbe4bad78ec0..d3cc88144ec55221f4527a6db259977ef425d96b 100644 --- a/docs/source/TestParameters.rst +++ b/docs/source/TestParameters.rst @@ -102,7 +102,7 @@ AvocadoParams Is a "database" of params present in every (instrumented) avocado test. It's produced during :class:`avocado.core.test.Test`'s ``__init__`` from a `variant`_. It accepts a list of `TreeNode`_ objects; test name -:class:`avocado.core.test.TestName` (for logging purposes); list of +:class:`avocado.core.test.TestID` (for logging purposes); list of default paths (`Mux path`_) and the `Test's default params`_. In test it allows querying for data by using:: diff --git a/docs/source/WritingTests.rst b/docs/source/WritingTests.rst index 4cbf79b486195607711be81c7990b67ded986f16..819c4f0ffe373a08e08411d0464ca2a224ba38af 100644 --- a/docs/source/WritingTests.rst +++ b/docs/source/WritingTests.rst @@ -266,69 +266,69 @@ as an example: Which produces following structure and parameters:: - $ avocado variants -m examples/tests/sleeptenmin.py.data/sleeptenmin.yaml --summary 2 --variants 2 - Multiplex tree representation: - ┗━━ run - ┣━━ sleeptenmin - ┃ ╠══ builtin - ┃ ║ → sleep_method: builtin - ┃ ╚══ shell - ┃ → sleep_method: shell - ┗━━ variants - ╠══ one_cycle - ║ → sleep_length: 600 - ║ → sleep_cycles: 1 - ╠══ six_cycles - ║ → sleep_length: 100 - ║ → sleep_cycles: 6 - ╠══ one_hundred_cycles - ║ → sleep_length: 6 - ║ → sleep_cycles: 100 - ╚══ six_hundred_cycles - → sleep_length: 1 - → sleep_cycles: 600 - - Multiplex variants: - - Variant 1: /run/sleeptenmin/builtin, /run/variants/one_cycle - /run/sleeptenmin/builtin:sleep_method => builtin - /run/variants/one_cycle:sleep_cycles => 1 - /run/variants/one_cycle:sleep_length => 600 - - Variant 2: /run/sleeptenmin/builtin, /run/variants/six_cycles - /run/sleeptenmin/builtin:sleep_method => builtin - /run/variants/six_cycles:sleep_cycles => 6 - /run/variants/six_cycles:sleep_length => 100 - - Variant 3: /run/sleeptenmin/builtin, /run/variants/one_hundred_cycles - /run/sleeptenmin/builtin:sleep_method => builtin - /run/variants/one_hundred_cycles:sleep_cycles => 100 - /run/variants/one_hundred_cycles:sleep_length => 6 - - Variant 4: /run/sleeptenmin/builtin, /run/variants/six_hundred_cycles - /run/sleeptenmin/builtin:sleep_method => builtin - /run/variants/six_hundred_cycles:sleep_cycles => 600 - /run/variants/six_hundred_cycles:sleep_length => 1 - - Variant 5: /run/sleeptenmin/shell, /run/variants/one_cycle - /run/sleeptenmin/shell:sleep_method => shell - /run/variants/one_cycle:sleep_cycles => 1 - /run/variants/one_cycle:sleep_length => 600 - - Variant 6: /run/sleeptenmin/shell, /run/variants/six_cycles - /run/sleeptenmin/shell:sleep_method => shell - /run/variants/six_cycles:sleep_cycles => 6 - /run/variants/six_cycles:sleep_length => 100 - - Variant 7: /run/sleeptenmin/shell, /run/variants/one_hundred_cycles - /run/sleeptenmin/shell:sleep_method => shell - /run/variants/one_hundred_cycles:sleep_cycles => 100 - /run/variants/one_hundred_cycles:sleep_length => 6 - - Variant 8: /run/sleeptenmin/shell, /run/variants/six_hundred_cycles - /run/sleeptenmin/shell:sleep_method => shell - /run/variants/six_hundred_cycles:sleep_cycles => 600 - /run/variants/six_hundred_cycles:sleep_length => 1 + $ avocado variants -m examples/tests/sleeptenmin.py.data/sleeptenmin.yaml --summary 2 --variants 2 + Multiplex tree representation: + ┗━━ run + ┣━━ sleeptenmin + ┃ ╠══ builtin + ┃ ║ → sleep_method: builtin + ┃ ╚══ shell + ┃ → sleep_method: shell + ┗━━ variants + ╠══ one_cycle + ║ → sleep_length: 600 + ║ → sleep_cycles: 1 + ╠══ six_cycles + ║ → sleep_length: 100 + ║ → sleep_cycles: 6 + ╠══ one_hundred_cycles + ║ → sleep_length: 6 + ║ → sleep_cycles: 100 + ╚══ six_hundred_cycles + → sleep_length: 1 + → sleep_cycles: 600 + + Multiplex variants (8): + + Variant builtin-one_cycle-f659: /run/sleeptenmin/builtin, /run/variants/one_cycle + /run/sleeptenmin/builtin:sleep_method => builtin + /run/variants/one_cycle:sleep_cycles => 1 + /run/variants/one_cycle:sleep_length => 600 + + Variant builtin-six_cycles-723b: /run/sleeptenmin/builtin, /run/variants/six_cycles + /run/sleeptenmin/builtin:sleep_method => builtin + /run/variants/six_cycles:sleep_cycles => 6 + /run/variants/six_cycles:sleep_length => 100 + + Variant builtin-one_hundred_cycles-633a: /run/sleeptenmin/builtin, /run/variants/one_hundred_cycles + /run/sleeptenmin/builtin:sleep_method => builtin + /run/variants/one_hundred_cycles:sleep_cycles => 100 + /run/variants/one_hundred_cycles:sleep_length => 6 + + Variant builtin-six_hundred_cycles-a570: /run/sleeptenmin/builtin, /run/variants/six_hundred_cycles + /run/sleeptenmin/builtin:sleep_method => builtin + /run/variants/six_hundred_cycles:sleep_cycles => 600 + /run/variants/six_hundred_cycles:sleep_length => 1 + + Variant shell-one_cycle-55f5: /run/sleeptenmin/shell, /run/variants/one_cycle + /run/sleeptenmin/shell:sleep_method => shell + /run/variants/one_cycle:sleep_cycles => 1 + /run/variants/one_cycle:sleep_length => 600 + + Variant shell-six_cycles-9e23: /run/sleeptenmin/shell, /run/variants/six_cycles + /run/sleeptenmin/shell:sleep_method => shell + /run/variants/six_cycles:sleep_cycles => 6 + /run/variants/six_cycles:sleep_length => 100 + + Variant shell-one_hundred_cycles-586f: /run/sleeptenmin/shell, /run/variants/one_hundred_cycles + /run/sleeptenmin/shell:sleep_method => shell + /run/variants/one_hundred_cycles:sleep_cycles => 100 + /run/variants/one_hundred_cycles:sleep_length => 6 + + Variant shell-six_hundred_cycles-1e84: /run/sleeptenmin/shell, /run/variants/six_hundred_cycles + /run/sleeptenmin/shell:sleep_method => shell + /run/variants/six_hundred_cycles:sleep_cycles => 600 + /run/variants/six_hundred_cycles:sleep_length => 1 You can see that it creates all possible variants of each ``multiplex domain``, which are defined by ``!mux`` tag in the YAML file and displayed as single @@ -338,14 +338,14 @@ values). In total it'll produce 8 variants of each test:: $ avocado run --mux-yaml examples/tests/sleeptenmin.py.data/sleeptenmin.yaml -- passtest.py JOB ID : cc7ef22654c683b73174af6f97bc385da5a0f02f JOB LOG : /home/medic/avocado/job-results/job-2017-01-22T11.26-cc7ef22/job.log - (1/8) passtest.py:PassTest.test;1: PASS (0.01 s) - (2/8) passtest.py:PassTest.test;2: PASS (0.01 s) - (3/8) passtest.py:PassTest.test;3: PASS (0.01 s) - (4/8) passtest.py:PassTest.test;4: PASS (0.01 s) - (5/8) passtest.py:PassTest.test;5: PASS (0.01 s) - (6/8) passtest.py:PassTest.test;6: PASS (0.01 s) - (7/8) passtest.py:PassTest.test;7: PASS (0.01 s) - (8/8) passtest.py:PassTest.test;8: PASS (0.01 s) + (1/8) passtest.py:PassTest.test;builtin-one_cycle-f659: PASS (0.01 s) + (2/8) passtest.py:PassTest.test;builtin-six_cycles-723b: PASS (0.01 s) + (3/8) passtest.py:PassTest.test;builtin-one_hundred_cycles-633a: PASS (0.01 s) + (4/8) passtest.py:PassTest.test;builtin-six_hundred_cycles-a570: PASS (0.01 s) + (5/8) passtest.py:PassTest.test;shell-one_cycle-55f5: PASS (0.01 s) + (6/8) passtest.py:PassTest.test;shell-six_cycles-9e23: PASS (0.01 s) + (7/8) passtest.py:PassTest.test;shell-one_hundred_cycles-586f: PASS (0.01 s) + (8/8) passtest.py:PassTest.test;shell-six_hundred_cycles-1e84: PASS (0.01 s) RESULTS : PASS 8 | ERROR 0 | FAIL 0 | SKIP 0 | WARN 0 | INTERRUPT 0 JOB TIME : 0.16 s diff --git a/optional_plugins/runner_remote/avocado_runner_remote/__init__.py b/optional_plugins/runner_remote/avocado_runner_remote/__init__.py index b77e8716ae83d18bb596330d5a1042d55bd43c77..0979fd9e2a5c8fa00d0d2cbb5f03464d24c41e8a 100644 --- a/optional_plugins/runner_remote/avocado_runner_remote/__init__.py +++ b/optional_plugins/runner_remote/avocado_runner_remote/__init__.py @@ -37,7 +37,7 @@ from avocado.core.output import LOG_JOB, LOG_UI from avocado.core.plugin_interfaces import CLI from avocado.core.runner import TestRunner from avocado.core.settings import settings -from avocado.core.test import TestName +from avocado.core.test import TestID from avocado.utils import archive from avocado.utils import astring from avocado.utils import process @@ -507,7 +507,7 @@ class RemoteTestRunner(TestRunner): name = [name[0]] + name[1].split(';') if len(name) == 3: name[2] = {"variant_id": name[2]} - name = TestName(*name, no_digits=-1) + name = TestID(*name, no_digits=-1) state = dict(name=name, time_elapsed=tst['time'], time_start=tst['start'], diff --git a/selftests/unit/test_astring.py b/selftests/unit/test_astring.py index db8921abffeeb7c1ba30156d5335e9ff3b28ffe9..f0d48092670201a497c59d3446ea909d36e08ae8 100644 --- a/selftests/unit/test_astring.py +++ b/selftests/unit/test_astring.py @@ -5,7 +5,7 @@ from avocado.utils import astring class AstringTest(unittest.TestCase): - def testTabularOutput(self): + def test_tabular_output(self): matrix = [('foo', 'bar'), ('/bin/bar/sbrubles', '/home/myuser/sbrubles')] self.assertEqual(astring.tabular_output(matrix), @@ -17,7 +17,7 @@ class AstringTest(unittest.TestCase): 'foo bar\n' '/bin/bar/sbrubles /home/myuser/sbrubles')) - def testTabularWithConsoleCodes(self): + def test_tabular_with_console_codes(self): matrix = [("a", "an", "dog", "word", "last"), ("\x1b[94ma", # {BLUE}a "\033[0man", # {END}an @@ -32,7 +32,7 @@ class AstringTest(unittest.TestCase): "a an ccc " "dddd last") - def testTabularOutputDifferentNOCols(self): + def test_tabular_output_different_no_cols(self): matrix = [[], [1], [2, 2], [333, 333, 333], [4, 4, 4, 4444]] self.assertEqual(astring.tabular_output(matrix), "1\n" @@ -40,7 +40,7 @@ class AstringTest(unittest.TestCase): "333 333 333\n" "4 4 4 4444") - def testUnicodeTabular(self): + def test_unicode_tabular(self): """ Verifies tabular can handle utf-8 chars properly diff --git a/selftests/unit/test_datadir.py b/selftests/unit/test_datadir.py index 39e5c859b141b8ef81622bd1905c9d8516eaa7cb..a8f2cb43a91ce2aa0325ce30bb3dc1f12deb514d 100644 --- a/selftests/unit/test_datadir.py +++ b/selftests/unit/test_datadir.py @@ -37,7 +37,7 @@ class DataDirTest(unittest.TestCase): (self.mapping, self.config_file_path) = self._get_temporary_dirs_mapping_and_config() - def testDataDirFromConfig(self): + def test_datadir_from_config(self): """ When avocado.conf is present, honor the values coming from it. """ @@ -57,7 +57,7 @@ class DataDirTest(unittest.TestCase): flexmock(settings, settings=stg_orig) del data_dir - def testUniqueLogDir(self): + def test_unique_log_dir(self): """ Tests that multiple queries for a logdir at the same time provides unique results. @@ -78,7 +78,7 @@ class DataDirTest(unittest.TestCase): self.assertEqual(path, path_prefix + uid + ".1") self.assertTrue(os.path.exists(path)) - def testSettingsDirAlternateDynamic(self): + def test_settings_dir_alternate_dynamic(self): """ Tests that changes to the data_dir settings are applied dynamically diff --git a/selftests/unit/test_jsonresult.py b/selftests/unit/test_jsonresult.py index 8f21d1b97f8d128aee92fd472df5c69d8bf7f384..007060b10ca4448bd91ff92f45478b8e2482d11f 100644 --- a/selftests/unit/test_jsonresult.py +++ b/selftests/unit/test_jsonresult.py @@ -44,7 +44,7 @@ class JSONResultTest(unittest.TestCase): os.remove(self.tmpfile[1]) shutil.rmtree(self.tmpdir) - def testAddSuccess(self): + def test_add_success(self): self.test_result.start_test(self.test1) self.test_result.end_test(self.test1.get_state()) self.test_result.end_tests() @@ -56,7 +56,7 @@ class JSONResultTest(unittest.TestCase): self.assertTrue(obj) self.assertEqual(len(obj['tests']), 1) - def testAddSeveralStatuses(self): + def test_add_several_statuses(self): def run_fake_status(status): self.test_result.start_test(self.test1) self.test_result.check_test(status) @@ -92,7 +92,7 @@ class JSONResultTest(unittest.TestCase): check_item("[skip]", res["skip"], 4) check_item("[total]", res["total"], 13) - def testNegativeStatus(self): + def test_negative_status(self): def check_item(name, value, exp): self.assertEqual(value, exp, "Result%s is %s and not %s\n%s" % (name, value, exp, res)) diff --git a/selftests/unit/test_loader.py b/selftests/unit/test_loader.py index b7db38afafd70c0add79a7e7886de968c23cd5d2..24c8a5cc330f07bb11788d02a70e94cb974aeedd 100644 --- a/selftests/unit/test_loader.py +++ b/selftests/unit/test_loader.py @@ -253,7 +253,7 @@ class LoaderTest(unittest.TestCase): test_class, test_parameters = ( self.loader.discover(simple_test.path, loader.ALL)[0]) self.assertTrue(test_class == test.SimpleTest, test_class) - test_parameters['name'] = test.TestName(0, test_parameters['name']) + test_parameters['name'] = test.TestID(0, test_parameters['name']) test_parameters['base_logdir'] = self.tmpdir tc = test_class(**test_parameters) tc.run_avocado() @@ -299,7 +299,7 @@ class LoaderTest(unittest.TestCase): test_class, test_parameters = ( self.loader.discover(avocado_not_a_test.path, loader.ALL)[0]) self.assertTrue(test_class == test.SimpleTest, test_class) - test_parameters['name'] = test.TestName(0, test_parameters['name']) + test_parameters['name'] = test.TestID(0, test_parameters['name']) test_parameters['base_logdir'] = self.tmpdir tc = test_class(**test_parameters) # The test can't be executed (no shebang), raising an OSError @@ -315,7 +315,7 @@ class LoaderTest(unittest.TestCase): test_class, test_parameters = ( self.loader.discover(avocado_simple_test.path, loader.ALL)[0]) self.assertTrue(test_class == test.SimpleTest) - test_parameters['name'] = test.TestName(0, test_parameters['name']) + test_parameters['name'] = test.TestID(0, test_parameters['name']) test_parameters['base_logdir'] = self.tmpdir tc = test_class(**test_parameters) tc.run_avocado() diff --git a/selftests/unit/test_settings.py b/selftests/unit/test_settings.py index fecc6c507790c9d41d2fa47c8df321d04cd962e1..6e6a20333214c1870e897a1edbf06d84e55ad66d 100644 --- a/selftests/unit/test_settings.py +++ b/selftests/unit/test_settings.py @@ -24,21 +24,21 @@ class SettingsTest(unittest.TestCase): self.config_file.close() self.settings = settings.Settings(self.config_file.name) - def testStringConversion(self): + def test_string_conversion(self): self.assertEqual(self.settings.get_value('foo', 'str_key', str), 'frobnicate') - def testIntConversion(self): + def test_int_conversion(self): self.assertEqual(self.settings.get_value('foo', 'int_key', int), 1) - def testFloatConversion(self): + def test_float_conversion(self): self.assertEqual(self.settings.get_value('foo', 'float_key', float), 1.25) - def testBoolConversion(self): + def test_bool_conversion(self): self.assertTrue(self.settings.get_value('foo', 'bool_key', bool)) - def testPathHomeDir(self): + def test_path_homedir(self): raw_from_settings = '~/path/at/home' path_from_settings = self.settings.get_value('foo', 'path', 'path') home_str_from_settings = self.settings.get_value('foo', 'home_path', str) @@ -49,47 +49,47 @@ class SettingsTest(unittest.TestCase): self.assertEqual(os.path.expanduser(home_str_from_settings), self.settings.get_value('foo', 'home_path', 'path')) - def testPathOnStrKey(self): + def test_path_on_str_key(self): self.assertEqual(self.settings.get_value('foo', 'path', str), '~/path/at/home') - def testListConversion(self): + def test_list_conversion(self): self.assertEqual(self.settings.get_value('foo', 'list_key', list), ['I', 'love', 'settings']) - def testDefault(self): + def test_default(self): self.assertEqual(self.settings.get_value('foo', 'non_existing', str, "ohnoes"), "ohnoes") - def testNonExistingKey(self): + def test_non_existing_key(self): with self.assertRaises(settings.SettingsError): self.settings.get_value('foo', 'non_existing', str) - def testAllowBlankTrueStr(self): + def test_allow_blank_true_str(self): self.assertEqual(self.settings.get_value('foo', 'empty_key', str, allow_blank=True), "") - def testAllowBlankTrueInt(self): + def test_allow_blank_true_int(self): self.assertEqual(self.settings.get_value('foo', 'empty_key', int, allow_blank=True), 0) - def testAllowBlankTrueFloat(self): + def test_allow_blank_true_float(self): self.assertEqual(self.settings.get_value('foo', 'empty_key', float, allow_blank=True), 0.0) - def testAllowBlankTrueList(self): + def test_allow_blank_true_list(self): self.assertEqual(self.settings.get_value('foo', 'empty_key', list, allow_blank=True), []) - def testAllowBlankTrueBool(self): + def test_allow_blank_true_bool(self): self.assertEqual(self.settings.get_value('foo', 'empty_key', bool, allow_blank=True), False) - def testAllowBlankTrueOther(self): + def test_allow_blank_true_other(self): self.assertEqual(self.settings.get_value('foo', 'empty_key', 'baz', allow_blank=True), None) - def testAllowBlankFalse(self): + def test_allow_blank_false(self): with self.assertRaises(settings.SettingsError): self.settings.get_value('foo', 'empty_key', str) diff --git a/selftests/unit/test_sysinfo.py b/selftests/unit/test_sysinfo.py index ecd9ae57d209d9e583bfd44bf0b1ce7c6c8fd834..6650d46eee23f62b0cfc2ce30a1adc190c360e92 100644 --- a/selftests/unit/test_sysinfo.py +++ b/selftests/unit/test_sysinfo.py @@ -11,7 +11,7 @@ class SysinfoTest(unittest.TestCase): def setUp(self): self.tmpdir = tempfile.mkdtemp(prefix="sysinfo_unittest") - def testLoggablesEqual(self): + def test_loggables_equal(self): cmd1 = sysinfo.Command("ls -l") cmd2 = sysinfo.Command("ls -l") self.assertEqual(cmd1, cmd2) @@ -19,7 +19,7 @@ class SysinfoTest(unittest.TestCase): file2 = sysinfo.Logfile("/proc/cpuinfo") self.assertEqual(file1, file2) - def testLoggablesNotEqual(self): + def test_loggables_not_equal(self): cmd1 = sysinfo.Command("ls -l") cmd2 = sysinfo.Command("ls -la") self.assertNotEqual(cmd1, cmd2) @@ -27,7 +27,7 @@ class SysinfoTest(unittest.TestCase): file2 = sysinfo.Logfile("/etc/fstab") self.assertNotEqual(file1, file2) - def testLoggablesSet(self): + def test_loggables_set(self): container = set() cmd1 = sysinfo.Command("ls -l") cmd2 = sysinfo.Command("ls -l") diff --git a/selftests/unit/test_test.py b/selftests/unit/test_test.py index 7baa6893472bc51dd3484781999541daa5b11ae8..08188ec4af055ceb9ebe893780050cfbfc044f9b 100644 --- a/selftests/unit/test_test.py +++ b/selftests/unit/test_test.py @@ -30,10 +30,10 @@ class TestClassTestUnit(unittest.TestCase): flexmock_teardown() shutil.rmtree(self.tmpdir) - def testUglyName(self): + def test_ugly_name(self): def run(name, path_name): """ Initialize test and check the dirs were created """ - tst = self.DummyTest("test", test.TestName(1, name), + tst = self.DummyTest("test", test.TestID(1, name), base_logdir=self.tmpdir) self.assertEqual(os.path.basename(tst.logdir), path_name) self.assertTrue(os.path.exists(tst.logdir)) @@ -56,9 +56,9 @@ class TestClassTestUnit(unittest.TestCase): "\xac\xef\xb7\xad\xef\xb7\xae\xef\xb7\xaf") run(name, "1-" + name) - def testLongName(self): + def test_long_name(self): def check(uid, name, variant, exp_logdir): - tst = self.DummyTest("test", test.TestName(uid, name, variant), + tst = self.DummyTest("test", test.TestID(uid, name, variant), base_logdir=self.tmpdir) self.assertEqual(os.path.basename(tst.logdir), exp_logdir) return tst @@ -93,13 +93,13 @@ class TestClassTestUnit(unittest.TestCase): tst._record_reference_stdout() tst._record_reference_stderr() - def testAllDirsExistsNoHang(self): + def test_all_dirs_exists_no_hang(self): flexmock(os.path) os.path.should_receive('exists').and_return(True) self.assertRaises(exceptions.TestSetupFail, self.DummyTest, "test", - test.TestName(1, "name"), base_logdir=self.tmpdir) + test.TestID(1, "name"), base_logdir=self.tmpdir) - def testTryOverrideTestVariable(self): + def test_try_override_test_variable(self): test = self.DummyTest(base_logdir=self.tmpdir) self.assertRaises(AttributeError, setattr, test, "name", "whatever") self.assertRaises(AttributeError, setattr, test, "status", "whatever") @@ -119,16 +119,16 @@ class TestClassTest(unittest.TestCase): self.tst_instance_pass = AvocadoPass(base_logdir=self.base_logdir) self.tst_instance_pass.run_avocado() - def testClassAttributesName(self): + def test_class_attributes_name(self): self.assertEqual(self.tst_instance_pass.name, '0-AvocadoPass') - def testClassAttributesStatus(self): + def test_class_attributes_status(self): self.assertEqual(self.tst_instance_pass.status, 'PASS') - def testClassAttributesTimeElapsed(self): + def test_class_attributes_time_elapsed(self): self.assertIsInstance(self.tst_instance_pass.time_elapsed, float) - def testWhiteboardSave(self): + def test_whiteboard_save(self): whiteboard_file = os.path.join( self.tst_instance_pass.logdir, 'whiteboard') self.assertTrue(os.path.isfile(whiteboard_file)) @@ -136,7 +136,7 @@ class TestClassTest(unittest.TestCase): whiteboard_contents = whiteboard_file_obj.read().strip() self.assertTrue(whiteboard_contents, 'foo') - def testRunningTestTwiceWithTheSameUidFailure(self): + def test_running_test_twice_with_the_same_uid_failure(self): class AvocadoPass(test.Test): def test(self): @@ -145,10 +145,6 @@ class TestClassTest(unittest.TestCase): self.assertRaises(exceptions.TestSetupFail, AvocadoPass, base_logdir=self.base_logdir) - def testNotTestName(self): - self.assertRaises(test.NameNotTestNameError, - test.Test, name='mytest') - def tearDown(self): shutil.rmtree(self.base_logdir) @@ -170,19 +166,19 @@ class SimpleTestClassTest(unittest.TestCase): self.fail_script.save() self.tst_instance_pass = test.SimpleTest( - name=test.TestName(1, self.pass_script.path), + name=test.TestID(1, self.pass_script.path), base_logdir=self.tmpdir) self.tst_instance_pass.run_avocado() self.tst_instance_fail = test.SimpleTest( - name=test.TestName(1, self.fail_script.path), + name=test.TestID(1, self.fail_script.path), base_logdir=self.tmpdir) self.tst_instance_fail.run_avocado() - def testSimpleTestPassStatus(self): + def test_simple_test_pass_status(self): self.assertEqual(self.tst_instance_pass.status, 'PASS') - def testSimpleTestFailStatus(self): + def test_simple_test_fail_status(self): self.assertEqual(self.tst_instance_fail.status, 'FAIL') def tearDown(self): @@ -200,14 +196,14 @@ class MockingTest(unittest.TestCase): # No params self.tests.append(test.MockingTest()) # Positional - self.tests.append(test.MockingTest("test", test.TestName(1, "my_name"), + self.tests.append(test.MockingTest("test", test.TestID(1, "my_name"), {}, None, "1", None, None, "extra_param1", "extra_param2")) self.assertEqual(self.tests[-1].name, "1-my_name") # Kwargs self.tests.append(test.MockingTest(methodName="test", - name=test.TestName(1, "my_name2"), + name=test.TestID(1, "my_name2"), params={}, base_logdir=None, tag="a", job=None, runner_queue=None, extra1="extra_param1", @@ -219,14 +215,14 @@ class MockingTest(unittest.TestCase): None, None, "extra_param1", "extra_param2", methodName="test", - name=test.TestName(1, "my_name3"), + name=test.TestID(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, "1-my_name3") # combination - self.tests.append(test.MockingTest("test", test.TestName(1, "my_name4"), + self.tests.append(test.MockingTest("test", test.TestID(1, "my_name4"), tag="321", other_param="Whatever")) self.assertEqual(self.tests[-1].name, "1-my_name4") @@ -236,7 +232,7 @@ class MockingTest(unittest.TestCase): # ones. name = "positional_method_name_becomes_test_name" tag = "positional_base_logdir_becomes_tag" - self.tests.append(test.MockingTest(test.TestName(1, name), None, None, tag, + self.tests.append(test.MockingTest(test.TestID(1, name), None, None, tag, methodName="test", other_param="Whatever")) self.assertEqual(self.tests[-1].name, "1-" + name) @@ -249,5 +245,81 @@ class MockingTest(unittest.TestCase): pass +class TestID(unittest.TestCase): + + def test_uid_name(self): + uid = 1 + name = 'file.py:klass.test_method' + test_id = test.TestID(uid, name) + self.assertEqual(test_id.uid, 1) + self.assertEqual(test_id.str_uid, '1') + self.assertEqual(test_id.str_filesystem, '%s-%s' % (uid, name)) + self.assertIs(test_id.variant, None) + self.assertIs(test_id.str_variant, '') + + def test_uid_name_no_digits(self): + uid = 1 + name = 'file.py:klass.test_method' + test_id = test.TestID(uid, name, no_digits=2) + self.assertEqual(test_id.uid, 1) + self.assertEqual(test_id.str_uid, '01') + self.assertEqual(test_id.str_filesystem, '%s-%s' % ('01', name)) + self.assertIs(test_id.variant, None) + self.assertIs(test_id.str_variant, '') + + def test_uid_name_large_digits(self): + """ + Tests that when the filesystem can only cope with the size of + the Test ID, that's the only thing that will be kept. + """ + uid = 1 + name = 'test' + test_id = test.TestID(uid, name, no_digits=255) + self.assertEqual(test_id.uid, 1) + self.assertEqual(test_id.str_uid, '%0255i' % uid) + self.assertEqual(test_id.str_filesystem, '%0255i' % uid) + self.assertIs(test_id.variant, None) + self.assertIs(test_id.str_variant, '') + + def test_uid_name_uid_too_large_digitis(self): + """ + Tests that when the filesystem can not cope with the size of + the Test ID, not even the test uid, an exception will be + raised. + """ + test_id = test.TestID(1, 'test', no_digits=256) + self.assertRaises(AssertionError, lambda: test_id.str_filesystem) + + def test_uid_large_name(self): + """ + Tests that when the filesystem can not cope with the size of + the Test ID, the name will be shortened. + """ + uid = 1 + name = 'test_' * 51 # 255 characters + test_id = test.TestID(uid, name) + self.assertEqual(test_id.uid, 1) + # only 253 can fit for the test name + self.assertEqual(test_id.str_filesystem, '%s-%s' % (uid, name[:253])) + self.assertIs(test_id.variant, None) + self.assertIs(test_id.str_variant, "") + + def test_uid_name_large_variant(self): + """ + Tests that when the filesystem can not cope with the size of + the Test ID, and a variant name is present, the name will be + removed. + """ + uid = 1 + name = 'test' + variant_id = 'fast_' * 51 # 255 characters + variant = {'variant_id': variant_id} + test_id = test.TestID(uid, name, variant=variant) + self.assertEqual(test_id.uid, 1) + self.assertEqual(test_id.str_filesystem, '%s;%s' % (uid, variant_id[:253])) + self.assertIs(test_id.variant, variant_id) + self.assertEqual(test_id.str_variant, ";%s" % variant_id) + + if __name__ == '__main__': unittest.main() diff --git a/selftests/unit/test_utils_asset.py b/selftests/unit/test_utils_asset.py index 6c54be1b25942333809b5f913cfd4b8daf4c4a55..4d38f21f6cb35751c43715714df762663b5678c6 100644 --- a/selftests/unit/test_utils_asset.py +++ b/selftests/unit/test_utils_asset.py @@ -20,7 +20,7 @@ class TestAsset(unittest.TestCase): self.url = 'file://%s' % self.localpath self.cache_dir = tempfile.mkdtemp(dir=self.basedir) - def testFetch_urlname(self): + def test_fetch_urlname(self): foo_tarball = asset.Asset(self.url, asset_hash=self.assethash, algorithm='sha1', @@ -30,7 +30,7 @@ class TestAsset(unittest.TestCase): expected_tarball = os.path.join(self.cache_dir, self.assetname) self.assertEqual(foo_tarball, expected_tarball) - def testFetch_location(self): + def test_fetch_location(self): foo_tarball = asset.Asset(self.assetname, asset_hash=self.assethash, algorithm='sha1', @@ -40,7 +40,7 @@ class TestAsset(unittest.TestCase): expected_tarball = os.path.join(self.cache_dir, self.assetname) self.assertEqual(foo_tarball, expected_tarball) - def testFecth_expire(self): + def test_fecth_expire(self): foo_tarball = asset.Asset(self.assetname, asset_hash=self.assethash, algorithm='sha1', @@ -81,13 +81,13 @@ class TestAsset(unittest.TestCase): content2 = f.read() self.assertNotEqual(content1, content2) - def testException(self): + def test_exception(self): a = asset.Asset(name='bar.tgz', asset_hash=None, algorithm=None, locations=None, cache_dirs=[self.cache_dir], expire=None) self.assertRaises(EnvironmentError, a.fetch) - def testFetch_lockerror(self): + def test_fetch_lockerror(self): with FileLock(os.path.join(self.cache_dir, self.assetname)): a = asset.Asset(self.url, asset_hash=self.assethash, diff --git a/selftests/unit/test_utils_output.py b/selftests/unit/test_utils_output.py index ed1720e97fd6569216245a801505941e13492c78..426a30011d67600fe855f2d4842b6fc2dba79c54 100644 --- a/selftests/unit/test_utils_output.py +++ b/selftests/unit/test_utils_output.py @@ -5,7 +5,7 @@ from avocado.utils import output class UtilsOutputTest(unittest.TestCase): - def testDisplayDataSizeFactor1024(self): + def test_display_data_size_factor_1024(self): self.assertEqual(output.display_data_size(103), '103.00 B') self.assertEqual(output.display_data_size(1024**1), '1.02 KB') self.assertEqual(output.display_data_size(1024**2), '1.05 MB') @@ -14,7 +14,7 @@ class UtilsOutputTest(unittest.TestCase): self.assertEqual(output.display_data_size(1024**5), '1.13 PB') self.assertEqual(output.display_data_size(1024**6), '1152.92 PB') - def testDisplayDataSizeFactor1000(self): + def test_display_data_size_factor_1000(self): self.assertEqual(output.display_data_size(1000**1), '1.00 KB') self.assertEqual(output.display_data_size(1000**2), '1.00 MB') self.assertEqual(output.display_data_size(1000**3), '1.00 GB') diff --git a/selftests/unit/test_xunit.py b/selftests/unit/test_xunit.py index f8a67bc9da95bea0bdf2664816111e14ee97ce8f..5e88e08adc453b0883eee8c00492eacd7249295c 100644 --- a/selftests/unit/test_xunit.py +++ b/selftests/unit/test_xunit.py @@ -56,7 +56,7 @@ class xUnitSucceedTest(unittest.TestCase): os.remove(self.tmpfile[1]) shutil.rmtree(self.tmpdir) - def testAddSuccess(self): + def test_add_success(self): self.test_result.start_test(self.test1) self.test_result.end_test(self.test1.get_state()) self.test_result.end_tests()