未验证 提交 e0397091 编写于 作者: L Lucas Meneghel Rodrigues

Merge branch 'clebert push origin mastergnu-move_yaml_to_mux_tests_v2'

......@@ -36,11 +36,8 @@ original base tree code and re-license under GPLv2+, given that GPLv3 and GPLv2
import collections
import itertools
import locale
import os
from six import string_types, iterkeys, iteritems
from . import output
from six import string_types, iteritems
class FilterSet(set):
......@@ -369,141 +366,6 @@ class TreeNode(object):
return self
#
# Debug version of TreeNode with additional utilities.
#
class OutputValue(object): # only container pylint: disable=R0903
""" Ordinary value with some debug info """
def __init__(self, value, node, srcyaml):
self.value = value
self.node = node
self.yaml = srcyaml
def __str__(self):
return "%s%s@%s:%s%s" % (self.value,
output.TERM_SUPPORT.LOWLIGHT,
self.yaml, self.node.path,
output.TERM_SUPPORT.ENDC)
class OutputList(list): # only container pylint: disable=R0903
""" List with some debug info """
def __init__(self, values, nodes, yamls):
super(OutputList, self).__init__(values)
self.nodes = nodes
self.yamls = yamls
def __add__(self, other):
""" Keep attrs separate in order to print the origins """
value = super(OutputList, self).__add__(other)
return OutputList(value,
self.nodes + other.nodes,
self.yamls + other.yamls)
def __str__(self):
color = output.TERM_SUPPORT.LOWLIGHT
cend = output.TERM_SUPPORT.ENDC
return ' + '.join("%s%s@%s:%s%s"
% (_[0], color, _[1], _[2].path, cend)
for _ in itertools.izip(self, self.yamls,
self.nodes))
class ValueDict(dict): # only container pylint: disable=R0903
""" Dict which stores the origin of the items """
def __init__(self, srcyaml, node, values):
super(ValueDict, self).__init__()
self.yaml = srcyaml
self.node = node
self.yaml_per_key = {}
for key, value in iteritems(values):
self[key] = value
def __setitem__(self, key, value):
""" Store yaml_per_key and value """
# Merge is responsible to set `self.yaml` to current file
self.yaml_per_key[key] = self.yaml
return super(ValueDict, self).__setitem__(key, value)
def __getitem__(self, key):
"""
This is debug run. Fake the results and return either
OutputValue (let's call it string) and OutputList. These
overrides the `__str__` and return string with origin.
:warning: Returned values are unusable in tests!
"""
value = super(ValueDict, self).__getitem__(key)
origin = self.yaml_per_key.get(key)
if isinstance(value, list):
value = OutputList([value], [self.node], [origin])
else:
value = OutputValue(value, self.node, origin)
return value
def iteritems(self):
""" Slower implementation with the use of __getitem__ """
for key in iterkeys(self):
yield key, self[key]
raise StopIteration
class TreeNodeDebug(TreeNode): # only container pylint: disable=R0903
"""
Debug version of TreeNodeDebug
:warning: Origin of the value is appended to all values thus it's not
suitable for running tests.
"""
def __init__(self, name='', value=None, parent=None, children=None,
srcyaml=None):
if value is None:
value = {}
if srcyaml:
srcyaml = os.path.relpath(srcyaml)
super(TreeNodeDebug, self).__init__(name,
ValueDict(srcyaml, self, value),
parent, children)
self.yaml = srcyaml
def merge(self, other):
"""
Override origin with the one from other tree. Updated/Newly set values
are going to use this location as origin.
"""
if hasattr(other, 'yaml') and other.yaml:
srcyaml = os.path.relpath(other.yaml)
# when we use TreeNodeDebug, value is always ValueDict
self.value.yaml_per_key.update(other.value.yaml_per_key) # pylint: disable=E1101
else:
srcyaml = "Unknown"
self.yaml = srcyaml
self.value.yaml = srcyaml
return super(TreeNodeDebug, self).merge(other)
def get_named_tree_cls(path, klass=TreeNodeDebug):
""" Return TreeNodeDebug class with hardcoded yaml path """
class NamedTreeNodeDebug(klass): # pylint: disable=R0903
""" Fake class with hardcoded yaml path """
def __init__(self, name='', value=None, parent=None,
children=None):
super(NamedTreeNodeDebug, self).__init__(name, value, parent,
children,
path.split(':', 1)[-1])
return NamedTreeNodeDebug
def tree_view(root, verbose=None, use_utf8=None):
"""
Generate tree-view of the given node
......
......@@ -20,27 +20,21 @@ import os
import re
import sys
import yaml
try:
from yaml import CLoader as Loader
except ImportError:
from yaml import Loader
from six import iteritems
from avocado.core import tree, exit_codes
from avocado.core import exit_codes
from avocado.core.output import LOG_UI
from avocado.core.plugin_interfaces import CLI, Varianter
from . import mux
try:
import yaml
except ImportError:
MULTIPLEX_CAPABLE = False
else:
MULTIPLEX_CAPABLE = True
try:
from yaml import CLoader as Loader
except ImportError:
from yaml import Loader
# Mapping for yaml flags
YAML_INCLUDE = 100
YAML_USING = 101
......@@ -288,6 +282,20 @@ def _create_from_yaml(path, cls_node=mux.MuxTreeNode):
return loaded_tree
def get_named_tree_cls(path, klass):
""" Return TreeNodeDebug class with hardcoded yaml path """
class NamedTreeNodeDebug(klass): # pylint: disable=R0903
""" Fake class with hardcoded yaml path """
def __init__(self, name='', value=None, parent=None,
children=None):
super(NamedTreeNodeDebug, self).__init__(name, value, parent,
children,
path.split(':', 1)[-1])
return NamedTreeNodeDebug
def create_from_yaml(paths, debug=False):
"""
Create tree structure from yaml-like file
......@@ -303,7 +311,7 @@ def create_from_yaml(paths, debug=False):
def _merge_debug(data, path):
"""Use NamedTreeNodeDebug magic"""
node_cls = tree.get_named_tree_cls(path, mux.MuxTreeNodeDebug)
node_cls = get_named_tree_cls(path, mux.MuxTreeNodeDebug)
tmp = _create_from_yaml(path, node_cls)
if tmp:
data.merge(tmp)
......@@ -342,8 +350,6 @@ class YamlToMuxCLI(CLI):
"""
Configures "run" and "variants" subparsers
"""
if not MULTIPLEX_CAPABLE:
return
for name in ("run", "multiplex", "variants"):
subparser = parser.subcommands.choices.get(name, None)
if subparser is None:
......
......@@ -24,11 +24,14 @@ a custom Varianter plugin.
import collections
import itertools
import re
import os
from six import iterkeys, iteritems
from six.moves import xrange as range
from avocado.core import tree
from avocado.core import varianter
from avocado.core import output
#
......@@ -233,6 +236,87 @@ class MuxPlugin(object):
return sum(1 for _ in self)
class OutputValue(object): # only container pylint: disable=R0903
""" Ordinary value with some debug info """
def __init__(self, value, node, srcyaml):
self.value = value
self.node = node
self.yaml = srcyaml
def __str__(self):
return "%s%s@%s:%s%s" % (self.value,
output.TERM_SUPPORT.LOWLIGHT,
self.yaml, self.node.path,
output.TERM_SUPPORT.ENDC)
class OutputList(list): # only container pylint: disable=R0903
""" List with some debug info """
def __init__(self, values, nodes, yamls):
super(OutputList, self).__init__(values)
self.nodes = nodes
self.yamls = yamls
def __add__(self, other):
""" Keep attrs separate in order to print the origins """
value = super(OutputList, self).__add__(other)
return OutputList(value,
self.nodes + other.nodes,
self.yamls + other.yamls)
def __str__(self):
color = output.TERM_SUPPORT.LOWLIGHT
cend = output.TERM_SUPPORT.ENDC
return ' + '.join("%s%s@%s:%s%s"
% (_[0], color, _[1], _[2].path, cend)
for _ in itertools.izip(self, self.yamls,
self.nodes))
class ValueDict(dict): # only container pylint: disable=R0903
""" Dict which stores the origin of the items """
def __init__(self, srcyaml, node, values):
super(ValueDict, self).__init__()
self.yaml = srcyaml
self.node = node
self.yaml_per_key = {}
for key, value in iteritems(values):
self[key] = value
def __setitem__(self, key, value):
""" Store yaml_per_key and value """
# Merge is responsible to set `self.yaml` to current file
self.yaml_per_key[key] = self.yaml
return super(ValueDict, self).__setitem__(key, value)
def __getitem__(self, key):
"""
This is debug run. Fake the results and return either
OutputValue (let's call it string) and OutputList. These
overrides the `__str__` and return string with origin.
:warning: Returned values are unusable in tests!
"""
value = super(ValueDict, self).__getitem__(key)
origin = self.yaml_per_key.get(key)
if isinstance(value, list):
value = OutputList([value], [self.node], [origin])
else:
value = OutputValue(value, self.node, origin)
return value
def iteritems(self):
""" Slower implementation with the use of __getitem__ """
for key in iterkeys(self):
yield key, self[key]
raise StopIteration
class Control(object): # Few methods pylint: disable=R0903
""" Container used to identify node vs. control sequence """
......@@ -293,7 +377,42 @@ class MuxTreeNode(tree.TreeNode):
self.multiplex = False
class MuxTreeNodeDebug(MuxTreeNode, tree.TreeNodeDebug):
class TreeNodeDebug(tree.TreeNode): # only container pylint: disable=R0903
"""
Debug version of TreeNodeDebug
:warning: Origin of the value is appended to all values thus it's not
suitable for running tests.
"""
def __init__(self, name='', value=None, parent=None, children=None,
srcyaml=None):
if value is None:
value = {}
if srcyaml:
srcyaml = os.path.relpath(srcyaml)
super(TreeNodeDebug, self).__init__(name,
ValueDict(srcyaml, self, value),
parent, children)
self.yaml = srcyaml
def merge(self, other):
"""
Override origin with the one from other tree. Updated/Newly set values
are going to use this location as origin.
"""
if hasattr(other, 'yaml') and other.yaml:
srcyaml = os.path.relpath(other.yaml)
# when we use TreeNodeDebug, value is always ValueDict
self.value.yaml_per_key.update(other.value.yaml_per_key) # pylint: disable=E1101
else:
srcyaml = "Unknown"
self.yaml = srcyaml
self.value.yaml = srcyaml
return super(TreeNodeDebug, self).merge(other)
class MuxTreeNodeDebug(MuxTreeNode, TreeNodeDebug):
"""
Debug version of TreeNodeDebug
......@@ -304,12 +423,12 @@ class MuxTreeNodeDebug(MuxTreeNode, tree.TreeNodeDebug):
def __init__(self, name='', value=None, parent=None, children=None,
srcyaml=None):
MuxTreeNode.__init__(self, name, value, parent, children)
tree.TreeNodeDebug.__init__(self, name, value, parent, children,
srcyaml)
TreeNodeDebug.__init__(self, name, value, parent, children,
srcyaml)
def merge(self, other):
MuxTreeNode.merge(self, other)
tree.TreeNodeDebug.merge(self, other)
TreeNodeDebug.merge(self, other)
#
......
......@@ -25,6 +25,7 @@ setup(name='avocado-framework-plugin-varianter-yaml-to-mux',
packages=find_packages(),
include_package_data=True,
install_requires=['avocado-framework', 'PyYAML'],
test_suite='tests',
entry_points={
"avocado.plugins.cli": [
"yaml_to_mux = avocado_varianter_yaml_to_mux:YamlToMuxCLI",
......
......@@ -7,20 +7,20 @@ from avocado.core import exit_codes
from avocado.utils import process
basedir = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..')
basedir = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..', '..')
basedir = os.path.abspath(basedir)
AVOCADO = os.environ.get("UNITTEST_AVOCADO_CMD", "./scripts/avocado")
DEBUG_OUT = """Variant mint-debug-amd-virtio-07c6: amd@selftests/.data/mux-environment.yaml, virtio@selftests/.data/mux-environment.yaml, mint@selftests/.data/mux-environment.yaml, debug@selftests/.data/mux-environment.yaml
/distro/mint:init => systemv@selftests/.data/mux-environment.yaml:/distro/mint
/env/debug:opt_CFLAGS => -O0 -g@selftests/.data/mux-environment.yaml:/env/debug
/hw/cpu/amd:cpu_CFLAGS => -march=athlon64@selftests/.data/mux-environment.yaml:/hw/cpu/amd
/hw/cpu/amd:joinlist => ['first_item']@selftests/.data/mux-selftest.yaml:/hw/cpu + ['second', 'third']@selftests/.data/mux-selftest.yaml:/hw/cpu/amd
/hw/disk/virtio:disk_type => virtio@selftests/.data/mux-environment.yaml:/hw/disk/virtio
/hw/disk:corruptlist => nonlist@selftests/.data/mux-selftest.yaml:/hw/disk
/hw:corruptlist => ['upper_node_list']@selftests/.data/mux-selftest.yaml:/hw
DEBUG_OUT = """
Variant mint-debug-amd-virtio-935e: amd@optional_plugins/varianter_yaml_to_mux/tests/.data/mux-environment.yaml, virtio@optional_plugins/varianter_yaml_to_mux/tests/.data/mux-environment.yaml, mint@optional_plugins/varianter_yaml_to_mux/tests/.data/mux-environment.yaml, debug@optional_plugins/varianter_yaml_to_mux/tests/.data/mux-environment.yaml
/distro/mint:init => systemv@optional_plugins/varianter_yaml_to_mux/tests/.data/mux-environment.yaml:/distro/mint
/env/debug:opt_CFLAGS => -O0 -g@optional_plugins/varianter_yaml_to_mux/tests/.data/mux-environment.yaml:/env/debug
/hw/cpu/amd:cpu_CFLAGS => -march=athlon64@optional_plugins/varianter_yaml_to_mux/tests/.data/mux-environment.yaml:/hw/cpu/amd
/hw/cpu/amd:joinlist => ['first_item']@optional_plugins/varianter_yaml_to_mux/tests/.data/mux-selftest.yaml:/hw/cpu + ['second', 'third']@optional_plugins/varianter_yaml_to_mux/tests/.data/mux-selftest.yaml:/hw/cpu/amd
/hw/disk/virtio:disk_type => virtio@optional_plugins/varianter_yaml_to_mux/tests/.data/mux-environment.yaml:/hw/disk/virtio
/hw/disk:corruptlist => nonlist@optional_plugins/varianter_yaml_to_mux/tests/.data/mux-selftest.yaml:/hw/disk
/hw:corruptlist => ['upper_node_list']@optional_plugins/varianter_yaml_to_mux/tests/.data/mux-selftest.yaml:/hw
"""
......@@ -56,10 +56,11 @@ class MultiplexTests(unittest.TestCase):
def test_mplex_debug(self):
cmd_line = ('%s variants -c -d -m '
'/:selftests/.data/mux-selftest.yaml '
'/:selftests/.data/mux-environment.yaml '
'/:selftests/.data/mux-selftest.yaml '
'/:selftests/.data/mux-environment.yaml' % AVOCADO)
'/:optional_plugins/varianter_yaml_to_mux/tests/.data/mux-selftest.yaml '
'/:optional_plugins/varianter_yaml_to_mux/tests/.data/mux-environment.yaml '
'/:optional_plugins/varianter_yaml_to_mux/tests/.data/mux-selftest.yaml '
'/:optional_plugins/varianter_yaml_to_mux/tests/.data/mux-environment.yaml'
% AVOCADO)
expected_rc = exit_codes.AVOCADO_ALL_OK
result = self.run_and_check(cmd_line, expected_rc)
self.assertIn(DEBUG_OUT, result.stdout)
......@@ -133,9 +134,9 @@ class MultiplexTests(unittest.TestCase):
self.run_and_check(cmd_line, expected_rc, (4, 0))
def test_empty_file(self):
cmd_line = ("%s run --job-results-dir %s -m selftests/.data/empty_file"
" -- passtest.py"
% (AVOCADO, self.tmpdir))
cmd_line = ("%s run --job-results-dir %s -m optional_plugins/"
"varianter_yaml_to_mux/tests/.data/empty_file -- "
"passtest.py" % (AVOCADO, self.tmpdir))
result = self.run_and_check(cmd_line, exit_codes.AVOCADO_ALL_OK,
(1, 0))
......
......@@ -11,11 +11,9 @@ import avocado_varianter_yaml_to_mux as yaml_to_mux
from avocado_varianter_yaml_to_mux import mux
from avocado.core import tree, parameters
BASEDIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..')
BASEDIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..')
BASEDIR = os.path.abspath(BASEDIR)
PATH_PREFIX = os.path.relpath(BASEDIR) + os.path.sep
def combine(leaves_pools):
""" Joins remaining leaves and pools and create product """
......@@ -26,8 +24,9 @@ def combine(leaves_pools):
class TestMuxTree(unittest.TestCase):
# Share tree with all tests
tree = yaml_to_mux.create_from_yaml(['/:' + PATH_PREFIX +
'selftests/.data/mux-selftest.yaml'])
tree_yaml_path = os.path.join(BASEDIR, 'tests/.data/mux-selftest.yaml')
tree_yaml_url = '/:%s' % tree_yaml_path
tree = yaml_to_mux.create_from_yaml([tree_yaml_url])
def test_node_order(self):
self.assertIsInstance(self.tree, mux.MuxTreeNode)
......@@ -167,9 +166,10 @@ class TestMuxTree(unittest.TestCase):
tree2.children[0].children[2].children[1].value)
def test_advanced_yaml(self):
tree2 = yaml_to_mux.create_from_yaml(['/:' + PATH_PREFIX +
'selftests/.data/mux-selftest-advanced.'
'yaml'])
tree2_yaml_path = os.path.join(BASEDIR,
'tests/.data/mux-selftest-advanced.yaml')
tree2_yaml_url = '/:%s' % tree2_yaml_path
tree2 = yaml_to_mux.create_from_yaml([tree2_yaml_url])
exp = ['intel', 'amd', 'arm', 'scsi', 'virtio', 'fedora', '6',
'7', 'gentoo', 'mint', 'prod', 'new_node', 'on', 'dict']
act = tree2.get_leaves()
......@@ -235,12 +235,10 @@ class TestMuxTree(unittest.TestCase):
class TestMultiplex(unittest.TestCase):
@unittest.skipIf(not yaml_to_mux.MULTIPLEX_CAPABLE,
"Not multiplex capable")
def setUp(self):
self.mux_tree = yaml_to_mux.create_from_yaml(['/:' + PATH_PREFIX +
'selftests/.data/mux-selftest.'
'yaml'])
tree_yaml_path = os.path.join(BASEDIR, 'tests/.data/mux-selftest.yaml')
tree_yaml_url = '/:%s' % tree_yaml_path
self.mux_tree = yaml_to_mux.create_from_yaml([tree_yaml_url])
self.mux_full = tuple(mux.MuxTree(self.mux_tree))
def test_empty(self):
......@@ -257,24 +255,27 @@ class TestMultiplex(unittest.TestCase):
self.assertEqual(len(self.mux_full), 12)
def test_create_variants(self):
from_file = yaml_to_mux.create_from_yaml(
["/:" + PATH_PREFIX + 'selftests/.data/mux-selftest.yaml'])
tree_yaml_path = os.path.join(BASEDIR, 'tests/.data/mux-selftest.yaml')
tree_yaml_url = '/:%s' % tree_yaml_path
from_file = yaml_to_mux.create_from_yaml([tree_yaml_url])
from_file = mux.MuxTree(from_file)
self.assertEqual(self.mux_full, tuple(from_file))
# Filters are tested in tree_unittests, only verify `multiplex_yamls` calls
def test_filter_only(self):
exp = (['intel', 'scsi'], ['intel', 'virtio'])
act = yaml_to_mux.create_from_yaml(["/:" + PATH_PREFIX +
'selftests/.data/mux-selftest.yaml'])
tree_yaml_path = os.path.join(BASEDIR, 'tests/.data/mux-selftest.yaml')
tree_yaml_url = '/:%s' % tree_yaml_path
act = yaml_to_mux.create_from_yaml([tree_yaml_url])
act = mux.apply_filters(act, ('/hw/cpu/intel', '/distro/fedora',
'/hw'))
act = tuple(mux.MuxTree(act))
self.assertEqual(act, exp)
def test_filter_out(self):
act = yaml_to_mux.create_from_yaml(["/:" + PATH_PREFIX +
'selftests/.data/mux-selftest.yaml'])
tree_yaml_path = os.path.join(BASEDIR, 'tests/.data/mux-selftest.yaml')
tree_yaml_url = '/:%s' % tree_yaml_path
act = yaml_to_mux.create_from_yaml([tree_yaml_url])
act = mux.apply_filters(act, None, ('/hw/cpu/intel', '/distro/fedora',
'/distro'))
act = tuple(mux.MuxTree(act))
......@@ -290,8 +291,9 @@ class TestMultiplex(unittest.TestCase):
class TestAvocadoParams(unittest.TestCase):
def setUp(self):
yamls = yaml_to_mux.create_from_yaml(["/:" + PATH_PREFIX +
'selftests/.data/mux-selftest-params.yaml'])
yaml_path = os.path.join(BASEDIR, 'tests/.data/mux-selftest-params.yaml')
yaml_url = '/:%s' % yaml_path
yamls = yaml_to_mux.create_from_yaml([yaml_url])
self.yamls = iter(mux.MuxTree(yamls))
self.params1 = parameters.AvocadoParams(next(self.yamls),
['/ch0/*', '/ch1/*'])
......@@ -300,13 +302,11 @@ class TestAvocadoParams(unittest.TestCase):
self.params2 = parameters.AvocadoParams(next(self.yamls),
['/ch1/*', '/ch0/*'])
@unittest.skipIf(not yaml_to_mux.MULTIPLEX_CAPABLE, "Not multiplex capable")
def test_pickle(self):
params = pickle.dumps(self.params1, 2) # protocol == 2
params = pickle.loads(params)
self.assertEqual(self.params1, params)
@unittest.skipIf(not yaml_to_mux.MULTIPLEX_CAPABLE, "Not multiplex capable")
def test_basic(self):
self.assertEqual(self.params1, self.params1)
self.assertNotEqual(self.params1, self.params2)
......@@ -315,7 +315,6 @@ class TestAvocadoParams(unittest.TestCase):
str(parameters.AvocadoParams([], []))
self.assertEqual(15, sum([1 for _ in iteritems(self.params1)]))
@unittest.skipIf(not yaml_to_mux.MULTIPLEX_CAPABLE, "Not multiplex capable")
def test_unhashable(self):
""" Verifies that unhashable arguments can be passed to params.get """
self.assertEqual(self.params1.get("root", "/ch0/", ["foo"]), ["foo"])
......@@ -323,7 +322,6 @@ class TestAvocadoParams(unittest.TestCase):
'/ch0/ch0.1/ch0.1.1/ch0.1.1.1/',
['bar']), 'unique1')
@unittest.skipIf(not yaml_to_mux.MULTIPLEX_CAPABLE, "Not multiplex capable")
def test_get_abs_path(self):
# /ch0/ is not leaf thus it's not queryable
self.assertEqual(self.params1.get('root', '/ch0/', 'bbb'), 'bbb')
......@@ -345,7 +343,6 @@ class TestAvocadoParams(unittest.TestCase):
'/ch0/ch0.1/ch0.1.1/ch0.1.1.1/',
'hhh'), 'hhh')
@unittest.skipIf(not yaml_to_mux.MULTIPLEX_CAPABLE, "Not multiplex capable")
def test_get_greedy_path(self):
self.assertEqual(self.params1.get('unique1', '/*/*/*/ch0.1.1.1/',
111), 'unique1')
......@@ -369,7 +366,6 @@ class TestAvocadoParams(unittest.TestCase):
# path matches nothing
self.assertEqual(self.params1.get('root', '', 999), 999)
@unittest.skipIf(not yaml_to_mux.MULTIPLEX_CAPABLE, "Not multiplex capable")
def test_get_rel_path(self):
self.assertEqual(self.params1.get('root', default='iii'), 'root')
self.assertEqual(self.params1.get('unique1', '*', 'jjj'), 'unique1')
......@@ -384,7 +380,6 @@ class TestAvocadoParams(unittest.TestCase):
self.assertEqual(self.params2.get('unique1', '*/ch0.1.1.1/', 'ooo'),
'ooo')
@unittest.skipIf(not yaml_to_mux.MULTIPLEX_CAPABLE, "Not multiplex capable")
def test_get_clashes(self):
# One inherited, the other is new
self.assertRaisesRegexp(ValueError, r"'clash1'.* \['/ch0/ch0.1/ch0.1.1"
......@@ -417,18 +412,15 @@ class TestMultipleLoaders(unittest.TestCase):
"""
Verifies that `create_from_yaml` does not affects the main yaml.Loader
"""
nondebug = yaml_to_mux.create_from_yaml(['/:' + PATH_PREFIX +
'selftests/.data/mux-selftest.'
'yaml'])
yaml_path = os.path.join(BASEDIR, 'tests/.data/mux-selftest.yaml')
yaml_url = '/:%s' % yaml_path
nondebug = yaml_to_mux.create_from_yaml([yaml_url])
self.assertEqual(type(nondebug), mux.MuxTreeNode)
self.assertEqual(type(nondebug.children[0]), mux.MuxTreeNode)
debug = yaml_to_mux.create_from_yaml(['/:' + PATH_PREFIX +
'selftests/.data/mux-selftest.'
'yaml'],
debug=True)
debug = yaml_to_mux.create_from_yaml([yaml_url], debug=True)
self.assertEqual(type(debug), mux.MuxTreeNodeDebug)
# Debug nodes are of generated "NamedTreeNodeDebug" type
self.assertEqual("<class 'avocado.core.tree.NamedTreeNodeDebug'>",
self.assertEqual("<class 'avocado_varianter_yaml_to_mux.NamedTreeNodeDebug'>",
str(type(debug.children[0])))
plain = yaml.load("foo: bar")
self.assertEqual(type(plain), dict)
......
......@@ -22,64 +22,109 @@ run_rc() {
parallel_selftests() {
local START=$(date +%s)
local ERR=0
# Use sort -R to randomize the order as longer tests seems to be likely in the same file
local ALL=($(./contrib/scripts/avocado-find-unittests selftests/*/*.py | sort -R))
[ ${#ALL[@]} -eq 0 ] && return 0
local FIND_UNITTESTS=$(realpath ./contrib/scripts/avocado-find-unittests)
local NO_WORKERS=$(($(cat /proc/cpuinfo | grep -c processor) * 2))
local PER_SLICE=$((${#ALL[@]} / $NO_WORKERS))
[ $PER_SLICE -eq 0 ] && PER_SLICE=1
local PIDS=()
local TMPS=()
for I in $(seq 0 $PER_SLICE $((${#ALL[@]} - 1))); do
TMP=$(mktemp /tmp/avocado_parallel_unittest_output_XXXXXX)
TMPS+=("$TMP")
( python -m unittest ${ALL[@]:$I:$PER_SLICE} &> $TMP ) &
PIDS+=("$!")
sleep 0.1
done
FAILED_ONCE=()
for I in $(seq 0 $((${#PIDS[@]} - 1))); do
wait ${PIDS[$I]}
RET=$?
if [ $RET -ne 0 ]; then
for FAILURE in $(cat "${TMPS[$I]}" | sed -n 's/\(ERROR\|FAIL\): \([^ ]*\) (\([^)]*\)).*/\3.\2/p'); do
FAILED_ONCE+=("$FAILURE")
done
else
rm ${TMPS[$I]}
# The directories that may contain files with tests, from the Avocado core
# and from all optional plugins
declare -A DIR_GLOB_MAP
DIR_GLOB_MAP[selftests]="selftests/unit/test_*.py selftests/functional/test_*.py selftests/doc/test_*.py"
for PLUGIN in $(find optional_plugins -mindepth 1 -maxdepth 1 -type d); do
DIR_GLOB_MAP[$PLUGIN]="tests/test_*.py"
done;
declare -A TESTS
for TEST_DIR in "${!DIR_GLOB_MAP[@]}"; do
# tests in core, that is "selftests" expect the regular path, while
# python -m unittest module.class.test_name won't work for tests on
# plugins without a change of directory because the full path is
# not a valid python module (would need __init__.py) in places where
# it doesn't make sense
if [ "x$TEST_DIR" != "xselftests" ]; then
OLD_PWD=$PWD
cd $TEST_DIR
fi
# Use sort -R to randomize the order as longer tests
# seems to be likely in the same file
THIS_DIR_TESTS=$(${FIND_UNITTESTS} ${DIR_GLOB_MAP[$TEST_DIR]} | sort -R)
if [ -n "$THIS_DIR_TESTS" ]; then
TESTS[$TEST_DIR]=${THIS_DIR_TESTS};
fi
if [ -n $TEST_DIR ]; then
cd $OLD_PWD
fi
done
if [ ${#FAILED_ONCE[@]} -gt 0 ]; then
if [ ${#FAILED_ONCE[@]} -le 10 ]; then
echo ${#FAILED_ONCE[@]} failed during parallel execution, trying them in series
echo "python -m unittest --failfast ${FAILED_ONCE[@]}"
if python -m unittest --failfast ${FAILED_ONCE[@]}; then
echo "All failed tests passed when executed in series"
echo
for I in $(seq 0 $((${#PIDS[@]} - 1))); do
[ -e "${TMPS[$I]}" ] && rm "${TMPS[$I]}"
for TEST_DIR in "${!TESTS[@]}"; do
if [ "x$TEST_DIR" != "xselftests" ]; then
OLD_PWD=$PWD
cd $TEST_DIR
fi
declare -a ALL
ALL=(${TESTS[$TEST_DIR]})
local PER_SLICE=$((${#ALL[@]} / $NO_WORKERS))
[ $PER_SLICE -eq 0 ] && PER_SLICE=1
local PIDS=()
local TMPS=()
for I in $(seq 0 $PER_SLICE $((${#ALL[@]} - 1))); do
TMP=$(mktemp /tmp/avocado_parallel_unittest_output_XXXXXX)
TMPS+=("$TMP")
( python -m unittest ${ALL[@]:$I:$PER_SLICE} &> $TMP ) &
PIDS+=("$!")
sleep 0.1
done
FAILED_ONCE=()
for I in $(seq 0 $((${#PIDS[@]} - 1))); do
wait ${PIDS[$I]}
RET=$?
if [ $RET -ne 0 ]; then
for FAILURE in $(cat "${TMPS[$I]}" | sed -n 's/\(ERROR\|FAIL\): \([^ ]*\) (\([^)]*\)).*/\3.\2/p'); do
FAILED_ONCE+=("$FAILURE")
done
else
echo
echo "Some test(s) failed in series as well, showing failures from parallel run:"
rm ${TMPS[$I]}
fi
done
if [ ${#FAILED_ONCE[@]} -gt 0 ]; then
if [ ${#FAILED_ONCE[@]} -le 10 ]; then
echo ${#FAILED_ONCE[@]} failed during parallel execution, trying them in series
echo "python -m unittest --failfast ${FAILED_ONCE[@]}"
if python -m unittest --failfast ${FAILED_ONCE[@]}; then
echo "All failed tests passed when executed in series"
echo
for I in $(seq 0 $((${#PIDS[@]} - 1))); do
[ -e "${TMPS[$I]}" ] && rm "${TMPS[$I]}"
done
else
echo
echo "Some test(s) failed in series as well, showing failures from parallel run:"
ERR=1
fi
else
echo "${#FAILED_ONCE[@]} tests failed during execution, not trying to re-run them."
ERR=1
fi
else
echo "${#FAILED_ONCE[@]} tests failed during execution, not trying to re-run them."
ERR=1
fi
fi
# Remove all tmp files
for I in $(seq 0 $((${#PIDS[@]} - 1))); do
if [ -e "${TMPS[$I]}" ]; then
echo
echo python -m unittest ${ALL[@]:$(($I * $PER_SLICE)):$PER_SLICE}
cat "${TMPS[$I]}"
rm "${TMPS[$I]}"
# Remove all tmp files
for I in $(seq 0 $((${#PIDS[@]} - 1))); do
if [ -e "${TMPS[$I]}" ]; then
echo
echo python -m unittest ${ALL[@]:$(($I * $PER_SLICE)):$PER_SLICE}
cat "${TMPS[$I]}"
rm "${TMPS[$I]}"
fi
done
echo ----------------------------------------------------------------------
echo Ran ${#ALL[@]} tests for $TEST_DIR in $(($(date +%s) - START))s
if [ -n $TEST_DIR ]; then
cd $OLD_PWD
fi
done
echo ----------------------------------------------------------------------
echo Ran ${#ALL[@]} tests in $(($(date +%s) - START))s
done;
return $ERR
}
......
......@@ -5,19 +5,26 @@ __author__ = 'Lucas Meneghel Rodrigues <lmr@redhat.com>'
import gc
import os
import pkg_resources
import subprocess
import sys
import logging
import unittest
from avocado.core import data_dir
logger = logging.getLogger(__name__)
CHECK_TMP_DIRS = os.path.abspath(os.path.join(os.path.dirname(__file__),
"check_tmp_dirs"))
def plugin_available(plugin_name):
try:
pkg_resources.require(plugin_name)
return True
except pkg_resources.DistributionNotFound:
return False
def test_suite():
suite = unittest.TestSuite()
loader = unittest.TestLoader()
......@@ -26,6 +33,11 @@ def test_suite():
for section in ('unit', 'functional', 'doc'):
suite.addTests(loader.discover(start_dir=os.path.join(selftests_dir, section),
top_level_dir=basedir))
# when other plugins get their own tests, make this a generic loop
if plugin_available('avocado-framework-plugin-varianter-yaml-to-mux'):
path = os.path.join(basedir, 'optional_plugins',
'varianter_yaml_to_mux', 'tests')
suite.addTests(loader.discover(start_dir=path, top_level_dir=path))
return suite
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册