未验证 提交 d11a0313 编写于 作者: L Lukáš Doktor

Merging pull request 2480

Signed-off-by: NLukáš Doktor <ldoktor@redhat.com>

* https://github.com/avocado-framework/avocado:
  Support variants dump/load
  core varianter: implement __len__
......@@ -346,3 +346,6 @@ class Varianter(object):
yield {"variant": self._default_params.get_leaves(),
"variant_id": None,
"paths": ["/run/*"]}
def __len__(self):
return self._no_variants
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# See LICENSE for more details.
#
# Copyright: Red Hat Inc. 2018
# Authors: Amador Pahim <apahim@redhat.com>
import json
import sys
from six import iteritems
from avocado.core import exit_codes
from avocado.core import varianter
from avocado.core.output import LOG_UI
from avocado.core.plugin_interfaces import CLI
from avocado.core.plugin_interfaces import Varianter
_NO_VARIANTS = -1
class JsonVariantsCLI(CLI):
"""
Serialized based Varianter options
"""
name = 'json variants'
description = "JSON serialized based Varianter options for the 'run' " \
"subcommand"
def configure(self, parser):
for name in ("run", "variants"): # intentionally omitting "multiplex"
subparser = parser.subcommands.choices.get(name, None)
if subparser is None:
continue
sparser = subparser.add_argument_group('JSON serialized based '
'varianter options')
sparser.add_argument('--json-variants-load', default=None,
help=('Load the Variants from a JSON '
'serialized file'))
def run(self, args):
pass
class JsonVariants(Varianter):
"""
Processes the serialized file into variants
"""
name = 'json variants'
description = "JSON serialized based Varianter"
variants = None
def initialize(self, args):
load_variants = getattr(args, "json_variants_load", None)
if load_variants is None:
self.variants = _NO_VARIANTS
return
try:
with open(load_variants, 'r') as var_file:
self.variants = varianter.Varianter(state=json.load(var_file))
except IOError:
LOG_UI.error("JSON serialized file '%s' could not be found or "
"is not readable", load_variants)
if args.subcommand == 'run':
sys.exit(exit_codes.AVOCADO_JOB_FAIL)
else:
sys.exit(exit_codes.AVOCADO_FAIL)
def __iter__(self):
if self.variants == _NO_VARIANTS:
return
elif self.variants is None:
raise RuntimeError("Iterating Varianter before initialization is"
"not supported")
for variant in self.variants.itertests():
yield variant
def __len__(self):
if self.variants == _NO_VARIANTS:
return 0
elif self.variants is None:
raise RuntimeError("Calling Varianter __len__ before"
"initialization is not supported")
return len(self.variants)
def update_defaults(self, defaults):
pass
def to_str(self, summary, variants, **kwargs):
"""
Return human readable representation
The summary/variants accepts verbosity where 0 means silent and
maximum is up to the plugin.
:param summary: How verbose summary to output (int)
:param variants: How verbose list of variants to output (int)
:param kwargs: Other free-form arguments
:rtype: str
"""
if self.variants == _NO_VARIANTS:
return ""
out = []
verbose = variants > 1
if summary:
# TODO: tree representation
out.append("No tree representation for JSON serialized variants")
if variants:
out.append("JSON Serialized Variants (%i):" % len(self))
for variant in self:
paths = ', '.join([x.path for x in variant["variant"]])
out.append('%sVariant %s: %s' % ('\n' if verbose else '',
variant["variant_id"],
paths))
if not verbose:
continue
env = set()
for node in variant["variant"]:
for key, value in iteritems(node.environment):
origin = node.environment.origin[key].path
env.add(("%s:%s" % (origin, key), str(value)))
if not env:
return out
fmt = ' %%-%ds => %%s' % max([len(_[0]) for _ in env])
for record in sorted(env):
out.append(fmt % record)
return "\n".join(out)
......@@ -13,6 +13,7 @@
# Author: Lucas Meneghel Rodrigues <lmr@redhat.com>
# Author: Lukas Doktor <ldoktor@redhat.com>
import json
import sys
from avocado.core import exit_codes
......@@ -65,6 +66,8 @@ class Variants(CLICmd):
parser.add_argument('-c', '--contents', action='store_true',
default=False, help="[obsoleted by --variants] "
"Shows the node content (variables)")
parser.add_argument('--json-variants-dump', default=None,
help="Dump the Variants to a JSON serialized file")
env_parser = parser.add_argument_group("environment view options")
env_parser.add_argument('-d', '--debug', action='store_true',
dest="varianter_debug", default=False,
......@@ -110,6 +113,15 @@ class Variants(CLICmd):
if args.contents:
variants += 2
# Export the serialized avocado_variants
if args.json_variants_dump is not None:
try:
with open(args.json_variants_dump, 'w') as variants_file:
json.dump(args.avocado_variants.dump(), variants_file)
except IOError:
LOG_UI.error("Cannot write %s", args.json_variants_dump)
sys.exit(exit_codes.AVOCADO_FAIL)
# Produce the output
lines = args.avocado_variants.to_str(summary=summary,
variants=variants,
......
......@@ -137,6 +137,54 @@ is ``None``, which still produces an empty `AvocadoParams`_. Also, the
`Variant`_ can also be a ``tuple(list, paths)`` or just the
``list`` of :class:`avocado.core.tree.TreeNode` with the params.
Dumping/Loading Variants
~~~~~~~~~~~~~~~~~~~~~~~~
Depending on the number of parameters, generating the Variants can be very
compute intensive. As the Variants are generated as part of the Job execution,
that compute intensive task will be executed by the systems under test, causing
a possibly unwanted cpu load on those systems.
To avoid such situation, you can acquire the resulting JSON serialized variants
file, generated out of the variants computation, and load that file on the
system where the Job will be executed.
There are two ways to acquire the JSON serialized variants file:
- Using the ``--json-variants-dump`` option of the ``avocado variants``
command::
$ avocado variants --mux-yaml examples/yaml_to_mux/hw/hw.yaml --json-variants-dump variants.json
...
$ file variants.json
variants.json: ASCII text, with very long lines, with no line terminators
- Getting the auto-generated JSON serialized variants file after a Avocado Job
execution::
$ avocado run passtest.py --mux-yaml examples/yaml_to_mux/hw/hw.yaml
...
$ file $HOME/avocado/job-results/latest/jobdata/variants.json
$HOME/avocado/job-results/latest/jobdata/variants.json: ASCII text, with very long lines, with no line terminators
Once you have the ``variants.json`` file, you can load it on the system where
the Job will take place::
$ avocado run passtest.py --json-variants-load variants.json
JOB ID : f2022736b5b89d7f4cf62353d3fb4d7e3a06f075
JOB LOG : $HOME/avocado/job-results/job-2018-02-09T14.39-f202273/job.log
(1/6) passtest.py:PassTest.test;intel-scsi-56d0: PASS (0.04 s)
(2/6) passtest.py:PassTest.test;intel-virtio-3d4e: PASS (0.02 s)
(3/6) passtest.py:PassTest.test;amd-scsi-fa43: PASS (0.02 s)
(4/6) passtest.py:PassTest.test;amd-virtio-a59a: PASS (0.02 s)
(5/6) passtest.py:PassTest.test;arm-scsi-1c14: PASS (0.03 s)
(6/6) passtest.py:PassTest.test;arm-virtio-5ce1: PASS (0.04 s)
RESULTS : PASS 6 | ERROR 0 | FAIL 0 | SKIP 0 | WARN 0 | INTERRUPT 0 | CANCEL 0
JOB TIME : 0.51 s
JOB HTML : $HOME/avocado/job-results/job-2018-02-09T14.39-f202273/results.html
Varianter
~~~~~~~~~
......
import json
import os
import tempfile
import shutil
import unittest
from avocado.utils import process
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")
class VariantsDumpLoadTests(unittest.TestCase):
def setUp(self):
self.tmpdir = tempfile.mkdtemp(prefix='avocado_' + __name__)
self.variants_file = os.path.join(self.tmpdir, 'variants.json')
os.chdir(basedir)
def test_variants_dump(self):
content = ('[{"paths": ["/run/*"], '
'"variant": [["/", []]], '
'"variant_id": null}]')
cmd_line = ('%s variants --json-variants-dump %s' %
(AVOCADO, self.variants_file))
process.run(cmd_line)
with open(self.variants_file, 'r') as file_obj:
self.assertEqual(file_obj.read(), content)
def test_run_load(self):
content = ('[{"paths": ["/run/*"],'
' "variant": [["/run/params/foo",'
' [["/run/params/foo", "p2", "foo2"],'
' ["/run/params/foo", "p1", "foo1"]]]], '
' "variant_id": "foo-0ead"}, '
' {"paths": ["/run/*"],'
' "variant": [["/run/params/bar",'
' [["/run/params/bar", "p2", "bar2"],'
' ["/run/params/bar", "p1", "bar1"]]]],'
' "variant_id": "bar-d06d"}]')
with open(self.variants_file, 'w') as file_obj:
file_obj.write(content)
cmd_line = ('%s run passtest.py --json-variants-load %s '
'--job-results-dir %s --json -' %
(AVOCADO, self.variants_file, self.tmpdir))
result = process.run(cmd_line)
json_result = json.loads(result.stdout)
self.assertEqual(json_result["pass"], 2)
self.assertEqual(json_result["tests"][0]["id"],
"1-passtest.py:PassTest.test;foo-0ead")
self.assertEqual(json_result["tests"][1]["id"],
"2-passtest.py:PassTest.test;bar-d06d")
def tearDown(self):
shutil.rmtree(self.tmpdir)
if __name__ == '__main__':
unittest.main()
......@@ -67,6 +67,7 @@ if __name__ == '__main__':
'replay = avocado.plugins.replay:Replay',
'tap = avocado.plugins.tap:TAP',
'zip_archive = avocado.plugins.archive:ArchiveCLI',
'json_variants = avocado.plugins.json_variants:JsonVariantsCLI',
],
'avocado.plugins.cli.cmd': [
'config = avocado.plugins.config:Config',
......@@ -95,6 +96,9 @@ if __name__ == '__main__':
'tap = avocado.plugins.tap:TAPResult',
'journal = avocado.plugins.journal:JournalResult',
],
'avocado.plugins.varianter': [
'json_variants = avocado.plugins.json_variants:JsonVariants',
],
},
zip_safe=False,
test_suite='selftests',
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册