Skip to content

Commit

Permalink
Merge pull request #629 from ldoktor/mux-paths2
Browse files Browse the repository at this point in the history
avocado.multiplexer: Inject YAML files into /run [v2]
  • Loading branch information
lmr committed Jun 2, 2015
2 parents 88b9c8c + 3e5cbc8 commit b6488cc
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 40 deletions.
9 changes: 6 additions & 3 deletions avocado/core/tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ def tree_node_from_values(name, values):
ypath = value[1]
if not os.path.isabs(ypath):
ypath = os.path.join(os.path.dirname(path), ypath)
node.merge(_create_from_yaml(ypath, cls_node))
node.merge(_create_from_yaml('/:' + ypath, cls_node))
elif value[0].code == YAML_USING:
if using:
raise ValueError("!using can be used only once per "
Expand Down Expand Up @@ -445,10 +445,12 @@ def mux_loader(loader, obj):
path = __RE_FILE_SPLIT.split(path, 1)
if len(path) == 1:
path = __RE_FILE_SUBS.sub(':', path[0])
using = None
using = ["run"]
else:
nodes = __RE_FILE_SUBS.sub(':', path[0]).strip('/').split('/')
using = [node for node in nodes if node]
if not path[0].startswith('/'): # relative path, put into /run
using.insert(0, 'run')
path = __RE_FILE_SUBS.sub(':', path[1])

# Load the tree
Expand Down Expand Up @@ -688,5 +690,6 @@ class NamedTreeNodeDebug(TreeNodeDebug): # pylint: disable=R0903
def __init__(self, name='', value=None, parent=None,
children=None):
super(NamedTreeNodeDebug, self).__init__(name, value, parent,
children, path)
children,
path.split(':', 1)[-1])
return NamedTreeNodeDebug
2 changes: 1 addition & 1 deletion avocado/multiplexer.py
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ def __init__(self, args):
self.variants = None
self._mux_entry = getattr(args, 'mux_entry', None)
if self._mux_entry is None:
self._mux_entry = ['/test/*']
self._mux_entry = ['/run/*']

