From c73e663596ab2e63616c74891060841e576b4092 Mon Sep 17 00:00:00 2001 From: Renan Moura Date: Fri, 11 Dec 2020 14:57:55 -0300 Subject: [PATCH 1/7] Updating black pre-commit version, because the version 19.10b0 create some conflicts with flake8. --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 93b819f5..3216a893 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/python/black - rev: 19.10b0 + rev: 20.8b1 hooks: - id: black language_version: python3 From 82337338131ee9a89930cff53029570084061cf6 Mon Sep 17 00:00:00 2001 From: Renan Moura Date: Fri, 11 Dec 2020 15:29:19 -0300 Subject: [PATCH 2/7] Updating changes made to solve #345 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 417a6164..3b7072c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added flake8 check workflow on pull_request event [#321](https://github.com/scanapi/scanapi/pull/321) - Hide sensitive information in the URL Query Params [#304](https://github.com/scanapi/scanapi/pull/325) - Add anchor link for each request in the report to make it easily shareable. [#317](https://github.com/scanapi/scanapi/pull/317) +- Update black version on pre-commit configurations to avoid conflicts with flake8 [#346](https://github.com/scanapi/scanapi/pull/346) ### Changed - Updated poetry-publish version to v1.3 [#311](https://github.com/scanapi/scanapi/pull/311) From 2355abf6c73c3cb15b84a1017d873347f844574d Mon Sep 17 00:00:00 2001 From: Renan Moura Date: Fri, 11 Dec 2020 15:45:17 -0300 Subject: [PATCH 3/7] Adding support to HEAD and OPTIONS http methods, and updating unit tests. --- scanapi/tree/request_node.py | 2 +- tests/unit/tree/test_request_node.py | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/scanapi/tree/request_node.py b/scanapi/tree/request_node.py index 3efbed2b..d855673a 100644 --- a/scanapi/tree/request_node.py +++ b/scanapi/tree/request_node.py @@ -37,7 +37,7 @@ class RequestNode: DELAY_KEY, RETRY_KEY, ) - ALLOWED_HTTP_METHODS = ("GET", "POST", "PUT", "PATCH", "DELETE") + ALLOWED_HTTP_METHODS = ("GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS") REQUIRED_KEYS = (NAME_KEY,) def __init__(self, spec, endpoint): diff --git a/tests/unit/tree/test_request_node.py b/tests/unit/tree/test_request_node.py index 859214b1..456114bc 100644 --- a/tests/unit/tree/test_request_node.py +++ b/tests/unit/tree/test_request_node.py @@ -51,10 +51,11 @@ def test_when_method_is_invalid(self): with pytest.raises(HTTPMethodNotAllowedError) as excinfo: request.http_method - assert ( - str(excinfo.value) == "HTTP method not supported: XXX. " - "Supported methods: ('GET', 'POST', 'PUT', 'PATCH', 'DELETE')." + expected = ( + "HTTP method not supported: XXX." + f" Supported methods: {request.ALLOWED_HTTP_METHODS}." ) + assert str(excinfo.value) == expected class TestName: def test_when_request_has_name(self): From b5b8a53aae33af4e1d840ae8d57d86397420de0b Mon Sep 17 00:00:00 2001 From: Renan Moura Date: Fri, 11 Dec 2020 15:47:17 -0300 Subject: [PATCH 4/7] Running default project formatter. --- scanapi/__main__.py | 6 +- scanapi/evaluators/spec_evaluator.py | 4 +- scanapi/hide_utils.py | 4 +- scanapi/settings.py | 8 +- scanapi/tree/endpoint_node.py | 12 ++- scanapi/tree/request_node.py | 14 ++- tests/unit/evaluators/test_code_evaluator.py | 21 ++++- tests/unit/evaluators/test_spec_evaluator.py | 7 +- .../unit/evaluators/test_string_evaluator.py | 29 ++++-- tests/unit/test_config_loader.py | 4 +- tests/unit/test_hide_utils.py | 23 ++++- tests/unit/test_main.py | 8 +- tests/unit/test_reporter.py | 29 +++++- tests/unit/test_scan.py | 36 ++++++-- tests/unit/test_settings.py | 20 +++- tests/unit/test_template_render.py | 4 +- tests/unit/test_utils.py | 5 +- tests/unit/tree/test_endpoint_node.py | 70 +++++++++++--- tests/unit/tree/test_request_node.py | 91 +++++++++++++++---- tests/unit/tree/test_testing_node.py | 27 ++++-- 20 files changed, 326 insertions(+), 96 deletions(-) diff --git a/scanapi/__main__.py b/scanapi/__main__.py index f90e65f2..4016cbb8 100644 --- a/scanapi/__main__.py +++ b/scanapi/__main__.py @@ -21,7 +21,11 @@ def main(): @main.command(context_settings=CONTEXT_SETTINGS) @click.argument("spec_path", type=click.Path(exists=True), required=False) @click.option( - "-o", "--output-path", "output_path", type=click.Path(), help="Report output path.", + "-o", + "--output-path", + "output_path", + type=click.Path(), + help="Report output path.", ) @click.option( "-c", diff --git a/scanapi/evaluators/spec_evaluator.py b/scanapi/evaluators/spec_evaluator.py index 329e60d5..acd49cd2 100644 --- a/scanapi/evaluators/spec_evaluator.py +++ b/scanapi/evaluators/spec_evaluator.py @@ -20,7 +20,9 @@ def evaluate_assertion(self, element): def update(self, vars, extras=None, preevaluate=False): if preevaluate: - values = {key: evaluate(value, extras) for key, value in vars.items()} + values = { + key: evaluate(value, extras) for key, value in vars.items() + } self.registry.update(values) self.registry.update(extras) else: diff --git a/scanapi/hide_utils.py b/scanapi/hide_utils.py index 80e43c67..2e32ce67 100644 --- a/scanapi/hide_utils.py +++ b/scanapi/hide_utils.py @@ -49,7 +49,9 @@ def _override_url(http_msg, secret_field): url_parsed = urlparse(http_msg.url) if secret_field in url_parsed.path: new_url = url_parsed._replace( - path=url_parsed.path.replace(secret_field, SENSITIVE_INFO_SUBSTITUTION_FLAG) + path=url_parsed.path.replace( + secret_field, SENSITIVE_INFO_SUBSTITUTION_FLAG + ) ) new_url = urlunparse(new_url) http_msg.url = new_url diff --git a/scanapi/settings.py b/scanapi/settings.py index 0fbaf330..b8e7f0ce 100644 --- a/scanapi/settings.py +++ b/scanapi/settings.py @@ -4,7 +4,9 @@ from scanapi.config_loader import load_config_file -GLOBAL_CONFIG_PATH = os.path.join(appdirs.site_config_dir("scanapi"), "scanapi.conf",) +GLOBAL_CONFIG_PATH = os.path.join( + appdirs.site_config_dir("scanapi"), "scanapi.conf", +) LOCAL_CONFIG_PATH = "./scanapi.conf" @@ -34,7 +36,9 @@ def save_config_file_preferences(self, config_path=None): def save_click_preferences(self, **preferences): """ Saves all preference items to the Settings object. """ - cleaned_preferences = {k: v for k, v in preferences.items() if v is not None} + cleaned_preferences = { + k: v for k, v in preferences.items() if v is not None + } self.update(**cleaned_preferences) def save_preferences(self, **click_preferences): diff --git a/scanapi/tree/endpoint_node.py b/scanapi/tree/endpoint_node.py index 655fb6fd..78d37a2f 100644 --- a/scanapi/tree/endpoint_node.py +++ b/scanapi/tree/endpoint_node.py @@ -46,7 +46,8 @@ def __build(self): self._validate() self.child_nodes = [ - EndpointNode(spec, parent=self) for spec in self.spec.get(ENDPOINTS_KEY, []) + EndpointNode(spec, parent=self) + for spec in self.spec.get(ENDPOINTS_KEY, []) ] def __repr__(self): @@ -90,9 +91,7 @@ def run(self): try: yield request.run() except Exception as e: - error_message = ( - f"\nError to make request `{request.full_url_path}`. \n{str(e)}\n" - ) + error_message = f"\nError to make request `{request.full_url_path}`. \n{str(e)}\n" logger.error(error_message) session.exit_code = ExitCode.REQUEST_ERROR continue @@ -121,6 +120,9 @@ def _get_specs(self, field_name): def _get_requests(self): return chain( - (RequestNode(spec, self) for spec in self.spec.get(REQUESTS_KEY, [])), + ( + RequestNode(spec, self) + for spec in self.spec.get(REQUESTS_KEY, []) + ), *(child._get_requests() for child in self.child_nodes), ) diff --git a/scanapi/tree/request_node.py b/scanapi/tree/request_node.py index d855673a..3f1c0520 100644 --- a/scanapi/tree/request_node.py +++ b/scanapi/tree/request_node.py @@ -37,7 +37,15 @@ class RequestNode: DELAY_KEY, RETRY_KEY, ) - ALLOWED_HTTP_METHODS = ("GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS") + ALLOWED_HTTP_METHODS = ( + "GET", + "POST", + "PUT", + "PATCH", + "DELETE", + "HEAD", + "OPTIONS", + ) REQUIRED_KEYS = (NAME_KEY,) def __init__(self, spec, endpoint): @@ -98,7 +106,9 @@ def body(self): @property def tests(self): - return (TestingNode(spec, self) for spec in self.spec.get(TESTS_KEY, [])) + return ( + TestingNode(spec, self) for spec in self.spec.get(TESTS_KEY, []) + ) @property def retry(self): diff --git a/tests/unit/evaluators/test_code_evaluator.py b/tests/unit/evaluators/test_code_evaluator.py index b49b74ed..2d1b374b 100644 --- a/tests/unit/evaluators/test_code_evaluator.py +++ b/tests/unit/evaluators/test_code_evaluator.py @@ -24,7 +24,9 @@ class TestWhenItIsATestCase: @pytest.mark.parametrize("sequence, expected", test_data) def test_should_return_assert_results(self, sequence, expected): assert ( - CodeEvaluator.evaluate(sequence, {}, is_a_test_case=True) + CodeEvaluator.evaluate( + sequence, {}, is_a_test_case=True + ) == expected ) @@ -36,7 +38,10 @@ def response(self, requests_mock): test_data = [ ("${{response.text == 'abcde'}}", (True, None)), - ("${{response.url == 'http://test.com/'}}", (True, None),), + ( + "${{response.url == 'http://test.com/'}}", + (True, None), + ), ( "${{response.status_code == 300}}", (False, "response.status_code == 300"), @@ -53,7 +58,9 @@ def test_should_return_assert_results( ): assert ( CodeEvaluator.evaluate( - sequence, {"response": response}, is_a_test_case=True, + sequence, + {"response": response}, + is_a_test_case=True, ) == expected ) @@ -62,7 +69,9 @@ class TestWhenCodeBreaks: def test_should_raises_invalid_python_code_error(self): with pytest.raises(InvalidPythonCodeError) as excinfo: CodeEvaluator.evaluate( - "${{response.url == 'abc'}}", {}, is_a_test_case=True, + "${{response.url == 'abc'}}", + {}, + is_a_test_case=True, ) assert ( @@ -98,7 +107,9 @@ def test_should_return_evaluated_code( self, sequence, expected, response ): assert ( - CodeEvaluator.evaluate(sequence, {"response": response}) + CodeEvaluator.evaluate( + sequence, {"response": response} + ) == expected ) diff --git a/tests/unit/evaluators/test_spec_evaluator.py b/tests/unit/evaluators/test_spec_evaluator.py index 2f6740a5..fc201fc4 100644 --- a/tests/unit/evaluators/test_spec_evaluator.py +++ b/tests/unit/evaluators/test_spec_evaluator.py @@ -43,10 +43,9 @@ def test_return_evaluated_dict( self, spec_evaluator, mocker, mock_string_evaluate ): mock_string_evaluate.side_effect = ["foo", "bar"] - assert spec_evaluator.evaluate({"app_id": "foo", "token": "bar"}) == { - "app_id": "foo", - "token": "bar", - } + assert spec_evaluator.evaluate( + {"app_id": "foo", "token": "bar"} + ) == {"app_id": "foo", "token": "bar",} mock_string_evaluate.assert_has_calls( [ diff --git a/tests/unit/evaluators/test_string_evaluator.py b/tests/unit/evaluators/test_string_evaluator.py index fc740e80..ee4c765a 100644 --- a/tests/unit/evaluators/test_string_evaluator.py +++ b/tests/unit/evaluators/test_string_evaluator.py @@ -50,7 +50,9 @@ class TestWhenMatchesThePattern: class TestWhenEnvVarIsSetProperly: @pytest.fixture(autouse=True) def base_url_env(self): - os.environ["BASE_URL"] = "https://jsonplaceholder.typicode.com" + os.environ[ + "BASE_URL" + ] = "https://jsonplaceholder.typicode.com" os.environ["POST_ID"] = "2" test_data = [ @@ -71,7 +73,9 @@ def base_url_env(self): @pytest.mark.parametrize("sequence, expected", test_data) def test_should_return_evaluated_var(self, sequence, expected): - assert StringEvaluator._evaluate_env_var(sequence) == expected + assert ( + StringEvaluator._evaluate_env_var(sequence) == expected + ) class TestWhenThereIsNoCorrespondingEnvVar: @pytest.fixture(autouse=True) @@ -94,7 +98,10 @@ class TestWhenDoesNotMatchThePattern: @pytest.mark.parametrize("sequence", test_data) def test_should_return_sequence(self, sequence): - assert StringEvaluator._evaluate_custom_var(sequence, {}) == sequence + assert ( + StringEvaluator._evaluate_custom_var(sequence, {}) + == sequence + ) class TestWhenMatchesThePattern: class TestWhenCodeDoesNotContainThePreSavedCustomVar: @@ -109,7 +116,8 @@ class TestWhenCodeDoesNotContainThePreSavedCustomVar: @pytest.mark.parametrize("sequence", test_data) def test_should_return_sequence(self, sequence): assert ( - StringEvaluator._evaluate_custom_var(sequence, {}) == sequence + StringEvaluator._evaluate_custom_var(sequence, {}) + == sequence ) class TestWhenCodeContainsThePreSavedCustomVar: @@ -127,9 +135,14 @@ class TestWhenCodeContainsThePreSavedCustomVar: @pytest.mark.parametrize("sequence, expected", test_data) def test_should_return_sequence(self, sequence, expected): - vars = {"user_id": "10", "apiKey": "abc123", "api-token": "xwo"} + vars = { + "user_id": "10", + "apiKey": "abc123", + "api-token": "xwo", + } assert ( - StringEvaluator._evaluate_custom_var(sequence, vars) == expected + StringEvaluator._evaluate_custom_var(sequence, vars) + == expected ) class TestReplaceVarWithValue: @@ -156,7 +169,9 @@ class TestReplaceVarWithValue: @pytest.mark.parametrize( "sequence, variable, variable_value, expected", test_data ) - def test_should_replace(self, sequence, variable, variable_value, expected): + def test_should_replace( + self, sequence, variable, variable_value, expected + ): assert ( StringEvaluator.replace_var_with_value( sequence, variable, variable_value diff --git a/tests/unit/test_config_loader.py b/tests/unit/test_config_loader.py index ed8583f1..0b979adb 100644 --- a/tests/unit/test_config_loader.py +++ b/tests/unit/test_config_loader.py @@ -46,7 +46,9 @@ def test_should_raise_exception(self): with pytest.raises(EmptyConfigFileError) as excinfo: load_config_file("tests/data/empty.yaml") - assert str(excinfo.value) == "File 'tests/data/empty.yaml' is empty." + assert ( + str(excinfo.value) == "File 'tests/data/empty.yaml' is empty." + ) class TestWhenIncludeFileDoesNotExist: def test_should_raise_exception(self): diff --git a/tests/unit/test_hide_utils.py b/tests/unit/test_hide_utils.py index 24277202..a391f52f 100644 --- a/tests/unit/test_hide_utils.py +++ b/tests/unit/test_hide_utils.py @@ -19,7 +19,11 @@ def mock__hide(self, mocker): ({}, {}, {}), ({"report": {"abc": "def"}}, {}, {}), ({"report": {"hide_request": {"url": ["abc"]}}}, {"url": ["abc"]}, {}), - ({"report": {"hide_request": {"headers": ["abc"]}}}, {"headers": ["abc"]}, {},), + ( + {"report": {"hide_request": {"headers": ["abc"]}}}, + {"headers": ["abc"]}, + {}, + ), ( {"report": {"hide_response": {"headers": ["abc"]}}}, {}, @@ -27,7 +31,9 @@ def mock__hide(self, mocker): ), ] - @pytest.mark.parametrize("settings, request_settings, response_settings", test_data) + @pytest.mark.parametrize( + "settings, request_settings, response_settings", test_data + ) def test_calls__hide( self, settings, @@ -81,7 +87,10 @@ def test_overrides_url(self, response): _override_info(response, http_attr, secret_field) - assert response.url == "http://test.com/users/SENSITIVE_INFORMATION/details" + assert ( + response.url + == "http://test.com/users/SENSITIVE_INFORMATION/details" + ) def test_overrides_headers(self, response): response.headers = {"abc": "123"} @@ -93,7 +102,9 @@ def test_overrides_headers(self, response): assert response.headers["abc"] == "SENSITIVE_INFORMATION" def test_overrides_body(self, response): - response.body = b'{"id": "abc21", "name": "Tarik", "yearsOfExperience": 2}' + response.body = ( + b'{"id": "abc21", "name": "Tarik", "yearsOfExperience": 2}' + ) http_attr = "body" secret_field = "id" @@ -106,7 +117,9 @@ def test_overrides_body(self, response): def test_overrides_params(self, response): param = "test" - response.url = "http://test.com/users/details?test=test&test2=test&test=test2" + response.url = ( + "http://test.com/users/details?test=test&test2=test&test=test2" + ) http_attr = "params" secret_field = param diff --git a/tests/unit/test_main.py b/tests/unit/test_main.py index 9dbcaaba..8d7dae90 100644 --- a/tests/unit/test_main.py +++ b/tests/unit/test_main.py @@ -33,7 +33,8 @@ def test_call_save_preferences(self, mocker): def test_should_log_error(self, mocker, caplog): mock_save_preferences = mocker.patch( - "scanapi.settings.Settings.save_preferences", side_effect=yaml_error + "scanapi.settings.Settings.save_preferences", + side_effect=yaml_error, ) with caplog.at_level(logging.ERROR): @@ -42,4 +43,7 @@ def test_should_log_error(self, mocker, caplog): assert mock_save_preferences.called assert result.exit_code == 4 - assert "Error loading configuration file.\nPyYAML: error foo" in caplog.text + assert ( + "Error loading configuration file.\nPyYAML: error foo" + in caplog.text + ) diff --git a/tests/unit/test_reporter.py b/tests/unit/test_reporter.py index fd3940bb..ae5dc439 100644 --- a/tests/unit/test_reporter.py +++ b/tests/unit/test_reporter.py @@ -58,20 +58,32 @@ def mocked__open(self, mocker): return mock def test_should_write_to_default_output( - self, mocker, mocked__render, mocked__open, mocked__session, context, + self, + mocker, + mocked__render, + mocked__open, + mocked__session, + context, ): mocked__render.return_value = "ScanAPI Report" reporter = Reporter() reporter.write(fake_results) - mocked__render.assert_called_once_with("report.html", context, False) + mocked__render.assert_called_once_with( + "report.html", context, False + ) mocked__open.assert_called_once_with( "scanapi-report.html", "w", newline="\n" ) mocked__open().write.assert_called_once_with("ScanAPI Report") def test_should_write_to_custom_output( - self, mocker, mocked__render, mocked__open, mocked__session, context, + self, + mocker, + mocked__render, + mocked__open, + mocked__session, + context, ): mocked__render.return_value = "ScanAPI Report" reporter = Reporter("./custom/report-output.html", "html") @@ -84,13 +96,20 @@ def test_should_write_to_custom_output( mocked__open().write.assert_called_once_with("ScanAPI Report") def test_should_handle_custom_templates( - self, mocker, mocked__render, mocked__open, mocked__session, context, + self, + mocker, + mocked__render, + mocked__open, + mocked__session, + context, ): mocked__render.return_value = "ScanAPI Report" reporter = Reporter(template="my-template.html") reporter.write(fake_results) - mocked__render.assert_called_once_with("my-template.html", context, True) + mocked__render.assert_called_once_with( + "my-template.html", context, True + ) mocked__open.assert_called_once_with( "scanapi-report.html", "w", newline="\n" ) diff --git a/tests/unit/test_scan.py b/tests/unit/test_scan.py index 0a7b59c3..d4bb71d7 100644 --- a/tests/unit/test_scan.py +++ b/tests/unit/test_scan.py @@ -40,9 +40,12 @@ class TestScan: class TestWhenCouldNotFindAPISpecFile: def test_should_log_error(self, mocker, caplog): mocker.patch( - "scanapi.scan.settings", {"spec_path": "invalid_path/scanapi.yaml"} + "scanapi.scan.settings", + {"spec_path": "invalid_path/scanapi.yaml"}, + ) + mocker.patch( + "scanapi.scan.load_config_file", side_effect=file_not_found ) - mocker.patch("scanapi.scan.load_config_file", side_effect=file_not_found) with caplog.at_level(logging.ERROR): with pytest.raises(SystemExit) as excinfo: scan() @@ -57,7 +60,9 @@ def test_should_log_error(self, mocker, caplog): class TestWhenAPISpecFileIsEmpty: def test_should_log_error(self, mocker, caplog): - mocker.patch("scanapi.scan.load_config_file", side_effect=empty_config_file) + mocker.patch( + "scanapi.scan.load_config_file", side_effect=empty_config_file + ) with caplog.at_level(logging.ERROR): with pytest.raises(SystemExit) as excinfo: @@ -73,7 +78,9 @@ def test_should_log_error(self, mocker, caplog): class TestWhenAPISpecFileHasAnError: def test_should_log_error(self, mocker, caplog): - mocker.patch("scanapi.scan.load_config_file", side_effect=yaml_error) + mocker.patch( + "scanapi.scan.load_config_file", side_effect=yaml_error + ) with caplog.at_level(logging.ERROR): with pytest.raises(SystemExit) as excinfo: scan() @@ -81,13 +88,20 @@ def test_should_log_error(self, mocker, caplog): assert excinfo.type == SystemExit assert excinfo.value.code == 4 - assert "Error loading specification file.\nPyYAML: error foo" in caplog.text + assert ( + "Error loading specification file.\nPyYAML: error foo" + in caplog.text + ) class TestWhenAPISpecHasAnInvalidKey: def test_should_log_error(self, mocker, caplog): - mock_load_config_file = mocker.patch("scanapi.scan.load_config_file") + mock_load_config_file = mocker.patch( + "scanapi.scan.load_config_file" + ) mock_load_config_file.return_value = {"blah": "blah"} - mocker.patch("scanapi.scan.EndpointNode.__init__", side_effect=invalid_key) + mocker.patch( + "scanapi.scan.EndpointNode.__init__", side_effect=invalid_key + ) with caplog.at_level(logging.ERROR): with pytest.raises(SystemExit) as excinfo: scan() @@ -102,9 +116,13 @@ def test_should_log_error(self, mocker, caplog): class TestWhenAPISpecIsOk: def test_should_call_reporter(self, mocker, response): - mock_load_config_file = mocker.patch("scanapi.scan.load_config_file") + mock_load_config_file = mocker.patch( + "scanapi.scan.load_config_file" + ) mock_load_config_file.return_value = {"endpoints": []} - mock_endpoint_init = mocker.patch("scanapi.scan.EndpointNode.__init__") + mock_endpoint_init = mocker.patch( + "scanapi.scan.EndpointNode.__init__" + ) mock_endpoint_init.return_value = None mock_endpoint_run = mocker.patch("scanapi.scan.EndpointNode.run") mock_endpoint_run.return_value = [response] diff --git a/tests/unit/test_settings.py b/tests/unit/test_settings.py index d2c14c56..f43a6585 100644 --- a/tests/unit/test_settings.py +++ b/tests/unit/test_settings.py @@ -52,8 +52,12 @@ class TestWithConfigFile: def test_should_save_preferences(self, mock_load_config_file): config_path = "my_config_file.yaml" settings.save_config_file_preferences(config_path) - assert settings["config_path"].endswith("my_config_file.yaml") - mock_load_config_file.assert_called_with("my_config_file.yaml") + assert settings["config_path"].endswith( + "my_config_file.yaml" + ) + mock_load_config_file.assert_called_with( + "my_config_file.yaml" + ) class TestWithoutConfigFile: def test_should_raise_exception(self): @@ -88,7 +92,9 @@ def test_should_save_preferences( class TestSavePreferences: @pytest.fixture def mock_save_click_preferences(self, mocker): - return mocker.patch("scanapi.settings.Settings.save_click_preferences") + return mocker.patch( + "scanapi.settings.Settings.save_click_preferences" + ) @pytest.fixture def mock_save_config_file_preferences(self, mocker): @@ -98,7 +104,9 @@ def mock_save_config_file_preferences(self, mocker): class TestWhenConfigPathIsInClickPreferences: def test_should_pass_config_path( - self, mock_save_click_preferences, mock_save_config_file_preferences, + self, + mock_save_click_preferences, + mock_save_config_file_preferences, ): preferences = {"config_path": "foo.yaml"} settings.save_preferences(**preferences) @@ -107,7 +115,9 @@ def test_should_pass_config_path( class TestWhenConfigPathIsNotInClickPreferences: def test_should_pass_config_path_as_none( - self, mock_save_click_preferences, mock_save_config_file_preferences, + self, + mock_save_click_preferences, + mock_save_config_file_preferences, ): preferences = {"foo": "bar"} settings.save_preferences(**preferences) diff --git a/tests/unit/test_template_render.py b/tests/unit/test_template_render.py index ebc58ea0..9bf9049c 100644 --- a/tests/unit/test_template_render.py +++ b/tests/unit/test_template_render.py @@ -7,7 +7,9 @@ class TestTemplateRender: class TestRender: @pytest.fixture def mocked__get_template(self, mocker): - return mocker.patch("scanapi.template_render.Environment.get_template") + return mocker.patch( + "scanapi.template_render.Environment.get_template" + ) def test_should_call_jinja_render(self, mocked__get_template): context = {"my_context": "foo"} diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py index 1526949e..2186dba4 100644 --- a/tests/unit/test_utils.py +++ b/tests/unit/test_utils.py @@ -87,7 +87,10 @@ def test_should_raise_an_exception(self): with pytest.raises(MissingMandatoryKeyError) as excinfo: validate_keys(keys, available_keys, mandatory_keys, scope) - assert str(excinfo.value) == "Missing 'key2' key(s) at 'endpoint' scope" + assert ( + str(excinfo.value) + == "Missing 'key2' key(s) at 'endpoint' scope" + ) class TestThereIsNotAnInvalidKeysOrMissingMandotoryKeys: def test_should_not_raise_an_exception(self): diff --git a/tests/unit/tree/test_endpoint_node.py b/tests/unit/tree/test_endpoint_node.py index 6f6b890b..e5a5ad55 100644 --- a/tests/unit/tree/test_endpoint_node.py +++ b/tests/unit/tree/test_endpoint_node.py @@ -21,7 +21,10 @@ def test_missing_required_keys(self): endpoints = [{}, {}] EndpointNode({"endpoints": endpoints}) - assert str(excinfo.value) == "Missing 'name' key(s) at 'endpoint' scope" + assert ( + str(excinfo.value) + == "Missing 'name' key(s) at 'endpoint' scope" + ) def test_no_required_keys_for_root(self): assert EndpointNode({}) @@ -66,7 +69,11 @@ def test_when_parent_has_url(self): def test_with_trailing_slashes(self): parent = EndpointNode( - {"path": "http://foo.com/", "name": "parent-node", "requests": []} + { + "path": "http://foo.com/", + "name": "parent-node", + "requests": [], + } ) node = EndpointNode( {"path": "/foo/", "name": "node", "requests": []}, parent=parent @@ -75,7 +82,11 @@ def test_with_trailing_slashes(self): def test_with_path_not_string(self): parent = EndpointNode( - {"path": "http://foo.com/", "name": "parent-node", "requests": []} + { + "path": "http://foo.com/", + "name": "parent-node", + "requests": [], + } ) node = EndpointNode( {"path": 2, "name": "node", "requests": []}, parent=parent @@ -84,7 +95,11 @@ def test_with_path_not_string(self): def test_calls_evaluate(self, mocker, mock_evaluate): parent = EndpointNode( - {"path": "http://foo.com/", "name": "parent-node", "requests": []} + { + "path": "http://foo.com/", + "name": "parent-node", + "requests": [], + } ) node = EndpointNode( {"path": "/foo/", "name": "node", "requests": []}, parent=parent @@ -109,7 +124,11 @@ def test_when_parent_has_headers(self): node = EndpointNode( {"headers": headers, "name": "node", "requests": []}, parent=EndpointNode( - {"headers": parent_headers, "name": "parent-node", "requests": []} + { + "headers": parent_headers, + "name": "parent-node", + "requests": [], + } ), ) assert node.headers == {"abc": "def", "xxx": "www"} @@ -120,7 +139,11 @@ def test_when_parent_has_repeated_keys(self): node = EndpointNode( {"headers": headers, "name": "node", "requests": []}, parent=EndpointNode( - {"headers": parent_headers, "name": "parent-node", "requests": []} + { + "headers": parent_headers, + "name": "parent-node", + "requests": [], + } ), ) assert node.headers == {"abc": "def", "xxx": "www"} @@ -140,7 +163,11 @@ def test_when_parent_has_params(self): node = EndpointNode( {"params": params, "name": "node", "requests": []}, parent=EndpointNode( - {"params": parent_params, "name": "parent-node", "requests": []} + { + "params": parent_params, + "name": "parent-node", + "requests": [], + } ), ) assert node.params == {"abc": "def", "xxx": "www"} @@ -151,7 +178,11 @@ def test_when_parent_has_repeated_keys(self): node = EndpointNode( {"params": params, "name": "node", "requests": []}, parent=EndpointNode( - {"params": parent_params, "name": "parent-node", "requests": []} + { + "params": parent_params, + "name": "parent-node", + "requests": [], + } ), ) assert node.params == {"abc": "def", "xxx": "www"} @@ -167,7 +198,8 @@ def test_when_node_has_delay(self): def test_when_parent_has_delay(self): node = EndpointNode( - {"name": "node"}, parent=EndpointNode({"name": "parent", "delay": 2}) + {"name": "node"}, + parent=EndpointNode({"name": "parent", "delay": 2}), ) assert node.delay == 2 @@ -199,7 +231,15 @@ def test_should_call_validate_keys(self, mock_validate_keys): mock_validate_keys.assert_called_with( keys, - ("endpoints", "headers", "name", "params", "path", "requests", "delay"), + ( + "endpoints", + "headers", + "name", + "params", + "path", + "requests", + "delay", + ), ("name",), "endpoint", ) @@ -219,8 +259,14 @@ def test_when_node_has_children(self): { "name": "foo", "requests": [ - {"name": "First", "path": "http://foo.com/first"}, - {"name": "Second", "path": "http://foo.com/second"}, + { + "name": "First", + "path": "http://foo.com/first", + }, + { + "name": "Second", + "path": "http://foo.com/second", + }, ], } ], diff --git a/tests/unit/tree/test_request_node.py b/tests/unit/tree/test_request_node.py index 456114bc..28a516c8 100644 --- a/tests/unit/tree/test_request_node.py +++ b/tests/unit/tree/test_request_node.py @@ -7,7 +7,9 @@ class TestRequestNode: @pytest.fixture def mock_evaluate(self, mocker): - mock_func = mocker.patch("scanapi.tree.request_node.SpecEvaluator.evaluate") + mock_func = mocker.patch( + "scanapi.tree.request_node.SpecEvaluator.evaluate" + ) mock_func.return_value = "" return mock_func @@ -23,10 +25,13 @@ def test_init_spec_and_endpoint(self): def test_missing_required_keys(self): with pytest.raises(MissingMandatoryKeyError) as excinfo: RequestNode( - spec={}, endpoint=EndpointNode({"name": "foo", "requests": [{}]}), + spec={}, + endpoint=EndpointNode({"name": "foo", "requests": [{}]}), ) - assert str(excinfo.value) == "Missing 'name' key(s) at 'request' scope" + assert ( + str(excinfo.value) == "Missing 'name' key(s) at 'request' scope" + ) class TestHTTPMethod: def test_when_request_has_method(self): @@ -68,7 +73,9 @@ def test_when_request_has_name(self): @pytest.mark.skip("it should validate mandatory `name` key before") def test_when_request_has_no_name(self): with pytest.raises(MissingMandatoryKeyError) as excinfo: - RequestNode({}, endpoint=EndpointNode({"name": "foo", "requests": []})) + RequestNode( + {}, endpoint=EndpointNode({"name": "foo", "requests": []}) + ) assert str(excinfo.value) == "Missing name, path at 'request'" @@ -77,7 +84,9 @@ def test_when_endpoint_has_no_url(self): path = "http://foo.com" request = RequestNode( {"name": "foo", "path": path}, - endpoint=EndpointNode({"name": "foo", "requests": [{}], "path": ""}), + endpoint=EndpointNode( + {"name": "foo", "requests": [{}], "path": ""} + ), ) assert request.full_url_path == path @@ -86,28 +95,36 @@ def test_when_endpoint_has_url(self): endpoint = EndpointNode( {"name": "foo", "requests": [{}], "path": endpoint_path} ) - request = RequestNode({"path": "/foo", "name": "foo"}, endpoint=endpoint) + request = RequestNode( + {"path": "/foo", "name": "foo"}, endpoint=endpoint + ) assert request.full_url_path == "http://foo.com/api/foo" def test_with_trailing_slashes(self): endpoint = EndpointNode( {"name": "foo", "requests": [{}], "path": "http://foo.com/"} ) - request = RequestNode({"name": "foo", "path": "/foo/"}, endpoint=endpoint) + request = RequestNode( + {"name": "foo", "path": "/foo/"}, endpoint=endpoint + ) assert request.full_url_path == "http://foo.com/foo/" def test_with_trailintest_with_path_not_stringg_slashes(self): endpoint = EndpointNode( {"name": "foo", "requests": [{}], "path": "http://foo.com/"} ) - request = RequestNode({"name": "foo", "path": []}, endpoint=endpoint) + request = RequestNode( + {"name": "foo", "path": []}, endpoint=endpoint + ) assert request.full_url_path == "http://foo.com/[]" def test_calls_evaluate(self, mocker, mock_evaluate): endpoint = EndpointNode( {"name": "foo", "requests": [{}], "path": "http://foo.com/"} ) - request = RequestNode({"path": "/foo/", "name": "foo"}, endpoint=endpoint) + request = RequestNode( + {"path": "/foo/", "name": "foo"}, endpoint=endpoint + ) request.full_url_path calls = [mocker.call("http://foo.com/"), mocker.call("/foo/")] @@ -128,7 +145,11 @@ def test_when_endpoint_has_headers(self): request = RequestNode( {"headers": headers, "path": "http://foo.com", "name": "foo"}, endpoint=EndpointNode( - {"headers": endpoint_headers, "name": "foo", "requests": [{}]} + { + "headers": endpoint_headers, + "name": "foo", + "requests": [{}], + } ), ) assert request.headers == {"abc": "def", "xxx": "www"} @@ -139,7 +160,11 @@ def test_with_repeated_keys(self): request = RequestNode( {"headers": headers, "path": "http://foo.com", "name": "foo"}, endpoint=EndpointNode( - {"headers": endpoint_headers, "name": "foo", "requests": [{}]} + { + "headers": endpoint_headers, + "name": "foo", + "requests": [{}], + } ), ) assert request.headers == {"abc": "def", "xxx": "www"} @@ -150,7 +175,11 @@ def test_calls_evaluate(self, mocker, mock_evaluate): ) request = RequestNode( - {"headers": {"ghi": "jkl"}, "path": "http://foo.com", "name": "foo"}, + { + "headers": {"ghi": "jkl"}, + "path": "http://foo.com", + "name": "foo", + }, endpoint=endpoint, ) request.headers @@ -195,7 +224,11 @@ def test_calls_evaluate(self, mocker, mock_evaluate): ) request = RequestNode( - {"params": {"ghi": "jkl"}, "path": "http://foo.com", "name": "foo"}, + { + "params": {"ghi": "jkl"}, + "path": "http://foo.com", + "name": "foo", + }, endpoint=endpoint, ) request.params @@ -212,13 +245,15 @@ def test_when_request_has_no_delay(self): def test_when_request_has_delay(self): request = RequestNode( - {"name": "foo", "delay": 1}, endpoint=EndpointNode({"name": "bar"}) + {"name": "foo", "delay": 1}, + endpoint=EndpointNode({"name": "bar"}), ) assert request.delay == 1 def test_when_endpoint_has_delay(self): request = RequestNode( - {"name": "foo"}, endpoint=EndpointNode({"name": "bar", "delay": 2}) + {"name": "foo"}, + endpoint=EndpointNode({"name": "bar", "delay": 2}), ) assert request.delay == 2 @@ -239,14 +274,22 @@ def test_when_request_has_no_body(self): def test_when_request_has_body(self): request = RequestNode( - {"body": {"abc": "def"}, "path": "http://foo.com", "name": "foo"}, + { + "body": {"abc": "def"}, + "path": "http://foo.com", + "name": "foo", + }, endpoint=EndpointNode({"name": "foo", "requests": [{}]}), ) assert request.body == {"abc": "def"} def test_calls_evaluate(self, mocker, mock_evaluate): request = RequestNode( - {"body": {"ghi": "jkl"}, "path": "http://foo.com", "name": "foo"}, + { + "body": {"ghi": "jkl"}, + "path": "http://foo.com", + "name": "foo", + }, endpoint=EndpointNode({"name": "foo", "requests": [{}]}), ) request.body @@ -261,7 +304,9 @@ def mock_session(self, mocker): @pytest.fixture def mock_run_tests(self, mocker): - return mocker.patch("scanapi.tree.request_node.RequestNode._run_tests") + return mocker.patch( + "scanapi.tree.request_node.RequestNode._run_tests" + ) @pytest.fixture def mock_time_sleep(self, mocker): @@ -270,7 +315,9 @@ def mock_time_sleep(self, mocker): def test_calls_request(self, mock_session, mock_time_sleep): request = RequestNode( {"path": "http://foo.com", "name": "foo"}, - endpoint=EndpointNode({"name": "foo", "requests": [{}], "delay": 1}), + endpoint=EndpointNode( + {"name": "foo", "requests": [{}], "delay": 1} + ), ) result = request.run() @@ -298,7 +345,11 @@ def test_calls_request(self, mock_session, mock_time_sleep): @pytest.mark.parametrize("test_results, expected_no_failure", test_data) def test_build_result( - self, test_results, expected_no_failure, mock_session, mock_run_tests, + self, + test_results, + expected_no_failure, + mock_session, + mock_run_tests, ): mock_run_tests.return_value = test_results request = RequestNode( diff --git a/tests/unit/tree/test_testing_node.py b/tests/unit/tree/test_testing_node.py index bb2ecb36..d9a16520 100644 --- a/tests/unit/tree/test_testing_node.py +++ b/tests/unit/tree/test_testing_node.py @@ -19,13 +19,16 @@ def test_missing_required_keys(self): TestingNode(spec={}, request=request_node) assert ( - str(excinfo.value) == "Missing 'assert', 'name' key(s) at 'test' scope" + str(excinfo.value) + == "Missing 'assert', 'name' key(s) at 'test' scope" ) class TestFullName: def test_full_name(self): endpoint_node = EndpointNode({"name": "foo"}) - request_node = RequestNode(spec={"name": "bar"}, endpoint=endpoint_node) + request_node = RequestNode( + spec={"name": "bar"}, endpoint=endpoint_node + ) test_node = TestingNode( spec={"name": "lol", "assert": "okay"}, request=request_node ) @@ -36,7 +39,9 @@ class TestRun: @pytest.fixture def testing_node(self): endpoint_node = EndpointNode(spec={"name": "foo"}) - request_node = RequestNode(spec={"name": "bar"}, endpoint=endpoint_node) + request_node = RequestNode( + spec={"name": "bar"}, endpoint=endpoint_node + ) spec = { "name": "status_is_200", "assert": "${{ response.status_code == 200 }}", @@ -51,11 +56,15 @@ def mock_evaluate(self, mocker): @pytest.fixture def mock_increment_successes(self, mocker): - return mocker.patch("scanapi.tree.testing_node.session.increment_successes") + return mocker.patch( + "scanapi.tree.testing_node.session.increment_successes" + ) @pytest.fixture def mock_increment_failures(self, mocker): - return mocker.patch("scanapi.tree.testing_node.session.increment_failures") + return mocker.patch( + "scanapi.tree.testing_node.session.increment_failures" + ) class TestWhenTestPassed: def test_build_result( @@ -84,7 +93,9 @@ def test_increment_successes( assert mock_increment_successes.call_count == 1 assert not mock_increment_failures.called - def test_logs_test_results(self, mock_evaluate, caplog, testing_node): + def test_logs_test_results( + self, mock_evaluate, caplog, testing_node + ): mock_evaluate.return_value = (True, None) with caplog.at_level(logging.DEBUG): @@ -124,7 +135,9 @@ def test_increment_failures( assert mock_increment_failures.call_count == 1 assert not mock_increment_successes.called - def test_logs_test_results(self, mock_evaluate, caplog, testing_node): + def test_logs_test_results( + self, mock_evaluate, caplog, testing_node + ): mock_evaluate.return_value = ( False, "response.status_code == 200", From 532d8020ba1e6ddc6db588140c034b67f8eb36ef Mon Sep 17 00:00:00 2001 From: Renan Moura Date: Mon, 14 Dec 2020 16:05:30 -0300 Subject: [PATCH 5/7] Fixing flake8 error. --- scanapi/evaluators/spec_evaluator.py | 4 +- scanapi/hide_utils.py | 6 +-- scanapi/settings.py | 7 ++- scanapi/tree/endpoint_node.py | 12 ++--- scanapi/tree/request_node.py | 7 ++- tests/unit/evaluators/test_code_evaluator.py | 8 +-- tests/unit/evaluators/test_spec_evaluator.py | 7 +-- .../unit/evaluators/test_string_evaluator.py | 23 +++----- tests/unit/test_config_loader.py | 4 +- tests/unit/test_hide_utils.py | 17 ++---- tests/unit/test_main.py | 5 +- tests/unit/test_reporter.py | 8 +-- tests/unit/test_scan.py | 33 +++--------- tests/unit/test_settings.py | 12 ++--- tests/unit/test_template_render.py | 4 +- tests/unit/test_utils.py | 5 +- tests/unit/tree/test_endpoint_node.py | 5 +- tests/unit/tree/test_request_node.py | 54 +++++++------------ tests/unit/tree/test_testing_node.py | 35 +++++------- 19 files changed, 81 insertions(+), 175 deletions(-) diff --git a/scanapi/evaluators/spec_evaluator.py b/scanapi/evaluators/spec_evaluator.py index acd49cd2..329e60d5 100644 --- a/scanapi/evaluators/spec_evaluator.py +++ b/scanapi/evaluators/spec_evaluator.py @@ -20,9 +20,7 @@ def evaluate_assertion(self, element): def update(self, vars, extras=None, preevaluate=False): if preevaluate: - values = { - key: evaluate(value, extras) for key, value in vars.items() - } + values = {key: evaluate(value, extras) for key, value in vars.items()} self.registry.update(values) self.registry.update(extras) else: diff --git a/scanapi/hide_utils.py b/scanapi/hide_utils.py index 2e32ce67..5e3467ca 100644 --- a/scanapi/hide_utils.py +++ b/scanapi/hide_utils.py @@ -23,7 +23,7 @@ def hide_sensitive_info(response): def _hide(http_msg, hide_settings): - """ Private method that finds all sensitive information attributes and calls _override_info + """Private method that finds all sensitive information attributes and calls _override_info to have sensitive data replaced """ for http_attr in hide_settings: @@ -49,9 +49,7 @@ def _override_url(http_msg, secret_field): url_parsed = urlparse(http_msg.url) if secret_field in url_parsed.path: new_url = url_parsed._replace( - path=url_parsed.path.replace( - secret_field, SENSITIVE_INFO_SUBSTITUTION_FLAG - ) + path=url_parsed.path.replace(secret_field, SENSITIVE_INFO_SUBSTITUTION_FLAG) ) new_url = urlunparse(new_url) http_msg.url = new_url diff --git a/scanapi/settings.py b/scanapi/settings.py index b8e7f0ce..6828cd24 100644 --- a/scanapi/settings.py +++ b/scanapi/settings.py @@ -5,7 +5,8 @@ from scanapi.config_loader import load_config_file GLOBAL_CONFIG_PATH = os.path.join( - appdirs.site_config_dir("scanapi"), "scanapi.conf", + appdirs.site_config_dir("scanapi"), + "scanapi.conf", ) LOCAL_CONFIG_PATH = "./scanapi.conf" @@ -36,9 +37,7 @@ def save_config_file_preferences(self, config_path=None): def save_click_preferences(self, **preferences): """ Saves all preference items to the Settings object. """ - cleaned_preferences = { - k: v for k, v in preferences.items() if v is not None - } + cleaned_preferences = {k: v for k, v in preferences.items() if v is not None} self.update(**cleaned_preferences) def save_preferences(self, **click_preferences): diff --git a/scanapi/tree/endpoint_node.py b/scanapi/tree/endpoint_node.py index 78d37a2f..655fb6fd 100644 --- a/scanapi/tree/endpoint_node.py +++ b/scanapi/tree/endpoint_node.py @@ -46,8 +46,7 @@ def __build(self): self._validate() self.child_nodes = [ - EndpointNode(spec, parent=self) - for spec in self.spec.get(ENDPOINTS_KEY, []) + EndpointNode(spec, parent=self) for spec in self.spec.get(ENDPOINTS_KEY, []) ] def __repr__(self): @@ -91,7 +90,9 @@ def run(self): try: yield request.run() except Exception as e: - error_message = f"\nError to make request `{request.full_url_path}`. \n{str(e)}\n" + error_message = ( + f"\nError to make request `{request.full_url_path}`. \n{str(e)}\n" + ) logger.error(error_message) session.exit_code = ExitCode.REQUEST_ERROR continue @@ -120,9 +121,6 @@ def _get_specs(self, field_name): def _get_requests(self): return chain( - ( - RequestNode(spec, self) - for spec in self.spec.get(REQUESTS_KEY, []) - ), + (RequestNode(spec, self) for spec in self.spec.get(REQUESTS_KEY, [])), *(child._get_requests() for child in self.child_nodes), ) diff --git a/scanapi/tree/request_node.py b/scanapi/tree/request_node.py index 3f1c0520..99ce268a 100644 --- a/scanapi/tree/request_node.py +++ b/scanapi/tree/request_node.py @@ -106,9 +106,7 @@ def body(self): @property def tests(self): - return ( - TestingNode(spec, self) for spec in self.spec.get(TESTS_KEY, []) - ) + return (TestingNode(spec, self) for spec in self.spec.get(TESTS_KEY, [])) @property def retry(self): @@ -122,7 +120,8 @@ def run(self): logger.info("Making request %s %s", method, url) self.endpoint.vars.update( - self.spec.get(VARS_KEY, {}), preevaluate=False, + self.spec.get(VARS_KEY, {}), + preevaluate=False, ) session = session_with_retry(self.retry) diff --git a/tests/unit/evaluators/test_code_evaluator.py b/tests/unit/evaluators/test_code_evaluator.py index 2d1b374b..7a1b000d 100644 --- a/tests/unit/evaluators/test_code_evaluator.py +++ b/tests/unit/evaluators/test_code_evaluator.py @@ -24,9 +24,7 @@ class TestWhenItIsATestCase: @pytest.mark.parametrize("sequence, expected", test_data) def test_should_return_assert_results(self, sequence, expected): assert ( - CodeEvaluator.evaluate( - sequence, {}, is_a_test_case=True - ) + CodeEvaluator.evaluate(sequence, {}, is_a_test_case=True) == expected ) @@ -107,9 +105,7 @@ def test_should_return_evaluated_code( self, sequence, expected, response ): assert ( - CodeEvaluator.evaluate( - sequence, {"response": response} - ) + CodeEvaluator.evaluate(sequence, {"response": response}) == expected ) diff --git a/tests/unit/evaluators/test_spec_evaluator.py b/tests/unit/evaluators/test_spec_evaluator.py index 609e54eb..2f6740a5 100644 --- a/tests/unit/evaluators/test_spec_evaluator.py +++ b/tests/unit/evaluators/test_spec_evaluator.py @@ -43,9 +43,10 @@ def test_return_evaluated_dict( self, spec_evaluator, mocker, mock_string_evaluate ): mock_string_evaluate.side_effect = ["foo", "bar"] - assert spec_evaluator.evaluate( - {"app_id": "foo", "token": "bar",} - ) == {"app_id": "foo", "token": "bar",} + assert spec_evaluator.evaluate({"app_id": "foo", "token": "bar"}) == { + "app_id": "foo", + "token": "bar", + } mock_string_evaluate.assert_has_calls( [ diff --git a/tests/unit/evaluators/test_string_evaluator.py b/tests/unit/evaluators/test_string_evaluator.py index ee4c765a..34c55229 100644 --- a/tests/unit/evaluators/test_string_evaluator.py +++ b/tests/unit/evaluators/test_string_evaluator.py @@ -50,9 +50,7 @@ class TestWhenMatchesThePattern: class TestWhenEnvVarIsSetProperly: @pytest.fixture(autouse=True) def base_url_env(self): - os.environ[ - "BASE_URL" - ] = "https://jsonplaceholder.typicode.com" + os.environ["BASE_URL"] = "https://jsonplaceholder.typicode.com" os.environ["POST_ID"] = "2" test_data = [ @@ -73,9 +71,7 @@ def base_url_env(self): @pytest.mark.parametrize("sequence, expected", test_data) def test_should_return_evaluated_var(self, sequence, expected): - assert ( - StringEvaluator._evaluate_env_var(sequence) == expected - ) + assert StringEvaluator._evaluate_env_var(sequence) == expected class TestWhenThereIsNoCorrespondingEnvVar: @pytest.fixture(autouse=True) @@ -98,10 +94,7 @@ class TestWhenDoesNotMatchThePattern: @pytest.mark.parametrize("sequence", test_data) def test_should_return_sequence(self, sequence): - assert ( - StringEvaluator._evaluate_custom_var(sequence, {}) - == sequence - ) + assert StringEvaluator._evaluate_custom_var(sequence, {}) == sequence class TestWhenMatchesThePattern: class TestWhenCodeDoesNotContainThePreSavedCustomVar: @@ -116,8 +109,7 @@ class TestWhenCodeDoesNotContainThePreSavedCustomVar: @pytest.mark.parametrize("sequence", test_data) def test_should_return_sequence(self, sequence): assert ( - StringEvaluator._evaluate_custom_var(sequence, {}) - == sequence + StringEvaluator._evaluate_custom_var(sequence, {}) == sequence ) class TestWhenCodeContainsThePreSavedCustomVar: @@ -141,8 +133,7 @@ def test_should_return_sequence(self, sequence, expected): "api-token": "xwo", } assert ( - StringEvaluator._evaluate_custom_var(sequence, vars) - == expected + StringEvaluator._evaluate_custom_var(sequence, vars) == expected ) class TestReplaceVarWithValue: @@ -169,9 +160,7 @@ class TestReplaceVarWithValue: @pytest.mark.parametrize( "sequence, variable, variable_value, expected", test_data ) - def test_should_replace( - self, sequence, variable, variable_value, expected - ): + def test_should_replace(self, sequence, variable, variable_value, expected): assert ( StringEvaluator.replace_var_with_value( sequence, variable, variable_value diff --git a/tests/unit/test_config_loader.py b/tests/unit/test_config_loader.py index 0b979adb..ed8583f1 100644 --- a/tests/unit/test_config_loader.py +++ b/tests/unit/test_config_loader.py @@ -46,9 +46,7 @@ def test_should_raise_exception(self): with pytest.raises(EmptyConfigFileError) as excinfo: load_config_file("tests/data/empty.yaml") - assert ( - str(excinfo.value) == "File 'tests/data/empty.yaml' is empty." - ) + assert str(excinfo.value) == "File 'tests/data/empty.yaml' is empty." class TestWhenIncludeFileDoesNotExist: def test_should_raise_exception(self): diff --git a/tests/unit/test_hide_utils.py b/tests/unit/test_hide_utils.py index 32f77509..8b8f35b0 100644 --- a/tests/unit/test_hide_utils.py +++ b/tests/unit/test_hide_utils.py @@ -31,9 +31,7 @@ def mock__hide(self, mocker): ), ] - @pytest.mark.parametrize( - "settings, request_settings, response_settings", test_data - ) + @pytest.mark.parametrize("settings, request_settings, response_settings", test_data) def test_calls__hide( self, settings, @@ -90,10 +88,7 @@ def test_overrides_url(self, response): _override_info(response, http_attr, secret_field) - assert ( - response.url - == "http://test.com/users/SENSITIVE_INFORMATION/details" - ) + assert response.url == "http://test.com/users/SENSITIVE_INFORMATION/details" def test_overrides_headers(self, response): response.headers = {"abc": "123"} @@ -105,9 +100,7 @@ def test_overrides_headers(self, response): assert response.headers["abc"] == "SENSITIVE_INFORMATION" def test_overrides_body(self, response): - response.body = ( - b'{"id": "abc21", "name": "Tarik", "yearsOfExperience": 2}' - ) + response.body = b'{"id": "abc21", "name": "Tarik", "yearsOfExperience": 2}' http_attr = "body" secret_field = "id" @@ -120,9 +113,7 @@ def test_overrides_body(self, response): def test_overrides_params(self, response): param = "test" - response.url = ( - "http://test.com/users/details?test=test&test2=test&test=test2" - ) + response.url = "http://test.com/users/details?test=test&test2=test&test=test2" http_attr = "params" secret_field = param diff --git a/tests/unit/test_main.py b/tests/unit/test_main.py index 8d7dae90..2fd4a7c8 100644 --- a/tests/unit/test_main.py +++ b/tests/unit/test_main.py @@ -43,7 +43,4 @@ def test_should_log_error(self, mocker, caplog): assert mock_save_preferences.called assert result.exit_code == 4 - assert ( - "Error loading configuration file.\nPyYAML: error foo" - in caplog.text - ) + assert "Error loading configuration file.\nPyYAML: error foo" in caplog.text diff --git a/tests/unit/test_reporter.py b/tests/unit/test_reporter.py index ae5dc439..8a4fbbe0 100644 --- a/tests/unit/test_reporter.py +++ b/tests/unit/test_reporter.py @@ -69,9 +69,7 @@ def test_should_write_to_default_output( reporter = Reporter() reporter.write(fake_results) - mocked__render.assert_called_once_with( - "report.html", context, False - ) + mocked__render.assert_called_once_with("report.html", context, False) mocked__open.assert_called_once_with( "scanapi-report.html", "w", newline="\n" ) @@ -107,9 +105,7 @@ def test_should_handle_custom_templates( reporter = Reporter(template="my-template.html") reporter.write(fake_results) - mocked__render.assert_called_once_with( - "my-template.html", context, True - ) + mocked__render.assert_called_once_with("my-template.html", context, True) mocked__open.assert_called_once_with( "scanapi-report.html", "w", newline="\n" ) diff --git a/tests/unit/test_scan.py b/tests/unit/test_scan.py index 057afe67..d8ce6b84 100644 --- a/tests/unit/test_scan.py +++ b/tests/unit/test_scan.py @@ -46,9 +46,7 @@ def test_should_log_error(self, mocker, caplog): "scanapi.scan.settings", {"spec_path": "invalid_path/scanapi.yaml"}, ) - mocker.patch( - "scanapi.scan.load_config_file", side_effect=file_not_found - ) + mocker.patch("scanapi.scan.load_config_file", side_effect=file_not_found) with caplog.at_level(logging.ERROR): with pytest.raises(SystemExit) as excinfo: scan() @@ -65,9 +63,7 @@ def test_should_log_error(self, mocker, caplog): class TestWhenAPISpecFileIsEmpty: @pytest.mark.it("should an log error") def test_should_log_error(self, mocker, caplog): - mocker.patch( - "scanapi.scan.load_config_file", side_effect=empty_config_file - ) + mocker.patch("scanapi.scan.load_config_file", side_effect=empty_config_file) with caplog.at_level(logging.ERROR): with pytest.raises(SystemExit) as excinfo: @@ -85,9 +81,7 @@ def test_should_log_error(self, mocker, caplog): class TestWhenAPISpecFileHasAnError: @pytest.mark.it("should log error") def test_should_log_error(self, mocker, caplog): - mocker.patch( - "scanapi.scan.load_config_file", side_effect=yaml_error - ) + mocker.patch("scanapi.scan.load_config_file", side_effect=yaml_error) with caplog.at_level(logging.ERROR): with pytest.raises(SystemExit) as excinfo: scan() @@ -95,22 +89,15 @@ def test_should_log_error(self, mocker, caplog): assert excinfo.type == SystemExit assert excinfo.value.code == 4 - assert ( - "Error loading specification file.\nPyYAML: error foo" - in caplog.text - ) + assert "Error loading specification file.\nPyYAML: error foo" in caplog.text @pytest.mark.context("When APISpec Has An Invalid Key") class TestWhenAPISpecHasAnInvalidKey: @pytest.mark.it("should log error") def test_should_log_error(self, mocker, caplog): - mock_load_config_file = mocker.patch( - "scanapi.scan.load_config_file" - ) + mock_load_config_file = mocker.patch("scanapi.scan.load_config_file") mock_load_config_file.return_value = {"blah": "blah"} - mocker.patch( - "scanapi.scan.EndpointNode.__init__", side_effect=invalid_key - ) + mocker.patch("scanapi.scan.EndpointNode.__init__", side_effect=invalid_key) with caplog.at_level(logging.ERROR): with pytest.raises(SystemExit) as excinfo: scan() @@ -127,13 +114,9 @@ def test_should_log_error(self, mocker, caplog): class TestWhenAPISpecIsOk: @pytest.mark.it("should call reporter write_report") def test_should_call_reporter(self, mocker, response): - mock_load_config_file = mocker.patch( - "scanapi.scan.load_config_file" - ) + mock_load_config_file = mocker.patch("scanapi.scan.load_config_file") mock_load_config_file.return_value = {"endpoints": []} - mock_endpoint_init = mocker.patch( - "scanapi.scan.EndpointNode.__init__" - ) + mock_endpoint_init = mocker.patch("scanapi.scan.EndpointNode.__init__") mock_endpoint_init.return_value = None mock_endpoint_run = mocker.patch("scanapi.scan.EndpointNode.run") mock_endpoint_run.return_value = [response] diff --git a/tests/unit/test_settings.py b/tests/unit/test_settings.py index f43a6585..0b7ee4f2 100644 --- a/tests/unit/test_settings.py +++ b/tests/unit/test_settings.py @@ -52,12 +52,8 @@ class TestWithConfigFile: def test_should_save_preferences(self, mock_load_config_file): config_path = "my_config_file.yaml" settings.save_config_file_preferences(config_path) - assert settings["config_path"].endswith( - "my_config_file.yaml" - ) - mock_load_config_file.assert_called_with( - "my_config_file.yaml" - ) + assert settings["config_path"].endswith("my_config_file.yaml") + mock_load_config_file.assert_called_with("my_config_file.yaml") class TestWithoutConfigFile: def test_should_raise_exception(self): @@ -92,9 +88,7 @@ def test_should_save_preferences( class TestSavePreferences: @pytest.fixture def mock_save_click_preferences(self, mocker): - return mocker.patch( - "scanapi.settings.Settings.save_click_preferences" - ) + return mocker.patch("scanapi.settings.Settings.save_click_preferences") @pytest.fixture def mock_save_config_file_preferences(self, mocker): diff --git a/tests/unit/test_template_render.py b/tests/unit/test_template_render.py index 9bf9049c..ebc58ea0 100644 --- a/tests/unit/test_template_render.py +++ b/tests/unit/test_template_render.py @@ -7,9 +7,7 @@ class TestTemplateRender: class TestRender: @pytest.fixture def mocked__get_template(self, mocker): - return mocker.patch( - "scanapi.template_render.Environment.get_template" - ) + return mocker.patch("scanapi.template_render.Environment.get_template") def test_should_call_jinja_render(self, mocked__get_template): context = {"my_context": "foo"} diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py index 2186dba4..1526949e 100644 --- a/tests/unit/test_utils.py +++ b/tests/unit/test_utils.py @@ -87,10 +87,7 @@ def test_should_raise_an_exception(self): with pytest.raises(MissingMandatoryKeyError) as excinfo: validate_keys(keys, available_keys, mandatory_keys, scope) - assert ( - str(excinfo.value) - == "Missing 'key2' key(s) at 'endpoint' scope" - ) + assert str(excinfo.value) == "Missing 'key2' key(s) at 'endpoint' scope" class TestThereIsNotAnInvalidKeysOrMissingMandotoryKeys: def test_should_not_raise_an_exception(self): diff --git a/tests/unit/tree/test_endpoint_node.py b/tests/unit/tree/test_endpoint_node.py index 75fbf696..8a6d84e4 100644 --- a/tests/unit/tree/test_endpoint_node.py +++ b/tests/unit/tree/test_endpoint_node.py @@ -25,10 +25,7 @@ def test_missing_required_keys(self): endpoints = [{}, {}] EndpointNode({"endpoints": endpoints}) - assert ( - str(excinfo.value) - == "Missing 'name' key(s) at 'endpoint' scope" - ) + assert str(excinfo.value) == "Missing 'name' key(s) at 'endpoint' scope" def test_no_required_keys_for_root(self): assert EndpointNode({}) diff --git a/tests/unit/tree/test_request_node.py b/tests/unit/tree/test_request_node.py index 0721547c..b8cfa030 100644 --- a/tests/unit/tree/test_request_node.py +++ b/tests/unit/tree/test_request_node.py @@ -7,9 +7,7 @@ class TestRequestNode: @pytest.fixture def mock_evaluate(self, mocker): - mock_func = mocker.patch( - "scanapi.tree.request_node.SpecEvaluator.evaluate" - ) + mock_func = mocker.patch("scanapi.tree.request_node.SpecEvaluator.evaluate") mock_func.return_value = "" return mock_func @@ -29,9 +27,7 @@ def test_missing_required_keys(self): endpoint=EndpointNode({"name": "foo", "requests": [{}]}), ) - assert ( - str(excinfo.value) == "Missing 'name' key(s) at 'request' scope" - ) + assert str(excinfo.value) == "Missing 'name' key(s) at 'request' scope" class TestHTTPMethod: def test_when_request_has_method(self): @@ -50,14 +46,14 @@ def test_when_request_has_no_method(self): def test_when_method_is_invalid(self): request = RequestNode( - {"method": "xxx", "name": "foo", "path": "http:foo.com"}, + {"method": "XXX", "name": "foo", "path": "http:foo.com"}, endpoint=EndpointNode({"name": "foo", "requests": [{}]}), ) with pytest.raises(HTTPMethodNotAllowedError) as excinfo: request.http_method expected = ( - "HTTP method not supported: XXX." + f"HTTP method not supported: {request.spec.get('method')}." f" Supported methods: {request.ALLOWED_HTTP_METHODS}." ) assert str(excinfo.value) == expected @@ -73,9 +69,7 @@ def test_when_request_has_name(self): @pytest.mark.skip("it should validate mandatory `name` key before") def test_when_request_has_no_name(self): with pytest.raises(MissingMandatoryKeyError) as excinfo: - RequestNode( - {}, endpoint=EndpointNode({"name": "foo", "requests": []}) - ) + RequestNode({}, endpoint=EndpointNode({"name": "foo", "requests": []})) assert str(excinfo.value) == "Missing name, path at 'request'" @@ -84,9 +78,7 @@ def test_when_endpoint_has_no_url(self): path = "http://foo.com" request = RequestNode( {"name": "foo", "path": path}, - endpoint=EndpointNode( - {"name": "foo", "requests": [{}], "path": ""} - ), + endpoint=EndpointNode({"name": "foo", "requests": [{}], "path": ""}), ) assert request.full_url_path == path @@ -95,36 +87,28 @@ def test_when_endpoint_has_url(self): endpoint = EndpointNode( {"name": "foo", "requests": [{}], "path": endpoint_path} ) - request = RequestNode( - {"path": "/foo", "name": "foo"}, endpoint=endpoint - ) + request = RequestNode({"path": "/foo", "name": "foo"}, endpoint=endpoint) assert request.full_url_path == "http://foo.com/api/foo" def test_with_trailing_slashes(self): endpoint = EndpointNode( {"name": "foo", "requests": [{}], "path": "http://foo.com/"} ) - request = RequestNode( - {"name": "foo", "path": "/foo/"}, endpoint=endpoint - ) + request = RequestNode({"name": "foo", "path": "/foo/"}, endpoint=endpoint) assert request.full_url_path == "http://foo.com/foo/" def test_with_trailintest_with_path_not_stringg_slashes(self): endpoint = EndpointNode( {"name": "foo", "requests": [{}], "path": "http://foo.com/"} ) - request = RequestNode( - {"name": "foo", "path": []}, endpoint=endpoint - ) + request = RequestNode({"name": "foo", "path": []}, endpoint=endpoint) assert request.full_url_path == "http://foo.com/[]" def test_calls_evaluate(self, mocker, mock_evaluate): endpoint = EndpointNode( {"name": "foo", "requests": [{}], "path": "http://foo.com/"} ) - request = RequestNode( - {"path": "/foo/", "name": "foo"}, endpoint=endpoint - ) + request = RequestNode({"path": "/foo/", "name": "foo"}, endpoint=endpoint) request.full_url_path calls = [mocker.call("http://foo.com/"), mocker.call("/foo/")] @@ -312,9 +296,7 @@ def mock_session(self, mocker): @pytest.fixture def mock_run_tests(self, mocker): - return mocker.patch( - "scanapi.tree.request_node.RequestNode._run_tests" - ) + return mocker.patch("scanapi.tree.request_node.RequestNode._run_tests") @pytest.fixture def mock_time_sleep(self, mocker): @@ -323,9 +305,7 @@ def mock_time_sleep(self, mocker): def test_calls_request(self, mock_session, mock_time_sleep): request = RequestNode( {"path": "http://foo.com", "name": "foo"}, - endpoint=EndpointNode( - {"name": "foo", "requests": [{}], "delay": 1} - ), + endpoint=EndpointNode({"name": "foo", "requests": [{}], "delay": 1}), ) result = request.run() @@ -347,8 +327,14 @@ def test_calls_request(self, mock_session, mock_time_sleep): } test_data = [ - ([{"status": "passed"}, {"status": "failed"}], False,), - ([{"status": "passed"}, {"status": "passed"}], True,), + ( + [{"status": "passed"}, {"status": "failed"}], + False, + ), + ( + [{"status": "passed"}, {"status": "passed"}], + True, + ), ] @pytest.mark.parametrize("test_results, expected_no_failure", test_data) diff --git a/tests/unit/tree/test_testing_node.py b/tests/unit/tree/test_testing_node.py index d9a16520..6ca0ea43 100644 --- a/tests/unit/tree/test_testing_node.py +++ b/tests/unit/tree/test_testing_node.py @@ -19,16 +19,13 @@ def test_missing_required_keys(self): TestingNode(spec={}, request=request_node) assert ( - str(excinfo.value) - == "Missing 'assert', 'name' key(s) at 'test' scope" + str(excinfo.value) == "Missing 'assert', 'name' key(s) at 'test' scope" ) class TestFullName: def test_full_name(self): endpoint_node = EndpointNode({"name": "foo"}) - request_node = RequestNode( - spec={"name": "bar"}, endpoint=endpoint_node - ) + request_node = RequestNode(spec={"name": "bar"}, endpoint=endpoint_node) test_node = TestingNode( spec={"name": "lol", "assert": "okay"}, request=request_node ) @@ -39,9 +36,7 @@ class TestRun: @pytest.fixture def testing_node(self): endpoint_node = EndpointNode(spec={"name": "foo"}) - request_node = RequestNode( - spec={"name": "bar"}, endpoint=endpoint_node - ) + request_node = RequestNode(spec={"name": "bar"}, endpoint=endpoint_node) spec = { "name": "status_is_200", "assert": "${{ response.status_code == 200 }}", @@ -56,19 +51,17 @@ def mock_evaluate(self, mocker): @pytest.fixture def mock_increment_successes(self, mocker): - return mocker.patch( - "scanapi.tree.testing_node.session.increment_successes" - ) + return mocker.patch("scanapi.tree.testing_node.session.increment_successes") @pytest.fixture def mock_increment_failures(self, mocker): - return mocker.patch( - "scanapi.tree.testing_node.session.increment_failures" - ) + return mocker.patch("scanapi.tree.testing_node.session.increment_failures") class TestWhenTestPassed: def test_build_result( - self, mock_evaluate, testing_node, + self, + mock_evaluate, + testing_node, ): mock_evaluate.return_value = (True, None) @@ -93,9 +86,7 @@ def test_increment_successes( assert mock_increment_successes.call_count == 1 assert not mock_increment_failures.called - def test_logs_test_results( - self, mock_evaluate, caplog, testing_node - ): + def test_logs_test_results(self, mock_evaluate, caplog, testing_node): mock_evaluate.return_value = (True, None) with caplog.at_level(logging.DEBUG): @@ -104,7 +95,9 @@ def test_logs_test_results( class TestWhenTestFailed: def test_build_result( - self, mock_evaluate, testing_node, + self, + mock_evaluate, + testing_node, ): mock_evaluate.return_value = ( False, @@ -135,9 +128,7 @@ def test_increment_failures( assert mock_increment_failures.call_count == 1 assert not mock_increment_successes.called - def test_logs_test_results( - self, mock_evaluate, caplog, testing_node - ): + def test_logs_test_results(self, mock_evaluate, caplog, testing_node): mock_evaluate.return_value = ( False, "response.status_code == 200", From 3a874a4b1f1f908202dc8e49b2ad7b82563738c9 Mon Sep 17 00:00:00 2001 From: Renan Moura Date: Mon, 14 Dec 2020 16:08:45 -0300 Subject: [PATCH 6/7] Updating changelog with new supported methods. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d25edb9..ca6d1a09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Hide sensitive information in the URL Query Params [#304](https://github.com/scanapi/scanapi/pull/325) - Add anchor link for each request in the report to make it easily shareable. [#317](https://github.com/scanapi/scanapi/pull/317) - Update black version on pre-commit configurations to avoid conflicts with flake8 [#346](https://github.com/scanapi/scanapi/pull/346) +- Added support to HTTP methods HEAD and OPTIONS [#350](https://github.com/scanapi/scanapi/pull/350) ### Changed - Updated poetry-publish version to v1.3 [#311](https://github.com/scanapi/scanapi/pull/311) From be21a216302174f8e6cadf5c45be7c3524e3c1ca Mon Sep 17 00:00:00 2001 From: Renan Moura Date: Wed, 16 Dec 2020 11:12:41 -0300 Subject: [PATCH 7/7] Fixing code formatting. --- scanapi/evaluators/spec_evaluator.py | 4 ++- scanapi/hide_utils.py | 4 ++- scanapi/reporter.py | 5 ++- scanapi/scan.py | 2 +- scanapi/settings.py | 7 ++-- scanapi/tree/endpoint_node.py | 12 ++++--- scanapi/tree/request_node.py | 7 ++-- scanapi/utils.py | 4 +-- tests/unit/test_config_loader.py | 4 ++- tests/unit/test_hide_utils.py | 17 +++++++--- tests/unit/test_main.py | 5 ++- tests/unit/test_reporter.py | 8 +++-- tests/unit/test_scan.py | 33 +++++++++++++----- tests/unit/test_settings.py | 12 +++++-- tests/unit/test_utils.py | 5 ++- tests/unit/tree/test_request_node.py | 50 ++++++++++++++++++---------- tests/unit/tree/test_testing_node.py | 35 +++++++++++-------- 17 files changed, 144 insertions(+), 70 deletions(-) diff --git a/scanapi/evaluators/spec_evaluator.py b/scanapi/evaluators/spec_evaluator.py index 329e60d5..acd49cd2 100644 --- a/scanapi/evaluators/spec_evaluator.py +++ b/scanapi/evaluators/spec_evaluator.py @@ -20,7 +20,9 @@ def evaluate_assertion(self, element): def update(self, vars, extras=None, preevaluate=False): if preevaluate: - values = {key: evaluate(value, extras) for key, value in vars.items()} + values = { + key: evaluate(value, extras) for key, value in vars.items() + } self.registry.update(values) self.registry.update(extras) else: diff --git a/scanapi/hide_utils.py b/scanapi/hide_utils.py index 5e3467ca..04a74b5a 100644 --- a/scanapi/hide_utils.py +++ b/scanapi/hide_utils.py @@ -49,7 +49,9 @@ def _override_url(http_msg, secret_field): url_parsed = urlparse(http_msg.url) if secret_field in url_parsed.path: new_url = url_parsed._replace( - path=url_parsed.path.replace(secret_field, SENSITIVE_INFO_SUBSTITUTION_FLAG) + path=url_parsed.path.replace( + secret_field, SENSITIVE_INFO_SUBSTITUTION_FLAG + ) ) new_url = urlunparse(new_url) http_msg.url = new_url diff --git a/scanapi/reporter.py b/scanapi/reporter.py index ca7da632..8fe7fb6e 100644 --- a/scanapi/reporter.py +++ b/scanapi/reporter.py @@ -17,8 +17,7 @@ def __init__(self, output_path=None, template=None): self.template = template def write(self, results): - """ Part of the Reporter instance that is responsible for writing scanapi-report.html. - """ + """Part of the Reporter instance that is responsible for writing scanapi-report.html.""" logger.info("Writing documentation") template_path = self.template if self.template else "report.html" @@ -35,7 +34,7 @@ def write(self, results): @staticmethod def _build_context(results): - """ Private method of Reporter returns dict containing keys datetime, + """Private method of Reporter returns dict containing keys datetime, project_name, results and session and their corresponding values. """ return { diff --git a/scanapi/scan.py b/scanapi/scan.py index c3ce1159..c84a4bc2 100644 --- a/scanapi/scan.py +++ b/scanapi/scan.py @@ -58,7 +58,7 @@ def scan(): def write_report(results): - """ Constructs a Reporter object and calls the write method of Reporter to push + """Constructs a Reporter object and calls the write method of Reporter to push the results to a file. """ reporter = Reporter(settings["output_path"], settings["template"]) diff --git a/scanapi/settings.py b/scanapi/settings.py index 6828cd24..b8e7f0ce 100644 --- a/scanapi/settings.py +++ b/scanapi/settings.py @@ -5,8 +5,7 @@ from scanapi.config_loader import load_config_file GLOBAL_CONFIG_PATH = os.path.join( - appdirs.site_config_dir("scanapi"), - "scanapi.conf", + appdirs.site_config_dir("scanapi"), "scanapi.conf", ) LOCAL_CONFIG_PATH = "./scanapi.conf" @@ -37,7 +36,9 @@ def save_config_file_preferences(self, config_path=None): def save_click_preferences(self, **preferences): """ Saves all preference items to the Settings object. """ - cleaned_preferences = {k: v for k, v in preferences.items() if v is not None} + cleaned_preferences = { + k: v for k, v in preferences.items() if v is not None + } self.update(**cleaned_preferences) def save_preferences(self, **click_preferences): diff --git a/scanapi/tree/endpoint_node.py b/scanapi/tree/endpoint_node.py index 655fb6fd..78d37a2f 100644 --- a/scanapi/tree/endpoint_node.py +++ b/scanapi/tree/endpoint_node.py @@ -46,7 +46,8 @@ def __build(self): self._validate() self.child_nodes = [ - EndpointNode(spec, parent=self) for spec in self.spec.get(ENDPOINTS_KEY, []) + EndpointNode(spec, parent=self) + for spec in self.spec.get(ENDPOINTS_KEY, []) ] def __repr__(self): @@ -90,9 +91,7 @@ def run(self): try: yield request.run() except Exception as e: - error_message = ( - f"\nError to make request `{request.full_url_path}`. \n{str(e)}\n" - ) + error_message = f"\nError to make request `{request.full_url_path}`. \n{str(e)}\n" logger.error(error_message) session.exit_code = ExitCode.REQUEST_ERROR continue @@ -121,6 +120,9 @@ def _get_specs(self, field_name): def _get_requests(self): return chain( - (RequestNode(spec, self) for spec in self.spec.get(REQUESTS_KEY, [])), + ( + RequestNode(spec, self) + for spec in self.spec.get(REQUESTS_KEY, []) + ), *(child._get_requests() for child in self.child_nodes), ) diff --git a/scanapi/tree/request_node.py b/scanapi/tree/request_node.py index 99ce268a..3f1c0520 100644 --- a/scanapi/tree/request_node.py +++ b/scanapi/tree/request_node.py @@ -106,7 +106,9 @@ def body(self): @property def tests(self): - return (TestingNode(spec, self) for spec in self.spec.get(TESTS_KEY, [])) + return ( + TestingNode(spec, self) for spec in self.spec.get(TESTS_KEY, []) + ) @property def retry(self): @@ -120,8 +122,7 @@ def run(self): logger.info("Making request %s %s", method, url) self.endpoint.vars.update( - self.spec.get(VARS_KEY, {}), - preevaluate=False, + self.spec.get(VARS_KEY, {}), preevaluate=False, ) session = session_with_retry(self.retry) diff --git a/scanapi/utils.py b/scanapi/utils.py index 1db4edda..b6aef0cd 100644 --- a/scanapi/utils.py +++ b/scanapi/utils.py @@ -7,7 +7,7 @@ def join_urls(first_url, second_url): - """ Function that returns one url if two aren't given else joins the two urls and + """Function that returns one url if two aren't given else joins the two urls and returns them. """ if not first_url: @@ -43,7 +43,7 @@ def _validate_required_keys(keys, required_keys, scope): def session_with_retry(retry_configuration): - """ Instantiate a requests session with the retry configuration if provided by + """Instantiate a requests session with the retry configuration if provided by instantiating an HTTPAdapter mounting it into the mounting it into the `requests.Session`. """ diff --git a/tests/unit/test_config_loader.py b/tests/unit/test_config_loader.py index ed8583f1..0b979adb 100644 --- a/tests/unit/test_config_loader.py +++ b/tests/unit/test_config_loader.py @@ -46,7 +46,9 @@ def test_should_raise_exception(self): with pytest.raises(EmptyConfigFileError) as excinfo: load_config_file("tests/data/empty.yaml") - assert str(excinfo.value) == "File 'tests/data/empty.yaml' is empty." + assert ( + str(excinfo.value) == "File 'tests/data/empty.yaml' is empty." + ) class TestWhenIncludeFileDoesNotExist: def test_should_raise_exception(self): diff --git a/tests/unit/test_hide_utils.py b/tests/unit/test_hide_utils.py index 8b8f35b0..32f77509 100644 --- a/tests/unit/test_hide_utils.py +++ b/tests/unit/test_hide_utils.py @@ -31,7 +31,9 @@ def mock__hide(self, mocker): ), ] - @pytest.mark.parametrize("settings, request_settings, response_settings", test_data) + @pytest.mark.parametrize( + "settings, request_settings, response_settings", test_data + ) def test_calls__hide( self, settings, @@ -88,7 +90,10 @@ def test_overrides_url(self, response): _override_info(response, http_attr, secret_field) - assert response.url == "http://test.com/users/SENSITIVE_INFORMATION/details" + assert ( + response.url + == "http://test.com/users/SENSITIVE_INFORMATION/details" + ) def test_overrides_headers(self, response): response.headers = {"abc": "123"} @@ -100,7 +105,9 @@ def test_overrides_headers(self, response): assert response.headers["abc"] == "SENSITIVE_INFORMATION" def test_overrides_body(self, response): - response.body = b'{"id": "abc21", "name": "Tarik", "yearsOfExperience": 2}' + response.body = ( + b'{"id": "abc21", "name": "Tarik", "yearsOfExperience": 2}' + ) http_attr = "body" secret_field = "id" @@ -113,7 +120,9 @@ def test_overrides_body(self, response): def test_overrides_params(self, response): param = "test" - response.url = "http://test.com/users/details?test=test&test2=test&test=test2" + response.url = ( + "http://test.com/users/details?test=test&test2=test&test=test2" + ) http_attr = "params" secret_field = param diff --git a/tests/unit/test_main.py b/tests/unit/test_main.py index 2fd4a7c8..8d7dae90 100644 --- a/tests/unit/test_main.py +++ b/tests/unit/test_main.py @@ -43,4 +43,7 @@ def test_should_log_error(self, mocker, caplog): assert mock_save_preferences.called assert result.exit_code == 4 - assert "Error loading configuration file.\nPyYAML: error foo" in caplog.text + assert ( + "Error loading configuration file.\nPyYAML: error foo" + in caplog.text + ) diff --git a/tests/unit/test_reporter.py b/tests/unit/test_reporter.py index 8a4fbbe0..ae5dc439 100644 --- a/tests/unit/test_reporter.py +++ b/tests/unit/test_reporter.py @@ -69,7 +69,9 @@ def test_should_write_to_default_output( reporter = Reporter() reporter.write(fake_results) - mocked__render.assert_called_once_with("report.html", context, False) + mocked__render.assert_called_once_with( + "report.html", context, False + ) mocked__open.assert_called_once_with( "scanapi-report.html", "w", newline="\n" ) @@ -105,7 +107,9 @@ def test_should_handle_custom_templates( reporter = Reporter(template="my-template.html") reporter.write(fake_results) - mocked__render.assert_called_once_with("my-template.html", context, True) + mocked__render.assert_called_once_with( + "my-template.html", context, True + ) mocked__open.assert_called_once_with( "scanapi-report.html", "w", newline="\n" ) diff --git a/tests/unit/test_scan.py b/tests/unit/test_scan.py index d8ce6b84..057afe67 100644 --- a/tests/unit/test_scan.py +++ b/tests/unit/test_scan.py @@ -46,7 +46,9 @@ def test_should_log_error(self, mocker, caplog): "scanapi.scan.settings", {"spec_path": "invalid_path/scanapi.yaml"}, ) - mocker.patch("scanapi.scan.load_config_file", side_effect=file_not_found) + mocker.patch( + "scanapi.scan.load_config_file", side_effect=file_not_found + ) with caplog.at_level(logging.ERROR): with pytest.raises(SystemExit) as excinfo: scan() @@ -63,7 +65,9 @@ def test_should_log_error(self, mocker, caplog): class TestWhenAPISpecFileIsEmpty: @pytest.mark.it("should an log error") def test_should_log_error(self, mocker, caplog): - mocker.patch("scanapi.scan.load_config_file", side_effect=empty_config_file) + mocker.patch( + "scanapi.scan.load_config_file", side_effect=empty_config_file + ) with caplog.at_level(logging.ERROR): with pytest.raises(SystemExit) as excinfo: @@ -81,7 +85,9 @@ def test_should_log_error(self, mocker, caplog): class TestWhenAPISpecFileHasAnError: @pytest.mark.it("should log error") def test_should_log_error(self, mocker, caplog): - mocker.patch("scanapi.scan.load_config_file", side_effect=yaml_error) + mocker.patch( + "scanapi.scan.load_config_file", side_effect=yaml_error + ) with caplog.at_level(logging.ERROR): with pytest.raises(SystemExit) as excinfo: scan() @@ -89,15 +95,22 @@ def test_should_log_error(self, mocker, caplog): assert excinfo.type == SystemExit assert excinfo.value.code == 4 - assert "Error loading specification file.\nPyYAML: error foo" in caplog.text + assert ( + "Error loading specification file.\nPyYAML: error foo" + in caplog.text + ) @pytest.mark.context("When APISpec Has An Invalid Key") class TestWhenAPISpecHasAnInvalidKey: @pytest.mark.it("should log error") def test_should_log_error(self, mocker, caplog): - mock_load_config_file = mocker.patch("scanapi.scan.load_config_file") + mock_load_config_file = mocker.patch( + "scanapi.scan.load_config_file" + ) mock_load_config_file.return_value = {"blah": "blah"} - mocker.patch("scanapi.scan.EndpointNode.__init__", side_effect=invalid_key) + mocker.patch( + "scanapi.scan.EndpointNode.__init__", side_effect=invalid_key + ) with caplog.at_level(logging.ERROR): with pytest.raises(SystemExit) as excinfo: scan() @@ -114,9 +127,13 @@ def test_should_log_error(self, mocker, caplog): class TestWhenAPISpecIsOk: @pytest.mark.it("should call reporter write_report") def test_should_call_reporter(self, mocker, response): - mock_load_config_file = mocker.patch("scanapi.scan.load_config_file") + mock_load_config_file = mocker.patch( + "scanapi.scan.load_config_file" + ) mock_load_config_file.return_value = {"endpoints": []} - mock_endpoint_init = mocker.patch("scanapi.scan.EndpointNode.__init__") + mock_endpoint_init = mocker.patch( + "scanapi.scan.EndpointNode.__init__" + ) mock_endpoint_init.return_value = None mock_endpoint_run = mocker.patch("scanapi.scan.EndpointNode.run") mock_endpoint_run.return_value = [response] diff --git a/tests/unit/test_settings.py b/tests/unit/test_settings.py index 0b7ee4f2..f43a6585 100644 --- a/tests/unit/test_settings.py +++ b/tests/unit/test_settings.py @@ -52,8 +52,12 @@ class TestWithConfigFile: def test_should_save_preferences(self, mock_load_config_file): config_path = "my_config_file.yaml" settings.save_config_file_preferences(config_path) - assert settings["config_path"].endswith("my_config_file.yaml") - mock_load_config_file.assert_called_with("my_config_file.yaml") + assert settings["config_path"].endswith( + "my_config_file.yaml" + ) + mock_load_config_file.assert_called_with( + "my_config_file.yaml" + ) class TestWithoutConfigFile: def test_should_raise_exception(self): @@ -88,7 +92,9 @@ def test_should_save_preferences( class TestSavePreferences: @pytest.fixture def mock_save_click_preferences(self, mocker): - return mocker.patch("scanapi.settings.Settings.save_click_preferences") + return mocker.patch( + "scanapi.settings.Settings.save_click_preferences" + ) @pytest.fixture def mock_save_config_file_preferences(self, mocker): diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py index 1526949e..2186dba4 100644 --- a/tests/unit/test_utils.py +++ b/tests/unit/test_utils.py @@ -87,7 +87,10 @@ def test_should_raise_an_exception(self): with pytest.raises(MissingMandatoryKeyError) as excinfo: validate_keys(keys, available_keys, mandatory_keys, scope) - assert str(excinfo.value) == "Missing 'key2' key(s) at 'endpoint' scope" + assert ( + str(excinfo.value) + == "Missing 'key2' key(s) at 'endpoint' scope" + ) class TestThereIsNotAnInvalidKeysOrMissingMandotoryKeys: def test_should_not_raise_an_exception(self): diff --git a/tests/unit/tree/test_request_node.py b/tests/unit/tree/test_request_node.py index b8cfa030..8070cc16 100644 --- a/tests/unit/tree/test_request_node.py +++ b/tests/unit/tree/test_request_node.py @@ -7,7 +7,9 @@ class TestRequestNode: @pytest.fixture def mock_evaluate(self, mocker): - mock_func = mocker.patch("scanapi.tree.request_node.SpecEvaluator.evaluate") + mock_func = mocker.patch( + "scanapi.tree.request_node.SpecEvaluator.evaluate" + ) mock_func.return_value = "" return mock_func @@ -27,7 +29,9 @@ def test_missing_required_keys(self): endpoint=EndpointNode({"name": "foo", "requests": [{}]}), ) - assert str(excinfo.value) == "Missing 'name' key(s) at 'request' scope" + assert ( + str(excinfo.value) == "Missing 'name' key(s) at 'request' scope" + ) class TestHTTPMethod: def test_when_request_has_method(self): @@ -69,7 +73,9 @@ def test_when_request_has_name(self): @pytest.mark.skip("it should validate mandatory `name` key before") def test_when_request_has_no_name(self): with pytest.raises(MissingMandatoryKeyError) as excinfo: - RequestNode({}, endpoint=EndpointNode({"name": "foo", "requests": []})) + RequestNode( + {}, endpoint=EndpointNode({"name": "foo", "requests": []}) + ) assert str(excinfo.value) == "Missing name, path at 'request'" @@ -78,7 +84,9 @@ def test_when_endpoint_has_no_url(self): path = "http://foo.com" request = RequestNode( {"name": "foo", "path": path}, - endpoint=EndpointNode({"name": "foo", "requests": [{}], "path": ""}), + endpoint=EndpointNode( + {"name": "foo", "requests": [{}], "path": ""} + ), ) assert request.full_url_path == path @@ -87,28 +95,36 @@ def test_when_endpoint_has_url(self): endpoint = EndpointNode( {"name": "foo", "requests": [{}], "path": endpoint_path} ) - request = RequestNode({"path": "/foo", "name": "foo"}, endpoint=endpoint) + request = RequestNode( + {"path": "/foo", "name": "foo"}, endpoint=endpoint + ) assert request.full_url_path == "http://foo.com/api/foo" def test_with_trailing_slashes(self): endpoint = EndpointNode( {"name": "foo", "requests": [{}], "path": "http://foo.com/"} ) - request = RequestNode({"name": "foo", "path": "/foo/"}, endpoint=endpoint) + request = RequestNode( + {"name": "foo", "path": "/foo/"}, endpoint=endpoint + ) assert request.full_url_path == "http://foo.com/foo/" def test_with_trailintest_with_path_not_stringg_slashes(self): endpoint = EndpointNode( {"name": "foo", "requests": [{}], "path": "http://foo.com/"} ) - request = RequestNode({"name": "foo", "path": []}, endpoint=endpoint) + request = RequestNode( + {"name": "foo", "path": []}, endpoint=endpoint + ) assert request.full_url_path == "http://foo.com/[]" def test_calls_evaluate(self, mocker, mock_evaluate): endpoint = EndpointNode( {"name": "foo", "requests": [{}], "path": "http://foo.com/"} ) - request = RequestNode({"path": "/foo/", "name": "foo"}, endpoint=endpoint) + request = RequestNode( + {"path": "/foo/", "name": "foo"}, endpoint=endpoint + ) request.full_url_path calls = [mocker.call("http://foo.com/"), mocker.call("/foo/")] @@ -296,7 +312,9 @@ def mock_session(self, mocker): @pytest.fixture def mock_run_tests(self, mocker): - return mocker.patch("scanapi.tree.request_node.RequestNode._run_tests") + return mocker.patch( + "scanapi.tree.request_node.RequestNode._run_tests" + ) @pytest.fixture def mock_time_sleep(self, mocker): @@ -305,7 +323,9 @@ def mock_time_sleep(self, mocker): def test_calls_request(self, mock_session, mock_time_sleep): request = RequestNode( {"path": "http://foo.com", "name": "foo"}, - endpoint=EndpointNode({"name": "foo", "requests": [{}], "delay": 1}), + endpoint=EndpointNode( + {"name": "foo", "requests": [{}], "delay": 1} + ), ) result = request.run() @@ -327,14 +347,8 @@ def test_calls_request(self, mock_session, mock_time_sleep): } test_data = [ - ( - [{"status": "passed"}, {"status": "failed"}], - False, - ), - ( - [{"status": "passed"}, {"status": "passed"}], - True, - ), + ([{"status": "passed"}, {"status": "failed"}], False,), + ([{"status": "passed"}, {"status": "passed"}], True,), ] @pytest.mark.parametrize("test_results, expected_no_failure", test_data) diff --git a/tests/unit/tree/test_testing_node.py b/tests/unit/tree/test_testing_node.py index 6ca0ea43..d9a16520 100644 --- a/tests/unit/tree/test_testing_node.py +++ b/tests/unit/tree/test_testing_node.py @@ -19,13 +19,16 @@ def test_missing_required_keys(self): TestingNode(spec={}, request=request_node) assert ( - str(excinfo.value) == "Missing 'assert', 'name' key(s) at 'test' scope" + str(excinfo.value) + == "Missing 'assert', 'name' key(s) at 'test' scope" ) class TestFullName: def test_full_name(self): endpoint_node = EndpointNode({"name": "foo"}) - request_node = RequestNode(spec={"name": "bar"}, endpoint=endpoint_node) + request_node = RequestNode( + spec={"name": "bar"}, endpoint=endpoint_node + ) test_node = TestingNode( spec={"name": "lol", "assert": "okay"}, request=request_node ) @@ -36,7 +39,9 @@ class TestRun: @pytest.fixture def testing_node(self): endpoint_node = EndpointNode(spec={"name": "foo"}) - request_node = RequestNode(spec={"name": "bar"}, endpoint=endpoint_node) + request_node = RequestNode( + spec={"name": "bar"}, endpoint=endpoint_node + ) spec = { "name": "status_is_200", "assert": "${{ response.status_code == 200 }}", @@ -51,17 +56,19 @@ def mock_evaluate(self, mocker): @pytest.fixture def mock_increment_successes(self, mocker): - return mocker.patch("scanapi.tree.testing_node.session.increment_successes") + return mocker.patch( + "scanapi.tree.testing_node.session.increment_successes" + ) @pytest.fixture def mock_increment_failures(self, mocker): - return mocker.patch("scanapi.tree.testing_node.session.increment_failures") + return mocker.patch( + "scanapi.tree.testing_node.session.increment_failures" + ) class TestWhenTestPassed: def test_build_result( - self, - mock_evaluate, - testing_node, + self, mock_evaluate, testing_node, ): mock_evaluate.return_value = (True, None) @@ -86,7 +93,9 @@ def test_increment_successes( assert mock_increment_successes.call_count == 1 assert not mock_increment_failures.called - def test_logs_test_results(self, mock_evaluate, caplog, testing_node): + def test_logs_test_results( + self, mock_evaluate, caplog, testing_node + ): mock_evaluate.return_value = (True, None) with caplog.at_level(logging.DEBUG): @@ -95,9 +104,7 @@ def test_logs_test_results(self, mock_evaluate, caplog, testing_node): class TestWhenTestFailed: def test_build_result( - self, - mock_evaluate, - testing_node, + self, mock_evaluate, testing_node, ): mock_evaluate.return_value = ( False, @@ -128,7 +135,9 @@ def test_increment_failures( assert mock_increment_failures.call_count == 1 assert not mock_increment_successes.called - def test_logs_test_results(self, mock_evaluate, caplog, testing_node): + def test_logs_test_results( + self, mock_evaluate, caplog, testing_node + ): mock_evaluate.return_value = ( False, "response.status_code == 200",