diff --git a/avocado/core/job.py b/avocado/core/job.py index d9755fc0312711d3ab5885a623306ad701df3203..5a1c796132e2163c421cc4af32a1ca35617efb3d 100644 --- a/avocado/core/job.py +++ b/avocado/core/job.py @@ -42,7 +42,6 @@ from . import output from . import multiplexer from . import tree from . import test -from . import jsonresult from . import replay from .output import STD_OUTPUT from .settings import settings @@ -280,11 +279,6 @@ class Job(object): # If there are any active output plugins, let's use them self._set_output_plugins() - # Setup the json plugin to output to the debug directory - json_file = os.path.join(self.logdir, 'results.json') - json_plugin = jsonresult.JSONResult(self, json_file) - self.result_proxy.add_output_plugin(json_plugin) - # Setup the html output to the results directory if HTML_REPORT_SUPPORT: html_file = os.path.join(self.logdir, 'html', 'results.html') diff --git a/avocado/core/jsonresult.py b/avocado/core/jsonresult.py deleted file mode 100644 index 0ac9443954382835dacba557653513487cacd796..0000000000000000000000000000000000000000 --- a/avocado/core/jsonresult.py +++ /dev/null @@ -1,98 +0,0 @@ -# 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. 2014 -# Author: Ruda Moura - -""" -JSON output module. -""" - -import json -import logging - -from .result import Result - - -class JSONResult(Result): - - """ - JSON Test Result class. - """ - - command_line_arg_name = '--json' - - def __init__(self, job, force_json_file=None): - """ - :param job: Job which defines this result - :param force_json_file: Override the json output file location - """ - Result.__init__(self, job) - if force_json_file: - self.output = force_json_file - else: - self.output = getattr(self.args, 'json_output', '-') - self.json = None - self.log = logging.getLogger("avocado.app") - - def start_tests(self): - """ - Called once before any tests are executed. - """ - Result.start_tests(self) - self.json = {'debuglog': self.logfile, - 'tests': []} - - def end_test(self, state): - """ - Called when the given test has been run. - - :param state: result of :class:`avocado.core.test.Test.get_state`. - :type state: dict - """ - Result.end_test(self, state) - if 'job_id' not in self.json: - self.json['job_id'] = state.get('job_unique_id', "") - t = {'test': str(state.get('name', "")), - 'url': str(state.get('name', "")), - 'start': state.get('time_start', -1), - 'end': state.get('time_end', -1), - 'time': state.get('time_elapsed', -1), - 'status': state.get('status', {}), - 'whiteboard': state.get('whiteboard', ""), - 'logdir': state.get('logdir', ""), - 'logfile': state.get('logfile', ""), - 'fail_reason': str(state.get('fail_reason', "")) - } - self.json['tests'].append(t) - - def _save_json(self): - with open(self.output, 'w') as j: - j.write(self.json) - - def end_tests(self): - """ - Called once after all tests are executed. - """ - Result.end_tests(self) - self.json.update({ - 'total': self.tests_total, - 'pass': self.passed, - 'errors': self.errors, - 'failures': self.failed, - 'skip': self.skipped, - 'time': self.tests_total_time - }) - self.json = json.dumps(self.json) - if self.output == '-': - self.log.debug(self.json) - else: - self._save_json() diff --git a/avocado/plugins/json.py b/avocado/plugins/json.py deleted file mode 100644 index d07d175599f66b35f8b09003aab75c39d0a7b95c..0000000000000000000000000000000000000000 --- a/avocado/plugins/json.py +++ /dev/null @@ -1,48 +0,0 @@ -# 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. 2014 -# Author: Ruda Moura - -""" -JSON output module. -""" - - -from avocado.core.plugin_interfaces import CLI -from avocado.core.jsonresult import JSONResult -from avocado.core.result import register_test_result_class -from avocado.core.parser import FileOrStdoutAction - - -class JSON(CLI): - - """ - JSON output - """ - - name = 'json' - description = "JSON output options for '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( - '--json', type=str, action=FileOrStdoutAction, - dest='json_output', metavar='FILE', - help='Enable JSON result format and write it to FILE. ' - "Use '-' to redirect to the standard output.") - - def run(self, args): - if 'json_output' in args and args.json_output is not None: - register_test_result_class(args, JSONResult) diff --git a/avocado/plugins/jsonresult.py b/avocado/plugins/jsonresult.py new file mode 100644 index 0000000000000000000000000000000000000000..f3190547f496d51540b391676ff327a9b3b2255c --- /dev/null +++ b/avocado/plugins/jsonresult.py @@ -0,0 +1,105 @@ +# 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. 2014 +# Authors: Ruda Moura +# Cleber Rosa + +""" +JSON output module. +""" + +import json +import logging +import os + +from avocado.core.parser import FileOrStdoutAction +from avocado.core.plugin_interfaces import CLI, Result + + +UNKNOWN = '' + + +class JSONResult(Result): + + def _render(self, result): + tests = [] + for test in result.tests: + tests.append({'test': str(test.get('name', UNKNOWN)), + 'url': str(test.get('name', UNKNOWN)), + 'start': test.get('time_start', -1), + 'end': test.get('time_end', -1), + 'time': test.get('time_elapsed', -1), + 'status': test.get('status', {}), + 'whiteboard': test.get('whiteboard', UNKNOWN), + 'logdir': test.get('logdir', UNKNOWN), + 'logfile': test.get('logfile', UNKNOWN), + 'fail_reason': str(test.get('fail_reason', UNKNOWN))}) + content = {'job_id': result.job_unique_id, + 'debuglog': result.logfile, + 'tests': tests, + 'total': result.tests_total, + 'pass': result.passed, + 'errors': result.errors, + 'failures': result.failed, + 'skip': result.skipped, + 'time': result.tests_total_time} + return json.dumps(content) + + def render(self, result, job): + if not (hasattr(job.args, 'json_job_result') or + hasattr(job.args, 'json_output')): + return + + content = self._render(result) + if getattr(job.args, 'json_job_result', 'off') == 'on': + json_path = os.path.join(job.logdir, 'results.json') + with open(json_path, 'w') as json_file: + json_file.write(content) + + json_path = getattr(job.args, 'json_output', 'None') + if json_path is not None: + if json_path == '-': + log = logging.getLogger("avocado.app") + log.debug(content) + else: + with open(json_path, 'w') as json_file: + json_file.write(content) + + +class JSONCLI(CLI): + + """ + JSON output + """ + + name = 'json' + description = "JSON output options for '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( + '--json', type=str, action=FileOrStdoutAction, + dest='json_output', metavar='FILE', + help='Enable JSON result format and write it to FILE. ' + "Use '-' to redirect to the standard output.") + + run_subcommand_parser.output.add_argument( + '--json-job-result', dest='json_job_result', + choices=('on', 'off'), default='on', + help=('Enables default JSON result in the job results directory. ' + 'File will be named "results.json".')) + + def run(self, args): + pass diff --git a/selftests/unit/test_jsonresult.py b/selftests/unit/test_jsonresult.py index c4711b7565dcf88b249f187c1932a2f2d66ee7b4..44612c4ff7df0da6574f6aa00b523ca1fd4050fb 100644 --- a/selftests/unit/test_jsonresult.py +++ b/selftests/unit/test_jsonresult.py @@ -6,8 +6,9 @@ import tempfile import shutil from avocado import Test -from avocado.core import jsonresult from avocado.core import job +from avocado.core.result import Result +from avocado.plugins import jsonresult class FakeJob(object): @@ -28,10 +29,11 @@ class JSONResultTest(unittest.TestCase): self.tmpfile = tempfile.mkstemp() self.tmpdir = tempfile.mkdtemp(prefix='avocado_' + __name__) args = argparse.Namespace(json_output=self.tmpfile[1]) - self.test_result = jsonresult.JSONResult(FakeJob(args)) + self.job = job.Job(args) + self.test_result = Result(FakeJob(args)) self.test_result.filename = self.tmpfile[1] self.test_result.start_tests() - self.test1 = SimpleTest(job=job.Job(), base_logdir=self.tmpdir) + self.test1 = SimpleTest(job=self.job, base_logdir=self.tmpdir) self.test1.status = 'PASS' self.test1.time_elapsed = 1.23 @@ -44,8 +46,9 @@ class JSONResultTest(unittest.TestCase): self.test_result.start_test(self.test1) self.test_result.end_test(self.test1.get_state()) self.test_result.end_tests() - self.assertTrue(self.test_result.json) - with open(self.test_result.filename) as fp: + json_result = jsonresult.JSONResult() + json_result.render(self.test_result, self.job) + with open(self.job.args.json_output) as fp: j = fp.read() obj = json.loads(j) self.assertTrue(obj) @@ -78,7 +81,9 @@ class JSONResultTest(unittest.TestCase): run_fake_status({"status": ""}) # Postprocess self.test_result.end_tests() - res = json.loads(self.test_result.json) + json_result = jsonresult.JSONResult() + json_result.render(self.test_result, self.job) + res = json.loads(open(self.job.args.json_output).read()) check_item("[pass]", res["pass"], 2) check_item("[errors]", res["errors"], 4) check_item("[failures]", res["failures"], 1) @@ -94,7 +99,9 @@ class JSONResultTest(unittest.TestCase): self.test_result.start_test(self.test1) self.test_result.check_test(self.test1.get_state()) self.test_result.end_tests() - res = json.loads(self.test_result.json) + json_result = jsonresult.JSONResult() + json_result.render(self.test_result, self.job) + res = json.loads(open(self.job.args.json_output).read()) check_item("[total]", res["total"], 1) check_item("[skip]", res["skip"], 0) check_item("[pass]", res["pass"], 1) diff --git a/setup.py b/setup.py index e6e91e5749d3998f2300482ecb07206b9f46a532..ea8664ead1bb6a3df999b7e47f4339c680250ff7 100755 --- a/setup.py +++ b/setup.py @@ -132,7 +132,7 @@ if __name__ == '__main__': 'gdb = avocado.plugins.gdb:GDB', 'wrapper = avocado.plugins.wrapper:Wrapper', 'xunit = avocado.plugins.xunit:XUnitCLI', - 'json = avocado.plugins.json:JSON', + 'json = avocado.plugins.jsonresult:JSONCLI', 'journal = avocado.plugins.journal:Journal', 'html = avocado.plugins.html:HTML', 'remote = avocado.plugins.remote:Remote', @@ -156,6 +156,7 @@ if __name__ == '__main__': ], 'avocado.plugins.result': [ 'xunit = avocado.plugins.xunit:XUnitResult', + 'json = avocado.plugins.jsonresult:JSONResult', ], }, zip_safe=False,