提交 252f8be2 编写于 作者: C Cleber Rosa

Add core test parameter passing support (non-varianter based)

Currently, the only way to pass parameters to Avocado is by using the
variants layer, that is, one of the existing varianter plugin
implementations.  This was based on earlier design decisions, that
we're trying to fix without breaking expectation and compatibility.

While it'd makes sense to support parameters created by the varianter
layer itself, together with non-varianter parameters, it seems that we
can start by adding support for one or the other being used at a time.

This commit does exactly that: add support for a method of passing
parameters via the command line for all tests in a job, without
having to resort to the varianter.  When the varianter is used,
it takes precedence and the core test parameter passing support
is ignored.

This should solve a number of use cases that require one-time
executions of tests with different parameters, especially
executions during test development and debugging.
Signed-off-by: NCleber Rosa <crosa@redhat.com>
上级 6d8495f6
......@@ -134,6 +134,16 @@ class Job(object):
self.test_suite = None
self.test_runner = None
#: Placeholder for test parameters (related to --test-parameters command
#: line option). They're kept in the job because they will be prepared
#: only once, since they are read only and will be shared acrross all
#: tests of a job.
self.test_parameters = None
if "test_parameters" in self.args:
self.test_parameters = {}
for parameter_name, parameter_value in self.args.test_parameters:
self.test_parameters[parameter_name] = parameter_value
# The result events dispatcher is shared with the test runner.
# Because of our goal to support using the phases of a job
# freely, let's get the result events dispatcher ready early.
......
......@@ -25,6 +25,7 @@ import sys
import time
from . import test
from . import tree
from . import exceptions
from . import output
from . import status
......@@ -505,8 +506,7 @@ class TestRunner(object):
return False
return True
@staticmethod
def _template_to_factory(template, variant):
def _template_to_factory(self, template, variant):
"""
Applies test params from variant to the test template
......@@ -520,13 +520,18 @@ class TestRunner(object):
"""
var = variant.get("variant")
paths = variant.get("paths")
empty_variants = varianter.is_empty_variant(var)
if "params" not in template[1]:
factory = [template[0], template[1].copy()]
if self.job.test_parameters and empty_variants:
var[0] = tree.TreeNode().get_node("/", True)
var[0].value = self.job.test_parameters
paths = ["/"]
factory[1]["params"] = (var, paths)
return factory, variant
if not varianter.is_empty_variant(var):
if not empty_variants:
raise NotImplementedError("Specifying test params from test loader "
"and from varianter at the same time is "
"not yet supported. Please remove either "
......
......@@ -42,6 +42,15 @@ class Run(CLICmd):
description = ("Runs one or more tests (native test, test alias, binary "
"or script)")
@staticmethod
def _test_parameter(string):
param_name_value = string.split('=', 1)
if len(param_name_value) < 2:
msg = ('Invalid --test-parameter option: "%s". Valid option must '
'be a "NAME=VALUE" like expression' % string)
raise argparse.ArgumentTypeError(msg)
return param_name_value
def configure(self, parser):
"""
Add the subparser for the run action.
......@@ -54,6 +63,15 @@ class Run(CLICmd):
metavar="TEST_REFERENCE",
help='List of test references (aliases or paths)')
parser.add_argument("-p", "--test-parameter", action="append",
dest='test_parameters', default=[],
metavar="NAME_VALUE", type=self._test_parameter,
help="Parameter name and value to pass to all "
"tests. This is only applicable when not using a "
"varianter plugin. This option format must be "
"given in the NAME=VALUE format, and may be given "
"any number of times, or per parameter.")
parser.add_argument("-d", "--dry-run", action="store_true",
help="Instead of running the test only "
"list them and log their params.")
......
......@@ -26,16 +26,17 @@ Overall picture of how the params handling works is:
.. code-block:: c
+-----------+
| | // Test uses variant to produce AvocadoParams
| Test |
| |
| | // Test uses AvocadoParams, with content either from
| Test | // a variant or from the test parameters given by
| | // "--test-parameters"
+-----^-----+
| // single variant is passed to Test
|
|
+-----------+
| Runner | // iterates through tests and variants to run all
+-----^-----+ // desired combinations specified by "--execution-order"
|
+-----^-----+ // desired combinations specified by "--execution-order".
| // if no variants are produced by varianter plugins,
| // use the test parameters given by "--test-parameters"
|
+-------------------+ provide variants +-----------------------+
| |<-----------------| |
......@@ -273,6 +274,33 @@ Where:
* path - the location of this parameter. When the path does not exists yet,
it's created out of `TreeNode`_.
Test parameters
~~~~~~~~~~~~~~~
This is an Avocado core feature, that is, it's not dependent on any
varianter plugin. In fact, it's only active when no Varianter plugin
is used and produces a valid variant.
Avocado will use those simple parameters, and will pass them to all
tests in a job execution. This is done on the command line via
``--test-parameters``, or simply, ``-p``. It can be given multiple
times for multiple parameters.
Because Avocado parameters do not have a mechanism to define their
types, test code should always consider that a parameter value is a
string, and convert it to the appropriate type.
.. note:: Some varianter plugins would implicitly set parameters
with different data types, but given that the same test can be
used with different, or none, varianter plugins, it's safer if
the test does an explicit check or type conversion.
Because the :class:`avocado.core.varianter.AvocadoParams` mandates the
concept of a parameter path (a legacy of the tree based Multiplexer)
and these test parameters are flat, those test parameters are placed
in the ``/`` path. This is to ensure maximum compatibility with tests
that do not choose an specific parameter location.
Varianter plugins
~~~~~~~~~~~~~~~~~
......
......@@ -18,7 +18,7 @@ class SleepTest(Test):
"""
Sleep for length seconds.
"""
sleep_length = self.params.get('sleep_length', default=1)
sleep_length = float(self.params.get('sleep_length', default=1))
self.log.debug("Sleeping for %.2f seconds", sleep_length)
time.sleep(sleep_length)
......
......@@ -554,6 +554,18 @@ class RunnerOperationTest(unittest.TestCase):
self.assertEqual(result.exit_status, 1, "Expected exit status is 1\n%s"
% result)
def test_runner_test_parameters(self):
cmd_line = ('%s --show=test run --sysinfo=off --job-results-dir %s '
'-p "sleep_length=0.01" -- sleeptest.py ' % (AVOCADO,
self.tmpdir))
result = process.run(cmd_line, ignore_status=True)
expected_rc = exit_codes.AVOCADO_ALL_OK
self.assertEqual(result.exit_status, expected_rc,
"Avocado did not return rc %d:\n%s" % (expected_rc, result))
self.assertIn(b"PARAMS (key=sleep_length, path=*, default=1) => '0.01'",
result.stdout)
self.assertIn(b"Sleeping for 0.01 seconds", result.stdout)
def tearDown(self):
shutil.rmtree(self.tmpdir)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册