def get_number_of_tests(self, test_suite):
"""
Expand Down
49 changes: 48 additions & 1 deletion docs/source/MultiplexConfig.rst
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ possible and commonly desirable to use non-unique names. But always keep those p
in mind and provide sensible paths.

Multiplexer also supports something called "multiplex entry points" or
"resolution order". By default it's ``/tests/*`` but it can be overridden by
"resolution order". By default it's ``/run/*`` but it can be overridden by
``--mux-entry``, which accepts multiple arguments. What it does it splits
leaves by the provided paths. Each query goes one by one through those
sub-trees and first one to hit the match returns the result. It might not solve
Expand All @@ -216,6 +216,53 @@ Keep in mind that only slices defined in mux-entry are taken into account for
relative paths (the ones starting with ``*``)


Injecting files
===============

You can run any test with any YAML file by::

avocado run sleeptest --multiplex file.yaml

This puts the content of ``file.yaml`` into ``/run``
location, which as mentioned in previous section, is the default ``mux-entry``
path. For most simple cases this is the expected behavior as your files
are available in the default path and you can safely use ``params.get(key)``.

When you need to put a file into a different location, for example
when you have two files and you don't want the content to be merged into
a single place becomming effectively a single blob, you can do that by
giving a name to your yaml file::

avocado run sleeptest --multiplex duration:duration.yaml

The content of ``duration.yaml`` is injected into ``/run/duration``. Still when
keys from other files don't clash, you can use ``params.get(key)`` and retrieve
from this location as it's in the default path, only extended by the
``duration`` intermediary node. Another benefit is you can merge or separate
multiple files by using the same or different name, or even a complex
(relative) path.

Last but not least, advanced users can inject the file into whatever location
they prefer by::

avocado run sleeptest --multiplex /my/variants/duration:duration.yaml

Simple ``params.get(key)`` won't look in this location, which might be the
intention of the test writer. There are several ways to access the values:

* absolute location ``params.get(key, '/my/variants/duration')``
* absolute location with wildcards ``params.get(key, '/my/*)``
(or ``/*/duration/*``...)
* set the mux-entry ``avocado run ... --mux-entry /my/*`` and use relative path

It's recommended to use the simple injection for single YAML files, relative
injection for multiple simple YAML files and the last option is for very
advanced setups when you either can't modify the YAML files and you need to
specify custom resoltion order or you are specifying non-test parameters, for
example parameters for your plugin, which you need to separate from the test
parameters.


Multiple files
==============

Expand Down
57 changes: 31 additions & 26 deletions docs/source/WritingTests.rst
Original file line number Diff line number Diff line change
Expand Up @@ -116,22 +116,23 @@ Avocado finds and populates ``self.params`` with all parameters you define on
a Multiplex Config file (see :doc:`MultiplexConfig`). As an example, consider
the following multiplex file for sleeptest::

test:
sleeptest:
type: "builtin"
short:
sleep_length: 0.5
medium:
sleep_length: 1
long:
sleep_length: 5

In this example 3 variants are executed (see :doc:`MultiplexConfig` for
details). All of them contain variable "type" and "sleep_length". To obtain
current value, you need the name ("sleep_length") and its path. The path
differs for each variant so it's needed to use the most suitable portion
of the path, in this example: "/test/sleeptest/*" or perhaps "sleeptest/*"
might be enough. It depends on how your setups looks like.
sleeptest:
type: "builtin"
short:
sleep_length: 0.5
medium:
sleep_length: 1
long:
sleep_length: 5

When running this example by ``avocado run $test --multiplex $file.yaml``
three variants are executed and the content is injected into ``/run`` namespace
(see :doc:`MultiplexConfig` for details). Every variant contains variables
"type" and "sleep_length". To obtain the current value, you need the name
("sleep_length") and its path. The path differs for each variant so it's
needed to use the most suitable portion of the path, in this example:
"/run/sleeptest/*" or perhaps "sleeptest/*" might be enough. It depends on how
your setup looks like.

The default value is optional, but always keep in mind to handle them nicely.
Someone might be executing your test with different params or without any
Expand Down Expand Up @@ -164,8 +165,8 @@ clearer and easier to follow.
When thinking of the path always think about users. It's common to extend
default config with additional variants or combine them with different
ones to generate just the right scenarios they need. People might
simply inject the values elsewhere (eg. `/test/sleeptest` =>
`/upstream/test/sleeptest`) or they can merge other clashing file into the
simply inject the values elsewhere (eg. `/run/sleeptest` =>
`/upstream/sleeptest`) or they can merge other clashing file into the
default path, which won't generate clash, but would return their values
instead. Then you need to clarify the path (eg. `'*'` => `sleeptest/*`)

Expand All @@ -177,7 +178,7 @@ Using a multiplex file
You may use the avocado runner with a multiplex file to provide params and matrix
generation for sleeptest just like::

$ avocado run sleeptest --multiplex /test:examples/tests/sleeptest.py.data/sleeptest.yaml
$ avocado run sleeptest --multiplex examples/tests/sleeptest.py.data/sleeptest.yaml
JOB ID : d565e8dec576d6040f894841f32a836c751f968f
JOB LOG : $HOME/avocado/job-results/job-2014-08-12T15.44-d565e8de/job.log
JOB HTML : $HOME/avocado/job-results/job-2014-08-12T15.44-d565e8de/html/results.html
Expand All @@ -194,18 +195,22 @@ generation for sleeptest just like::
TIME : 6.52 s

The ``--multiplex`` accepts either only ``$FILE_LOCATION`` or ``$INJECT_TO:$FILE_LOCATION``.
By later you can combine multiple simple YAML files and inject them into a specific location
as shown in the example above. As you learned in previous section the ``/test`` location
is part of default ``mux-entry`` path thus sleeptest can access the values without specifying
the path. To understand the difference execute those commands::
As explained in :doc:`MultiplexConfig` without any path the content gets
injected into ``/run`` in order to be in the default relative path location.
The ``$INJECT_TO`` can be either relative path, then it's injected into
``/run/$INJECT_TO`` location, or absolute path (starting with ``'/'``), then
it's injected directly into the specified path and it's up to the test/framework
developer to get the value from this location (using path or adding the path to
``mux-entry``). To understand the difference execute those commands::

$ avocado multiplex -t examples/tests/sleeptest.py.data/sleeptest.yaml
$ avocado multiplex -t /test:examples/tests/sleeptest.py.data/sleeptest.yaml
$ avocado multiplex -t duration:examples/tests/sleeptest.py.data/sleeptest.yaml
$ avocado multiplex -t /my/location:examples/tests/sleeptest.py.data/sleeptest.yaml

Note that, as your multiplex file specifies all parameters for sleeptest, you
can't leave the test ID empty::

$ scripts/avocado run --multiplex /test:examples/tests/sleeptest/sleeptest.yaml
$ scripts/avocado run --multiplex examples/tests/sleeptest/sleeptest.yaml
Empty test ID. A test path or alias must be provided

You can also execute multiple tests with the same multiplex file::
Expand Down Expand Up @@ -594,7 +599,7 @@ impact your test grid. You can account for that possibility and set up a

::

$ avocado run sleeptest --multiplex /test:/tmp/sleeptest-example.yaml
$ avocado run sleeptest --multiplex /tmp/sleeptest-example.yaml
JOB ID : 6d5a2ff16bb92395100fbc3945b8d253308728c9
JOB LOG : $HOME/avocado/job-results/job-2014-08-12T15.52-6d5a2ff1/job.log
JOB HTML : $HOME/avocado/job-results/job-2014-08-12T15.52-6d5a2ff1/html/results.html
Expand Down
6 changes: 4 additions & 2 deletions selftests/all/functional/avocado/multiplex_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,10 @@ def test_mplex_plugin_nonexistent(self):

def test_mplex_debug(self):
cmd_line = ('./scripts/avocado multiplex -c -d '
'examples/mux-selftest.yaml examples/mux-environment.yaml '
'examples/mux-selftest.yaml examples/mux-environment.yaml')
'/:examples/mux-selftest.yaml '
'/:examples/mux-environment.yaml '
'/:examples/mux-selftest.yaml '
'/:examples/mux-environment.yaml')
expected_rc = 0
result = self.run_and_check(cmd_line, expected_rc)
self.assertIn(DEBUG_OUT, result.stdout)
Expand Down
11 changes: 6 additions & 5 deletions selftests/all/unit/avocado/multiplexer_unittest.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
else:
PATH_PREFIX = ""

TREE = tree.create_from_yaml([PATH_PREFIX + 'examples/mux-selftest.yaml'])
TREE = tree.create_from_yaml(['/:' + PATH_PREFIX +
'examples/mux-selftest.yaml'])


def combine(leaves_pools):
Expand Down Expand Up @@ -42,20 +43,20 @@ def test_full(self):
self.assertEqual(len(self.mux_full), 12)

def test_create_variants(self):
from_file = multiplexer.multiplex_yamls([PATH_PREFIX + 'examples/mux-selftest.yaml'])
from_file = multiplexer.multiplex_yamls(['/:' + PATH_PREFIX + 'examples/mux-selftest.yaml'])
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 = tuple(multiplexer.multiplex_yamls([PATH_PREFIX + 'examples/mux-selftest.yaml'],
act = tuple(multiplexer.multiplex_yamls(['/:' + PATH_PREFIX + 'examples/mux-selftest.yaml'],
('/hw/cpu/intel',
'/distro/fedora',
'/hw')))
self.assertEqual(act, exp)

def test_filter_out(self):
act = tuple(multiplexer.multiplex_yamls([PATH_PREFIX + 'examples/mux-selftest.yaml'],
act = tuple(multiplexer.multiplex_yamls(['/:' + PATH_PREFIX + 'examples/mux-selftest.yaml'],
None,
('/hw/cpu/intel',
'/distro/fedora',
Expand All @@ -70,7 +71,7 @@ def test_filter_out(self):


class TestAvocadoParams(unittest.TestCase):
yamls = iter(multiplexer.multiplex_yamls([PATH_PREFIX + 'examples/mux-selftest-params.'
yamls = iter(multiplexer.multiplex_yamls(['/:' + PATH_PREFIX + 'examples/mux-selftest-params.'
'yaml']))
params1 = multiplexer.AvocadoParams(yamls.next(), 'Unittest1', 1,
['/ch0/*', '/ch1/*'], {})
Expand Down
5 changes: 3 additions & 2 deletions selftests/all/unit/avocado/tree_unittest.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

class TestTree(unittest.TestCase):
# Share tree with all tests
tree = tree.create_from_yaml(['examples/mux-selftest.yaml'])
tree = tree.create_from_yaml(['/:examples/mux-selftest.yaml'])

def test_node_order(self):
self.assertIsInstance(self.tree, tree.TreeNode)
Expand Down Expand Up @@ -154,7 +154,8 @@ def test_merge_trees(self):
tree2.children[0].children[2].children[1].value)

def test_advanced_yaml(self):
tree2 = tree.create_from_yaml(['examples/mux-selftest-advanced.yaml'])
tree2 = tree.create_from_yaml(['/:examples/mux-selftest-advanced.'
'yaml'])
exp = ['intel', 'amd', 'arm', 'scsi', 'virtio', 'fedora', '6',
'7', 'gentoo', 'mint', 'prod', 'new_node']
act = tree2.get_leaves()
Expand Down

0 comments on commit b6488cc

Please sign in to comment.