From 5332f7a38175a1f8901f0bae769ad5159a3b9272 Mon Sep 17 00:00:00 2001 From: Cleber Rosa Date: Tue, 25 Oct 2016 23:34:22 -0300 Subject: [PATCH] Plugins: introduce archive result plugin The archive (ZIP) feature has no reason for reason for being a core feature, as it maps nicely to the result plugin interface. Let's turn that into a proper (and quite simple) plugin. Also, let's add a functional test for both the archive plugin, and for the ordered execution configuration using the zip archive for that. Signed-off-by: Cleber Rosa --- avocado/core/job.py | 5 -- avocado/plugins/archive.py | 47 ++++++++++++++++ avocado/plugins/run.py | 4 -- selftests/functional/test_basic.py | 86 ++++++++++++++++++++++++++++-- setup.py | 2 + 5 files changed, 130 insertions(+), 14 deletions(-) create mode 100644 avocado/plugins/archive.py diff --git a/avocado/core/job.py b/avocado/core/job.py index 450427c0..893d328d 100644 --- a/avocado/core/job.py +++ b/avocado/core/job.py @@ -44,7 +44,6 @@ from . import test from . import jobdata from .output import STD_OUTPUT from .settings import settings -from ..utils import archive from ..utils import astring from ..utils import path from ..utils import runtime @@ -472,10 +471,6 @@ class Job(object): # If it's all good so far, set job status to 'PASS' if self.status == 'RUNNING': self.status = 'PASS' - # Let's clean up test artifacts - if getattr(self.args, 'archive', False): - filename = self.logdir + '.zip' - archive.create(filename, self.logdir) _TEST_LOGGER.info('Test results available in %s', self.logdir) if summary is None: diff --git a/avocado/plugins/archive.py b/avocado/plugins/archive.py new file mode 100644 index 00000000..4646f823 --- /dev/null +++ b/avocado/plugins/archive.py @@ -0,0 +1,47 @@ +# 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. 2016 +# Authors: Cleber Rosa + +"""Result Archive Plugin""" + +from avocado.core.plugin_interfaces import CLI, Result +from avocado.utils import archive + + +class Archive(Result): + + name = 'zip_archive' + description = 'Result archive (ZIP) support' + + def render(self, result, job): + if getattr(job.args, 'archive', False): + archive.compress("%s.zip" % job.logdir, job.logdir) + + +class ArchiveCLI(CLI): + + name = 'zip_archive' + description = 'Result archive (ZIP) support to run command' + + def configure(self, parser): + run_subcommand_parser = parser.subcommands.choices.get('run', None) + if run_subcommand_parser is None: + return + + run_subcommand_parser.output.add_argument( + '-z', '--archive', action='store_true', + dest='archive', default=False, + help='Archive (ZIP) files generated by tests') + + def run(self, args): + pass diff --git a/avocado/plugins/run.py b/avocado/plugins/run.py index 33509476..8d8d62cc 100644 --- a/avocado/plugins/run.py +++ b/avocado/plugins/run.py @@ -55,10 +55,6 @@ class Run(CLICmd): help="Instead of running the test only " "list them and log their params.") - parser.add_argument('-z', '--archive', action='store_true', - default=False, help='Archive (ZIP) files generated' - ' by tests') - parser.add_argument('--force-job-id', dest='unique_job_id', type=str, default=None, help='Forces the use of a particular job ID. Used ' diff --git a/selftests/functional/test_basic.py b/selftests/functional/test_basic.py index 4b3f8fb7..0c4281ef 100644 --- a/selftests/functional/test_basic.py +++ b/selftests/functional/test_basic.py @@ -1,14 +1,17 @@ +import aexpect +import glob import json import os +import re import shutil -import time +import signal import sys import tempfile +import time import xml.dom.minidom -import glob -import aexpect -import signal -import re +import zipfile + +import pkg_resources if sys.version_info[:2] == (2, 6): import unittest2 as unittest @@ -912,6 +915,79 @@ class PluginsTest(AbsPluginsTest, unittest.TestCase): (expected_rc, result)) self.assertNotIn("Collect system information", result.stdout) + def test_plugin_order(self): + """ + Tests plugin order by configuration file + + First it checks if html, json, xunit and zip_archive plugins are enabled. + Then it runs a test with zip_archive running first, which means the html, + json and xunit output files do not make into the archive. + + Then it runs with zip_archive set to run last, which means the html, + json and xunit output files *do* make into the archive. + """ + def run_config(config_path): + cmd = ('./scripts/avocado --config %s run passtest.py --archive ' + '--job-results-dir %s') % (config_path, self.base_outputdir) + result = process.run(cmd, 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)) + + result_plugins = ["json", "xunit", "zip_archive"] + result_outputs = ["results.json", "results.xml"] + try: + pkg_resources.require('avocado_result_html') + result_plugins.append("html") + result_outputs.append("html/results.html") + except pkg_resources.DistributionNotFound: + pass + + os.chdir(basedir) + cmd_line = './scripts/avocado plugins' + 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)) + for result_plugin in result_plugins: + self.assertIn(result_plugin, result.stdout) + + config_content_zip_first = "[plugins.result]\norder=['zip_archive']" + config_zip_first = script.TemporaryScript("zip_first.conf", + config_content_zip_first) + with config_zip_first: + run_config(config_zip_first) + archives = glob.glob(os.path.join(self.base_outputdir, '*.zip')) + self.assertEqual(len(archives), 1, "ZIP Archive not generated") + zip_file = zipfile.ZipFile(archives[0], 'r') + zip_file_list = zip_file.namelist() + for result_output in result_outputs: + self.assertNotIn(result_output, zip_file_list) + os.unlink(archives[0]) + + config_content_zip_last = ("[plugins.result]\norder=['html', 'json'," + "'xunit', 'zip_archive']") + config_zip_last = script.TemporaryScript("zip_last.conf", + config_content_zip_last) + with config_zip_last: + run_config(config_zip_last) + archives = glob.glob(os.path.join(self.base_outputdir, '*.zip')) + self.assertEqual(len(archives), 1, "ZIP Archive not generated") + zip_file = zipfile.ZipFile(archives[0], 'r') + zip_file_list = zip_file.namelist() + for result_output in result_outputs: + self.assertIn(result_output, zip_file_list) + + config_content_missing = ("[plugins.result]\norder=['foo', " + "'html', 'json', 'xunit', " + "'zip_archive', 'bar']") + config_missing = script.TemporaryScript("missing.conf", + config_content_missing) + with config_missing: + run_config(config_missing) + def test_Namespace_object_has_no_attribute(self): os.chdir(basedir) cmd_line = './scripts/avocado plugins' diff --git a/setup.py b/setup.py index 4b09797f..481dfd30 100755 --- a/setup.py +++ b/setup.py @@ -139,6 +139,7 @@ if __name__ == '__main__': 'vm = avocado.plugins.vm:VM', 'docker = avocado.plugins.docker:Docker', 'yaml_to_mux = avocado.plugins.yaml_to_mux:YamlToMux', + 'zip_archive = avocado.plugins.archive:ArchiveCLI', ], 'avocado.plugins.cli.cmd': [ 'config = avocado.plugins.config:Config', @@ -157,6 +158,7 @@ if __name__ == '__main__': 'avocado.plugins.result': [ 'xunit = avocado.plugins.xunit:XUnitResult', 'json = avocado.plugins.jsonresult:JSONResult', + 'zip_archive = avocado.plugins.archive:Archive', ], }, zip_safe=False, -- GitLab