diff --git a/example/my_parser.py b/example/my_parser.py index ad5ff33..3896330 100644 --- a/example/my_parser.py +++ b/example/my_parser.py @@ -12,16 +12,16 @@ class MyParser(BaseHandler): {'name': 'My Test 2', 'passed': False, 'msg': 'Error text D:'}] } - def run_my_tests(self, resultfile): - with open(resultfile, 'w') as f: + def run_my_tests(self, result_file): + with open(result_file, 'w') as f: json.dump(self.RESULTS, f) - return resultfile + return result_file - def parse_results(self, resultfile): - with open(resultfile, 'r') as f: + def parse_results(self, result_file): + with open(result_file, 'r') as f: results = json.load(f) return { - 'name': resultfile, + 'name': result_file, 'tags': [], 'setup': None, 'teardown': None, diff --git a/src/oxygen/base_handler.py b/src/oxygen/base_handler.py index eb422c5..9f40186 100644 --- a/src/oxygen/base_handler.py +++ b/src/oxygen/base_handler.py @@ -3,7 +3,7 @@ from .robot_interface import RobotInterface class BaseHandler(object): - DEFAULT_CLI = {tuple(['resultfile']): {}} + DEFAULT_CLI = {tuple(['result_file']): {}} def __init__(self, config): ''' diff --git a/src/oxygen/oxygen.py b/src/oxygen/oxygen.py index 6b39606..8fdc734 100644 --- a/src/oxygen/oxygen.py +++ b/src/oxygen/oxygen.py @@ -213,10 +213,10 @@ def parse_args(self, parser): for flags, params in tool_handler.cli().items(): subcommand_parser.add_argument(*flags, **params) subcommand_parser.set_defaults(func=tool_handler.parse_results) - return parser.parse_args() + return vars(parser.parse_args()) # returns a dictionary - def get_output_filename(self, resultfile): - filename = Path(resultfile) + def get_output_filename(self, result_file): + filename = Path(result_file) filename = filename.with_suffix('.xml') robot_name = filename.stem + '_robot_output' + filename.suffix filename = filename.with_name(robot_name) @@ -228,10 +228,11 @@ def run(self): action='version', version=f'%(prog)s {self.__version__}') args = self.parse_args(parser) - if not vars(args): + if not args: parser.error('No arguments given') - output_filename = self.get_output_filename(args.resultfile) - parsed_results = args.func(args.resultfile) + output_filename = self.get_output_filename(args['result_file']) + parsed_results = args['func']( + **{k: v for (k, v) in args.items() if not callable(v)}) robot_suite = RobotInterface().running.build_suite(parsed_results) robot_suite.run(output=output_filename, log=None, diff --git a/src/oxygen/zap.py b/src/oxygen/zap.py index 96d3739..367d5a0 100644 --- a/src/oxygen/zap.py +++ b/src/oxygen/zap.py @@ -25,8 +25,25 @@ def run_zap(self, result_file, command, check_return_code=False, **env): logger.info('Result file: {}'.format(result_file)) return result_file - - def parse_results(self, result_file): + def cli(self): + cli_interface = self.DEFAULT_CLI.copy() + cli_interface[('--accepted-risk-level',)] = { + 'help': 'Set accepted risk level', + 'type': int + } + cli_interface[('--required-confidence-level',)] = { + 'help': 'Set required confidence level', + 'type': int + } + return cli_interface + + def parse_results(self, result_file, accepted_risk_level=None, + required_confidence_level=None): + if accepted_risk_level is not None: + self._config['accepted_risk_level'] = accepted_risk_level + if required_confidence_level is not None: + self._config['required_confidence_level'] = \ + required_confidence_level zap_dict = self._read_results(validate_path(result_file).resolve()) return self._parse_zap_dict(zap_dict) diff --git a/tests/utest/oxygen/test_oxygen_cli.py b/tests/utest/oxygen/test_oxygen_cli.py index 5fbab5e..166ca56 100644 --- a/tests/utest/oxygen/test_oxygen_cli.py +++ b/tests/utest/oxygen/test_oxygen_cli.py @@ -10,6 +10,7 @@ from ..helpers import RESOURCES_PATH + class TestOxygenCLIEntryPoints(TestCase): '''Coverage does not measure coverage correctly for these tests. @@ -20,6 +21,7 @@ class TestOxygenCLIEntryPoints(TestCase): Setting up Coverage to see subprocesses as well seems a lot of work and quite a hack: https://coverage.readthedocs.io/en/latest/subprocess.html ''' + def test_main_level_entrypoint(self): self.verify_cli_help_text('python -m oxygen --help') self.verify_cli_help_text('python -m oxygen -h') @@ -43,16 +45,20 @@ def verify_cli_help_text(self, cmd): def test_junit_works_on_cli(self): target = RESOURCES_PATH / 'green-junit-example.xml' - expected = target.with_name('green-junit-expected-robot-output.xml') + example = target.with_name('green-junit-expected-robot-output.xml') actual = target.with_name('green-junit-example_robot_output.xml') if actual.exists(): - actual.unlink() # delete file if exists + actual.unlink() # delete file if exists + + check_output(f'python -m oxygen oxygen.junit {target}', + text=True, + shell=True) - out = check_output(f'python -m oxygen oxygen.junit {target}', - text=True, - shell=True) + for expected in ('Critical Tests', + 'All Tests'): + self.assertIn(expected, example.read_text()) + self.assertIn(expected, actual.read_text()) - self.assertEqual(expected.read_text(), expected.read_text()) class TestOxygenCLI(TestCase): @@ -62,8 +68,9 @@ def setUp(self): @patch('oxygen.oxygen.RobotInterface') @patch('oxygen.oxygen.OxygenCLI.parse_args') def test_run(self, mock_parse_args, mock_robot_iface): - mock_parse_args.return_value = Mock(resultfile='path/to/file.xml', - func=lambda _: {'some': 'results'}) + mock_parse_args.return_value = { + 'result_file': 'path/to/file.xml', + 'func': lambda *_, **__: {'some': 'results'}} expected_suite = create_autospec(TestSuite) mock = Mock() mock.running.build_suite = Mock(return_value=expected_suite) diff --git a/tests/utest/zap/test_basic_functionality.py b/tests/utest/zap/test_basic_functionality.py index 2f96ee6..cb4b22c 100644 --- a/tests/utest/zap/test_basic_functionality.py +++ b/tests/utest/zap/test_basic_functionality.py @@ -1,10 +1,9 @@ from pathlib import Path -from unittest import skip, TestCase +from unittest import TestCase from unittest.mock import ANY, create_autospec, Mock, mock_open, patch from testfixtures import compare -from oxygen.base_handler import BaseHandler from oxygen.zap import ZAProxyHandler from oxygen.errors import ZAProxyHandlerException from ..helpers import (example_robot_output, @@ -299,9 +298,6 @@ def test_parsing_json(self): def assertNotNoneOrEmpty(self, str_): return str_ is not None and str_ != '' - def test_cli(self): - self.assertEqual(self.handler.cli(), BaseHandler.DEFAULT_CLI) - @patch('oxygen.zap.ZAProxyHandler._report_oxygen_run') def test_check_for_keyword(self, mock_report): fake_test = example_robot_output().suite.suites[0].tests[4] diff --git a/tests/utest/zap/test_zap_cli.py b/tests/utest/zap/test_zap_cli.py new file mode 100644 index 0000000..76023c0 --- /dev/null +++ b/tests/utest/zap/test_zap_cli.py @@ -0,0 +1,89 @@ +import sys +from unittest import TestCase +from unittest.mock import ANY, Mock, create_autospec, patch +from robot.running.model import TestSuite +from oxygen.oxygen import OxygenCLI +from ..helpers import RESOURCES_PATH + + +class TestOxygenZapCLI(TestCase): + ZAP_XML = str(RESOURCES_PATH / "zap" / "zap.xml") + + def setUp(self): + self.cli = OxygenCLI() + self.handler = self.cli._handlers["oxygen.zap"] + self.expected_suite = create_autospec(TestSuite) + self.mock = Mock() + self.mock.running.build_suite = Mock(return_value=self.expected_suite) + + def test_cli(self): + self.assertEqual( + self.handler.cli(), + { + ("--accepted-risk-level",): { + "help": "Set accepted risk level", + "type": int, + }, + ("--required-confidence-level",): { + "help": "Set required confidence level", + "type": int, + }, + ("result_file",): {}, + }, + ) + + @patch("oxygen.oxygen.RobotInterface") + def test_cli_run(self, mock_robot_iface): + mock_robot_iface.return_value = self.mock + + cmd_args = f"oxygen oxygen.zap {self.ZAP_XML}" + with patch.object(sys, "argv", cmd_args.split()): + self.cli.run() + + self.assertEqual(self.handler._config["accepted_risk_level"], 2) + self.assertEqual(self.handler._config["required_confidence_level"], 1) + + self.mock.running.build_suite.assert_called_once() + + self.expected_suite.run.assert_called_once_with( + output=str(RESOURCES_PATH / "zap" / "zap_robot_output.xml"), + log=None, + report=None, + stdout=ANY, + ) + + @patch("oxygen.oxygen.RobotInterface") + def test_cli_run_with_levels(self, mock_robot_iface): + mock_robot_iface.return_value = self.mock + + cmd_args = ( + f"oxygen oxygen.zap {self.ZAP_XML} --accepted-risk-level 3" + " --required-confidence-level 3" + ) + with patch.object(sys, "argv", cmd_args.split()): + self.cli.run() + + self.assertEqual(self.handler._config["accepted_risk_level"], 3) + self.assertEqual(self.handler._config["required_confidence_level"], 3) + + @patch("oxygen.oxygen.RobotInterface") + def test_cli_run_with_accepted_risk_level(self, mock_robot_iface): + mock_robot_iface.return_value = self.mock + + cmd_args = f"oxygen oxygen.zap {self.ZAP_XML} --accepted-risk-level 3" + with patch.object(sys, "argv", cmd_args.split()): + self.cli.run() + + self.assertEqual(self.handler._config["accepted_risk_level"], 3) + self.assertEqual(self.handler._config["required_confidence_level"], 1) + + @patch("oxygen.oxygen.RobotInterface") + def test_cli_run_with_required_confidence_level(self, mock_robot_iface): + mock_robot_iface.return_value = self.mock + + cmd_args = f"oxygen oxygen.zap {self.ZAP_XML} " "--required-confidence-level 3" + with patch.object(sys, "argv", cmd_args.split()): + self.cli.run() + + self.assertEqual(self.handler._config["accepted_risk_level"], 2) + self.assertEqual(self.handler._config["required_confidence_level"], 3)