From eb6f950875a91afa0e694482728d6441a8f28c9c Mon Sep 17 00:00:00 2001 From: Matej Cotman Date: Wed, 18 Aug 2021 14:06:04 +0300 Subject: [PATCH] feat(base_handler): add support for passing multiple args from handler's keyword method --- src/oxygen/base_handler.py | 39 ++++- src/oxygen/errors.py | 4 + tests/resources/example_robot_output.xml | 51 ++++++ tests/resources/my_dummy_handlers/__init__.py | 0 .../dummy_handler_default_params.py | 17 ++ .../dummy_handler_multiple_args.py | 17 ++ .../dummy_handler_multiple_args_too_few.py | 18 +++ .../dummy_handler_single_arg.py | 15 ++ tests/utest/helpers.py | 4 + tests/utest/my_dummy_handler/__init__.py | 0 .../test_basic_functionality.py | 150 ++++++++++++++++++ 11 files changed, 311 insertions(+), 4 deletions(-) create mode 100644 tests/resources/my_dummy_handlers/__init__.py create mode 100644 tests/resources/my_dummy_handlers/dummy_handler_default_params.py create mode 100644 tests/resources/my_dummy_handlers/dummy_handler_multiple_args.py create mode 100644 tests/resources/my_dummy_handlers/dummy_handler_multiple_args_too_few.py create mode 100644 tests/resources/my_dummy_handlers/dummy_handler_single_arg.py create mode 100644 tests/utest/my_dummy_handler/__init__.py create mode 100644 tests/utest/my_dummy_handler/test_basic_functionality.py diff --git a/src/oxygen/base_handler.py b/src/oxygen/base_handler.py index c9d5305..a0eb4e0 100644 --- a/src/oxygen/base_handler.py +++ b/src/oxygen/base_handler.py @@ -1,5 +1,8 @@ import re +from inspect import signature, Parameter + +from oxygen.errors import MismatchArgumentException from .robot_interface import (RobotInterface, get_keywords_from, set_special_keyword) @@ -100,14 +103,42 @@ def _build_results(self, keyword, setup_keyword, teardown_keyword): setup_keyword: The special oxygen setup wrapper teardown_keyword: The special oxygen teardown wrapper ''' - test = keyword.parent - test_results = self.parse_results(self.run_time_data) - end_time, result_suite = self._interface.result.build_suite(100000, - test_results) + accepted_params = signature(self.parse_results).parameters + accepted_params_max = len(accepted_params) + accepted_params_min = len([ + n for n, v in accepted_params.items() + if v.default == Parameter.empty]) + is_multiple_inputs = isinstance(self.run_time_data, tuple) + + # there are multiple inputs and in the range of accepted min and max + if is_multiple_inputs and (accepted_params_min <= len( + self.run_time_data) <= accepted_params_max): + test_results = self.parse_results(*self.run_time_data) + + # there is single input and one required, also can be more non-required + elif not is_multiple_inputs and accepted_params_min == 1: + test_results = self.parse_results(self.run_time_data) + + # else if there are multiple inputs and not in the range of accepted + elif is_multiple_inputs: + raise MismatchArgumentException( + f'parse_results expects at least {accepted_params_min} and' + f' at most {accepted_params_max} arguments ' + f'but got {len(self.run_time_data)}') + + # at this point there could be only multiple required and single input + else: + raise MismatchArgumentException( + f'parse_results expects at least {accepted_params_min} ' + 'arguments but got 1') + + _, result_suite = self._interface.result.build_suite( + 100000, test_results) if not result_suite: return + test = keyword.parent self._set_suite_tags(result_suite, *(self._tags + list(test.tags))) if setup_keyword: diff --git a/src/oxygen/errors.py b/src/oxygen/errors.py index d62f44e..932a080 100644 --- a/src/oxygen/errors.py +++ b/src/oxygen/errors.py @@ -24,3 +24,7 @@ class ResultFileNotFoundException(Exception): class ResultFileIsNotAFileException(Exception): pass + + +class MismatchArgumentException(Exception): + pass diff --git a/tests/resources/example_robot_output.xml b/tests/resources/example_robot_output.xml index e241ba2..78079a4 100644 --- a/tests/resources/example_robot_output.xml +++ b/tests/resources/example_robot_output.xml @@ -258,6 +258,56 @@ + + +Logs the given message with the given level. + +My Dummy Handler Setup Here 1 + +My Dummy Handler Setup Here 1 + + + +Logs the given message with the given level. + +My Dummy Handler Setup Here 2 + +My Dummy Handler Setup Here 2 + + + +Run My Dummy Handler tool specified with ``command``. + +${RESOURCES}/my_dummy_handler.xml +echo +MY_DUMMY_HANDLER_TEST_STRING + +MY_DUMMY_HANDLER_TEST_STRING + +Result file: /Users/tkairi/Coding/oxygen/tests/atest/../resources/my_dummy_handler.xml + + + +Logs the given message with the given level. + +My Dummy Handler Teardown Here 1 + +My Dummy Handler Teardown Here 1 + + + +Logs the given message with the given level. + +My Dummy Handler Teardown Here 2 + +My Dummy Handler Teardown Here 2 + + + +MY_DUMMY_HANDLER_ROBOT_TAG + + + @@ -272,6 +322,7 @@ JUNIT_ROBOT_TAG NO_OXYGEN_HERE ZAP_ROBOT_TAG +MY_DUMMY_HANDLER_ROBOT_TAG Atest diff --git a/tests/resources/my_dummy_handlers/__init__.py b/tests/resources/my_dummy_handlers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/resources/my_dummy_handlers/dummy_handler_default_params.py b/tests/resources/my_dummy_handlers/dummy_handler_default_params.py new file mode 100644 index 0000000..9ee23f0 --- /dev/null +++ b/tests/resources/my_dummy_handlers/dummy_handler_default_params.py @@ -0,0 +1,17 @@ +from oxygen import BaseHandler + + +class MyDummyHandler(BaseHandler): + ''' + A test handler that throws mismatch argument exception if single argument + is passed with multiple accepted + ''' + + def run_my_dummy_handler(self, result_file): + return result_file + + def parse_results(self, result_file, foo='foo'): + return { + 'name': result_file, + 'foo': foo + } diff --git a/tests/resources/my_dummy_handlers/dummy_handler_multiple_args.py b/tests/resources/my_dummy_handlers/dummy_handler_multiple_args.py new file mode 100644 index 0000000..e34c503 --- /dev/null +++ b/tests/resources/my_dummy_handlers/dummy_handler_multiple_args.py @@ -0,0 +1,17 @@ +from oxygen import BaseHandler + + +class MyDummyHandler(BaseHandler): + ''' + A test handler for unfolding parse_results arguments + if it has multiple parameters + ''' + + def run_my_dummy_handler(self, result_file): + return result_file, 'foo' + + def parse_results(self, result_file, foo): + return { + 'name': result_file, + 'foo': foo + } diff --git a/tests/resources/my_dummy_handlers/dummy_handler_multiple_args_too_few.py b/tests/resources/my_dummy_handlers/dummy_handler_multiple_args_too_few.py new file mode 100644 index 0000000..ec15650 --- /dev/null +++ b/tests/resources/my_dummy_handlers/dummy_handler_multiple_args_too_few.py @@ -0,0 +1,18 @@ +from oxygen import BaseHandler + + +class MyDummyHandler(BaseHandler): + ''' + A test handler that throws mismatch argument exception because + parse_results expects too many arguments + ''' + + def run_my_dummy_handler(self, result_file): + return result_file, 'foo' + + def parse_results(self, result_file, foo, bar): + return { + 'name': result_file, + 'foo': foo, + 'bar': bar + } diff --git a/tests/resources/my_dummy_handlers/dummy_handler_single_arg.py b/tests/resources/my_dummy_handlers/dummy_handler_single_arg.py new file mode 100644 index 0000000..ad1616a --- /dev/null +++ b/tests/resources/my_dummy_handlers/dummy_handler_single_arg.py @@ -0,0 +1,15 @@ +from oxygen import BaseHandler + + +class MyDummyHandler(BaseHandler): + ''' + A test handler for passing tuple if parse_results accepts one parameter + ''' + + def run_my_dummy_handler(self, result_file): + return result_file, 'foo' + + def parse_results(self, result_file): + return { + 'name': result_file + } diff --git a/tests/utest/helpers.py b/tests/utest/helpers.py index e6725a4..0174a41 100644 --- a/tests/utest/helpers.py +++ b/tests/utest/helpers.py @@ -25,6 +25,10 @@ tags: ZAP accepted_risk_level: 2 required_confidence_level: 1 +oxygen.my_dummy_handler: + handler: MyDummyHandler + keyword: run_my_dummy_handler + tags: MY_DUMMY_HANDLER ''' RESOURCES_PATH = Path.cwd() / 'tests' / 'resources' diff --git a/tests/utest/my_dummy_handler/__init__.py b/tests/utest/my_dummy_handler/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/utest/my_dummy_handler/test_basic_functionality.py b/tests/utest/my_dummy_handler/test_basic_functionality.py new file mode 100644 index 0000000..f863fd5 --- /dev/null +++ b/tests/utest/my_dummy_handler/test_basic_functionality.py @@ -0,0 +1,150 @@ +import sys +from unittest import TestCase +from oxygen.errors import MismatchArgumentException +from ..helpers import RESOURCES_PATH, get_config, example_robot_output + +sys.path.append(str(RESOURCES_PATH / 'my_dummy_handlers')) + +from dummy_handler_single_arg import ( + MyDummyHandler as DummyHandlerSingleArg, +) +from dummy_handler_multiple_args import ( + MyDummyHandler as DummyHandlerMultipleArgs, +) +from dummy_handler_multiple_args_too_few import ( + MyDummyHandler as DummyHandlerMultipleArgsTooFew, +) +from dummy_handler_default_params import ( + MyDummyHandler as DummyHandlerDefaultParams, +) + + +class DummyHandlerSingleArgTests(TestCase): + ''' + A test for passing tuple if parse_results accepts one parameter + ''' + + def setUp(self): + self.handler = DummyHandlerSingleArg( + get_config()['oxygen.my_dummy_handler'] + ) + + def test_run_my_dummy_handler(self): + return_value = self.handler.run_my_dummy_handler('/some/path/to.ext') + self.assertTupleEqual(return_value, ('/some/path/to.ext', 'foo')) + + def test_parse_results(self): + fake_test = example_robot_output().suite.suites[0].tests[6] + expected_data = {'Atest.Test.My Fifth Test': '/some/path/to.ext'} + + self.handler.check_for_keyword(fake_test, expected_data) + + self.assertEqual(self.handler.run_time_data, '/some/path/to.ext') + + +class DummyHandlerMultipleArgsTests(TestCase): + ''' + A test for unfolding parse_results arguments + if it has multiple parameters + ''' + + def setUp(self): + self.handler = DummyHandlerMultipleArgs( + get_config()['oxygen.my_dummy_handler'] + ) + + def test_parse_results(self): + fake_test = example_robot_output().suite.suites[0].tests[6] + expected_data = { + 'Atest.Test.My Fifth Test': ('/some/path/to.ext', 'foo') + } + + self.handler.check_for_keyword(fake_test, expected_data) + + self.assertEqual( + self.handler.run_time_data, ('/some/path/to.ext', 'foo') + ) + + +class DummyHandlerMultipleArgsTooFewTests(TestCase): + ''' + A test for testing if it throws mismatch argument exception because + parse_results expects too many arguments + ''' + + def setUp(self): + self.handler = DummyHandlerMultipleArgsTooFew( + get_config()['oxygen.my_dummy_handler'] + ) + + def test_parse_results(self): + fake_test = example_robot_output().suite.suites[0].tests[6] + expected_data = { + 'Atest.Test.My Fifth Test': ('/some/path/to.ext', 'foo') + } + + self.assertRaises( + MismatchArgumentException, + self.handler.check_for_keyword, + fake_test, + expected_data, + ) + + +class DummyHandlerMultipleArgsSingleTests(TestCase): + ''' + A test for testing if it throws mismatch argument exception because + parse_results expects multiple arguments but we do not pass multiple + ''' + + def setUp(self): + self.handler = DummyHandlerMultipleArgsTooFew( + get_config()['oxygen.my_dummy_handler'] + ) + + def test_parse_results(self): + fake_test = example_robot_output().suite.suites[0].tests[6] + expected_data = {'Atest.Test.My Fifth Test': 'some/path/to.ext'} + + self.assertRaises( + MismatchArgumentException, + self.handler.check_for_keyword, + fake_test, + expected_data, + ) + + +class DummyHandlerDefaultParamsTests(TestCase): + ''' + A test for testing arguments with defaults + ''' + + def setUp(self): + self.handler = DummyHandlerDefaultParams( + get_config()['oxygen.my_dummy_handler'] + ) + + def test_parse_results_with_one(self): + fake_test = example_robot_output().suite.suites[0].tests[6] + expected_data = {'Atest.Test.My Fifth Test': 'some/path/to.ext'} + self.handler.check_for_keyword(fake_test, expected_data) + self.assertEqual(self.handler.run_time_data, 'some/path/to.ext') + + def test_parse_results_with_multiple(self): + fake_test = example_robot_output().suite.suites[0].tests[6] + expected_data = { + 'Atest.Test.My Fifth Test': ('some/path/to.ext', 'foo')} + self.handler.check_for_keyword(fake_test, expected_data) + self.assertTupleEqual( + self.handler.run_time_data, ('some/path/to.ext', 'foo')) + + def test_parse_results_with_too_many(self): + fake_test = example_robot_output().suite.suites[0].tests[6] + expected_data = { + 'Atest.Test.My Fifth Test': ('some/path/to.ext', 'foo', 'bar')} + self.assertRaises( + MismatchArgumentException, + self.handler.check_for_keyword, + fake_test, + expected_data, + )