From f3db04976d7bb9851278152658bb593426d81471 Mon Sep 17 00:00:00 2001 From: James Neyer Date: Mon, 24 Feb 2020 16:17:28 -0500 Subject: [PATCH 1/4] Add count and ordering to json_asserter and non-vnd error reports --- .../test_utils/json_asserter.py | 187 +++++++++----- tests/test_json_asserter.py | 237 +++++++++++++++--- 2 files changed, 327 insertions(+), 97 deletions(-) diff --git a/src/shipchain_common/test_utils/json_asserter.py b/src/shipchain_common/test_utils/json_asserter.py index a05ea13..50ef690 100644 --- a/src/shipchain_common/test_utils/json_asserter.py +++ b/src/shipchain_common/test_utils/json_asserter.py @@ -52,6 +52,15 @@ def response_has_error(response, error, pointer=None): assert False, f'Error `{error}` not found in {response_json}' +def response_has_json_error(response, error): + if error is not None: + response_json = response.json() + assert 'detail' in response_json, f'Malformed error response: {response_json}' + assert isinstance(response_json, dict), f'Error response not a dict: {response_json}' + + assert response_json['detail'] == error, f'Error {error} not found in {response_json["detail"]}' + + def _vnd_assert_attributes(response_data, attributes): """ Scan response data for all attributes @@ -198,78 +207,114 @@ def _plain_assert_attributes_in_list(response_list, attributes): assert found_include, f'{attributes} NOT IN {response_list}' -def response_has_data(response, vnd=True, entity_refs=None, included=None, is_list=False, - resource=None, pk=None, attributes=None, relationships=None): - response = response.json() +def _test_vnd_json(response, entity_refs=None, included=None, is_list=False, count=None, resource=None, pk=None, + attributes=None, relationships=None, check_ordering=False): + assert 'data' in response, f'response does not contain `data` property: {response}' - # application/vnd.api+json - if vnd: - assert 'data' in response, f'response does not contain `data` property: {response}' - - # if (attributes or relationships or resource or pk) and entity_refs: - assert not ((attributes or relationships or resource or pk) and entity_refs), \ - 'Use Only `entity_refs` or explicit `attributes`, `relationships`, `resource`, and `pk` but not both' + # if (attributes or relationships or resource or pk) and entity_refs: + assert not ((attributes or relationships or resource or pk) and entity_refs), \ + 'Use Only `entity_refs` or explicit `attributes`, `relationships`, `resource`, and `pk` but not both' - if (attributes or relationships or resource or pk) and not entity_refs: - entity_refs = EntityReferenceClass(resource=resource, - pk=pk, - attributes=attributes, - relationships=relationships) + if (attributes or relationships or resource or pk) and not entity_refs: + entity_refs = EntityReferenceClass(resource=resource, + pk=pk, + attributes=attributes, + relationships=relationships) - response_data = response['data'] + response_data = response['data'] - if is_list: - assert isinstance(response_data, list), f'Response should be a list' + if is_list: + assert isinstance(response_data, list), f'Response should be a list' - # Included resources are outside of the list response - if included: - _vnd_assert_include(response, included) + # Included resources are outside of the list response + if included: + _vnd_assert_include(response, included) - # Assertion for only included and not entities is valid - if entity_refs: - if not isinstance(entity_refs, list): - entity_refs = [entity_refs] + # Assertion for only included and not entities is valid + if entity_refs: + if not isinstance(entity_refs, list): + entity_refs = [entity_refs] + if not check_ordering: for entity_ref in entity_refs: _vnd_assert_entity_ref_in_list(response_data, entity_ref) + else: + assert len(entity_refs) <= len(response_data), \ + f'Error: more entity refs supplied than available in response data. ' \ + f'{len(response_data)} found asserted {len(entity_refs)}' + for iteration, entity_ref in enumerate(entity_refs): + _vnd_assertions(response_data[iteration], entity_ref) - else: - assert not isinstance(response_data, list), f'Response should not be a list' - assert not (entity_refs and isinstance(entity_refs, list)), \ - f'entity_refs should not be a list for a non-list response' + if not (count is None): + assert len(response_data) == count, \ + f'Difference in count of response_data, got {len(response_data)} expected {count}' + + else: + assert not isinstance(response_data, list), f'Response should not be a list' + assert not (entity_refs and isinstance(entity_refs, list)), \ + f'entity_refs should not be a list for a non-list response' - # Included resources are outside of the list response - if included: - _vnd_assert_include(response, included) + assert (count is None), 'Count is only checked when response is list' + assert not check_ordering, 'Ordering is only checked when response is list' - # Assertion for only status is valid - if entity_refs: - _vnd_assertions(response_data, entity_refs) + # Included resources are outside of the list response + if included: + _vnd_assert_include(response, included) - # application/json - else: - assert not relationships, f'relationships not valid when vnd=False' - assert not entity_refs, f'entity_refs not valid when vnd=False' - assert not included, f'included not valid when vnd=False' - assert attributes, f'attributes must be provided when vnd=False' + # Assertion for only status is valid + if entity_refs: + _vnd_assertions(response_data, entity_refs) - if is_list: - assert isinstance(response, list), f'Response should be a list' - if not isinstance(attributes, list): - attributes = [attributes] +def _test_regular_json(response, entity_refs=None, included=None, is_list=False, count=None, attributes=None, + relationships=None, check_ordering=False): + assert not relationships, f'relationships not valid when vnd=False' + assert not entity_refs, f'entity_refs not valid when vnd=False' + assert not included, f'included not valid when vnd=False' + assert attributes, f'attributes must be provided when vnd=False' + if is_list: + assert isinstance(response, list), f'Response should be a list' + + if not isinstance(attributes, list): + attributes = [attributes] + + if not check_ordering: for attribute in attributes: _plain_assert_attributes_in_list(response, attribute) + else: - assert not isinstance(response, list), f'Response should not be a list' - assert not (attributes and isinstance(attributes, list)), \ - f'attributes should not be a list for a non-list response' + assert len(attributes) <= len(response), \ + f'Error: more attributes supplied than available in response. ' \ + f'{len(attributes)} found asserted {len(response)}' + for iteration, attribute in enumerate(attributes): + _plain_assert_attributes_in_response(response[iteration], attribute) + if not (count is None): + assert len(response) == count,\ + f'Difference in count of response_data, got {len(response)} expected {count}' + else: + assert not isinstance(response, list), f'Response should not be a list' + assert not (attributes and isinstance(attributes, list)), \ + f'attributes should not be a list for a non-list response' + + _plain_assert_attributes_in_response(response, attributes) - _plain_assert_attributes_in_response(response, attributes) +def response_has_data(response, vnd=True, entity_refs=None, included=None, is_list=False, count=None, + resource=None, pk=None, attributes=None, relationships=None, check_ordering=False): + response = response.json() -def assert_200(response, vnd=True, entity_refs=None, included=None, is_list=False, + # application/vnd.api+json + if vnd: + _test_vnd_json(response, entity_refs, included, is_list, count, resource, pk, attributes, relationships, + check_ordering) + + # application/json + else: + _test_regular_json(response, entity_refs, included, is_list, count, attributes, relationships, check_ordering) + + +def assert_200(response, vnd=True, entity_refs=None, included=None, is_list=False, count=None, check_ordering=False, resource=None, pk=None, attributes=None, relationships=None): assert response is not None assert response.status_code == status.HTTP_200_OK, f'status_code {response.status_code} != 200' @@ -281,7 +326,9 @@ def assert_200(response, vnd=True, entity_refs=None, included=None, is_list=Fals vnd=vnd, resource=resource, pk=pk, - entity_refs=entity_refs) + entity_refs=entity_refs, + count=count, + check_ordering=check_ordering) def assert_201(response, vnd=True, entity_refs=None, included=None, is_list=False, @@ -319,28 +366,49 @@ def assert_204(response): assert response.status_code == status.HTTP_204_NO_CONTENT, f'status_code {response.status_code} != 204' -def assert_400(response, error=None, pointer=None): +def assert_400(response, error=None, pointer=None, vnd=True): assert response is not None assert response.status_code == status.HTTP_400_BAD_REQUEST, f'status_code {response.status_code} != 400' - response_has_error(response, error, pointer) + if vnd: + response_has_error(response, error, pointer) + else: + response_has_json_error(response, error) -def assert_401(response, error='Authentication credentials were not provided'): +def assert_401(response, error='Authentication credentials were not provided', vnd=True): assert response is not None assert response.status_code == status.HTTP_401_UNAUTHORIZED, f'status_code {response.status_code} != 401' - response_has_error(response, error) + if vnd: + response_has_error(response, error) + else: + response_has_json_error(response, error) -def assert_403(response, error='You do not have permission to perform this action'): +def assert_403(response, error='You do not have permission to perform this action', vnd=True): assert response is not None assert response.status_code == status.HTTP_403_FORBIDDEN, f'status_code {response.status_code} != 403' - response_has_error(response, error) + if vnd: + response_has_error(response, error) + else: + response_has_json_error(response, error) -def assert_404(response, error='Not found', pointer=None): +def assert_404(response, error='Not found', pointer=None, vnd=True): assert response is not None assert response.status_code == status.HTTP_404_NOT_FOUND, f'status_code {response.status_code} != 404' - response_has_error(response, error, pointer) + if vnd: + response_has_error(response, error, pointer) + else: + response_has_json_error(response, error) + + +def assert_405(response, error='Method not allowed', pointer=None, vnd=True): + assert response is not None + assert response.status_code == status.HTTP_405_METHOD_NOT_ALLOWED, f'status_code {response.status_code} != 405' + if vnd: + response_has_error(response, error, pointer) + else: + response_has_json_error(response, error) def assert_500(response, error='A server error occurred.', pointer=None): @@ -367,6 +435,7 @@ class AssertionHelper: HTTP_401 = assert_401 HTTP_403 = assert_403 HTTP_404 = assert_404 + HTTP_405 = assert_405 HTTP_500 = assert_500 HTTP_503 = assert_503 diff --git a/tests/test_json_asserter.py b/tests/test_json_asserter.py index bd85e67..b375a59 100644 --- a/tests/test_json_asserter.py +++ b/tests/test_json_asserter.py @@ -1,7 +1,6 @@ from unittest.mock import Mock import pytest - from rest_framework import status from shipchain_common.test_utils import AssertionHelper, JsonAsserterMixin @@ -196,6 +195,36 @@ def vnd_error_400(vnd_error): return vnd_error +@pytest.fixture +def json_error(): + return { + 'detail': 'Error detail' + } + + +@pytest.fixture +def entity_ref_1(json_asserter): + return json_asserter.EntityRef( + resource=EXAMPLE_RESOURCE['type'], + pk=EXAMPLE_RESOURCE['id'], + attributes=EXAMPLE_RESOURCE['attributes'], + relationships={'owner': json_asserter.EntityRef( + resource=EXAMPLE_USER['type'], + pk=EXAMPLE_USER['id'], + )}) + + +@pytest.fixture +def entity_ref_3(json_asserter): + return json_asserter.EntityRef( + resource=EXAMPLE_RESOURCE_3['type'], + pk=EXAMPLE_RESOURCE_3['id'], + attributes=EXAMPLE_RESOURCE_3['attributes'], + relationships={'owner': json_asserter.EntityRef( + resource=EXAMPLE_USER['type'], + pk=EXAMPLE_USER['id'], + )}) + class TestAssertionHelper: @pytest.fixture(scope='session') @@ -223,6 +252,11 @@ def vnd_error_404(self, vnd_error): vnd_error['errors'][0]['detail'] = 'Not found' return vnd_error + @pytest.fixture + def vnd_error_405(self, vnd_error): + vnd_error['errors'][0]['detail'] = 'Method not allowed' + return vnd_error + def test_status_200(self, json_asserter, vnd_single, vnd_error_400): response = self.build_response(vnd_single) json_asserter.HTTP_200(response) @@ -279,6 +313,20 @@ def test_status_400_custom_pointer(self, json_asserter, vnd_error_400): response = self.build_response(vnd_error_400, status_code=status.HTTP_400_BAD_REQUEST) json_asserter.HTTP_400(response, error='custom error message', pointer='pointer') + def test_status_400_json(self, json_asserter, vnd_single, json_error): + response = self.build_response(json_error, status_code=status.HTTP_400_BAD_REQUEST) + json_asserter.HTTP_400(response, error=json_error['detail'], vnd=False) + + with pytest.raises(AssertionError) as err: + response = self.build_response(json_error, status_code=status.HTTP_200_OK) + json_asserter.HTTP_400(response, error='Different error', vnd=False) + assert 'status_code 200 != 400' in str(err.value) + + with pytest.raises(AssertionError) as err: + response = self.build_response(json_error, status_code=status.HTTP_400_BAD_REQUEST) + json_asserter.HTTP_400(response, error='Different error', vnd=False) + assert f'Error Different error not found in {json_error["detail"]}' in str(err.value) + def test_status_401(self, json_asserter, vnd_single, vnd_error_401): response = self.build_response(vnd_error_401, status_code=status.HTTP_401_UNAUTHORIZED) json_asserter.HTTP_401(response) @@ -288,6 +336,20 @@ def test_status_401(self, json_asserter, vnd_single, vnd_error_401): json_asserter.HTTP_401(response) assert 'status_code 200 != 401' in str(err.value) + def test_status_401_json(self, json_asserter, vnd_single, json_error): + response = self.build_response(json_error, status_code=status.HTTP_401_UNAUTHORIZED) + json_asserter.HTTP_401(response, error=json_error['detail'], vnd=False) + + with pytest.raises(AssertionError) as err: + response = self.build_response(json_error, status_code=status.HTTP_200_OK) + json_asserter.HTTP_401(response, error='Different error', vnd=False) + assert 'status_code 200 != 401' in str(err.value) + + with pytest.raises(AssertionError) as err: + response = self.build_response(json_error, status_code=status.HTTP_401_UNAUTHORIZED) + json_asserter.HTTP_401(response, error='Different error', vnd=False) + assert f'Error Different error not found in {json_error["detail"]}' in str(err.value) + def test_status_403(self, json_asserter, vnd_single, vnd_error_403): response = self.build_response(vnd_error_403, status_code=status.HTTP_403_FORBIDDEN) json_asserter.HTTP_403(response) @@ -297,6 +359,20 @@ def test_status_403(self, json_asserter, vnd_single, vnd_error_403): json_asserter.HTTP_403(response) assert 'status_code 200 != 403' in str(err.value) + def test_status_403_json(self, json_asserter, vnd_single, json_error): + response = self.build_response(json_error, status_code=status.HTTP_403_FORBIDDEN) + json_asserter.HTTP_403(response, error=json_error['detail'], vnd=False) + + with pytest.raises(AssertionError) as err: + response = self.build_response(json_error, status_code=status.HTTP_200_OK) + json_asserter.HTTP_403(response, error='Different error', vnd=False) + assert 'status_code 200 != 403' in str(err.value) + + with pytest.raises(AssertionError) as err: + response = self.build_response(json_error, status_code=status.HTTP_403_FORBIDDEN) + json_asserter.HTTP_403(response, error='Different error', vnd=False) + assert f'Error Different error not found in {json_error["detail"]}' in str(err.value) + def test_status_404(self, json_asserter, vnd_single, vnd_error_404): response = self.build_response(vnd_error_404, status_code=status.HTTP_404_NOT_FOUND) json_asserter.HTTP_404(response) @@ -306,6 +382,43 @@ def test_status_404(self, json_asserter, vnd_single, vnd_error_404): json_asserter.HTTP_404(response) assert 'status_code 200 != 404' in str(err.value) + def test_status_404_json(self, json_asserter, vnd_single, json_error): + response = self.build_response(json_error, status_code=status.HTTP_404_NOT_FOUND) + json_asserter.HTTP_404(response, error=json_error['detail'], vnd=False) + + with pytest.raises(AssertionError) as err: + response = self.build_response(json_error, status_code=status.HTTP_200_OK) + json_asserter.HTTP_404(response, error='Different error', vnd=False) + assert 'status_code 200 != 404' in str(err.value) + + with pytest.raises(AssertionError) as err: + response = self.build_response(json_error, status_code=status.HTTP_404_NOT_FOUND) + json_asserter.HTTP_404(response, error='Different error', vnd=False) + assert f'Error Different error not found in {json_error["detail"]}' in str(err.value) + + def test_status_405(self, json_asserter, vnd_single, vnd_error_405): + response = self.build_response(vnd_error_405, status_code=status.HTTP_405_METHOD_NOT_ALLOWED) + json_asserter.HTTP_405(response) + + with pytest.raises(AssertionError) as err: + response = self.build_response(vnd_single) + json_asserter.HTTP_405(response) + assert 'status_code 200 != 405' in str(err.value) + + def test_status_405_json(self, json_asserter, vnd_single, json_error): + response = self.build_response(json_error, status_code=status.HTTP_405_METHOD_NOT_ALLOWED) + json_asserter.HTTP_405(response, error=json_error['detail'], vnd=False) + + with pytest.raises(AssertionError) as err: + response = self.build_response(json_error, status_code=status.HTTP_200_OK) + json_asserter.HTTP_405(response, error='Different error', vnd=False) + assert 'status_code 200 != 405' in str(err.value) + + with pytest.raises(AssertionError) as err: + response = self.build_response(json_error, status_code=status.HTTP_405_METHOD_NOT_ALLOWED) + json_asserter.HTTP_405(response, error='Different error', vnd=False) + assert f'Error Different error not found in {json_error["detail"]}' in str(err.value) + def test_status_500(self, json_asserter, vnd_single, vnd_error): vnd_error['errors'][0]['detail'] = 'A server error occurred.' response = self.build_response(vnd_error, status_code=status.HTTP_500_INTERNAL_SERVER_ERROR) @@ -761,48 +874,57 @@ def test_vnd_list_entity_full_match(self, json_asserter, vnd_list): )} )) - def test_vnd_list_entity_list_all_match(self, json_asserter, vnd_list): + def test_vnd_list_entity_list_all_match(self, json_asserter, vnd_list, entity_ref_1, entity_ref_3): response = self.build_response(vnd_list) - entity_1 = json_asserter.EntityRef( - resource=EXAMPLE_RESOURCE['type'], - pk=EXAMPLE_RESOURCE['id'], - attributes=EXAMPLE_RESOURCE['attributes'], - relationships={'owner': json_asserter.EntityRef( - resource=EXAMPLE_USER['type'], - pk=EXAMPLE_USER['id'], - )}) - entity_2 = json_asserter.EntityRef( - resource=EXAMPLE_RESOURCE_3['type'], - pk=EXAMPLE_RESOURCE_3['id'], - attributes=EXAMPLE_RESOURCE_3['attributes'], - relationships={'owner': json_asserter.EntityRef( - resource=EXAMPLE_USER['type'], - pk=EXAMPLE_USER['id'], - )}) - json_asserter.HTTP_200(response, is_list=True, entity_refs=[entity_1, entity_2]) + json_asserter.HTTP_200(response, is_list=True, entity_refs=[entity_ref_1, entity_ref_3]) - def test_vnd_list_entity_list_one_not_match(self, json_asserter, vnd_list): + def test_vnd_list_count(self, json_asserter, vnd_list): response = self.build_response(vnd_list) - entity_1 = json_asserter.EntityRef( - resource=EXAMPLE_RESOURCE['type'], - pk=EXAMPLE_RESOURCE['id'], - attributes=EXAMPLE_RESOURCE['attributes'], - relationships={'owner': json_asserter.EntityRef( - resource=EXAMPLE_USER['type'], - pk=EXAMPLE_USER['id'], - )}) - entity_2 = json_asserter.EntityRef( - resource=EXAMPLE_RESOURCE_3['type'], - pk=EXAMPLE_RESOURCE_2['id'], - attributes=EXAMPLE_RESOURCE_3['attributes'], - relationships={'owner': json_asserter.EntityRef( - resource=EXAMPLE_USER['type'], - pk=EXAMPLE_USER['id'], - )}) + json_asserter.HTTP_200(response, is_list=True, count=len(vnd_list['data'])) + + def test_vnd_list_wrong_count(self, json_asserter, vnd_list): + list_length = len(vnd_list['data']) + response = self.build_response(vnd_list) + with pytest.raises(AssertionError) as err: + json_asserter.HTTP_200(response, is_list=True, count=list_length - 1) + assert f'Difference in count of response_data, got {list_length} expected {list_length - 1}' in str(err.value) + + def test_vnd_single_count(self, json_asserter, vnd_single): + response = self.build_response(vnd_single) + with pytest.raises(AssertionError) as err: + json_asserter.HTTP_200(response, count=1) + assert f'Count is only checked when response is list' in str(err.value) + + def test_vnd_list_ordering(self, json_asserter, vnd_list, entity_ref_1, entity_ref_3): + response = self.build_response(vnd_list) + json_asserter.HTTP_200(response, is_list=True, entity_refs=[entity_ref_1, entity_ref_3], check_ordering=True) + + def test_vnd_list_wrong_ordering(self, json_asserter, vnd_list, entity_ref_1, entity_ref_3): + response = self.build_response(vnd_list) + with pytest.raises(AssertionError) as err: + json_asserter.HTTP_200(response, is_list=True, entity_refs=[entity_ref_3, entity_ref_1], check_ordering=True) + assert 'Invalid ID in ' in str(err.value) + + def test_vnd_list_wrong_ordering_amount(self, json_asserter, vnd_list, entity_ref_1, entity_ref_3): + response = self.build_response(vnd_list) + with pytest.raises(AssertionError) as err: + json_asserter.HTTP_200(response, is_list=True, entity_refs=[entity_ref_1, entity_ref_3, entity_ref_1], + check_ordering=True) + assert 'Error: more entity refs supplied than available in response data. ' in str(err.value) + def test_vnd_single_ordering(self, json_asserter, vnd_single, entity_ref_1): + response = self.build_response(vnd_single) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, is_list=True, entity_refs=[entity_1, entity_2]) - assert f'{entity_2} NOT IN' in str(err.value) + json_asserter.HTTP_200(response, entity_refs=entity_ref_1, check_ordering=True) + assert f'Ordering is only checked when response is list' in str(err.value) + + def test_vnd_list_entity_list_one_not_match(self, json_asserter, vnd_list, entity_ref_1, entity_ref_3): + response = self.build_response(vnd_list) + entity_ref_3.pk = EXAMPLE_RESOURCE_2['id'] + + with pytest.raises(AssertionError) as err: + json_asserter.HTTP_200(response, is_list=True, entity_refs=[entity_ref_1, entity_ref_3]) + assert f'{entity_ref_3} NOT IN' in str(err.value) def test_plain_json_valid_parameters(self, json_asserter): response = self.build_response(EXAMPLE_PLAIN) @@ -899,6 +1021,28 @@ def test_plain_json_attributes_list_one_missing(self, json_asserter): json_asserter.HTTP_200(response, vnd=False, is_list=True, attributes=[EXAMPLE_PLAIN, EXAMPLE_PLAIN_3]) assert f'{EXAMPLE_PLAIN_3} NOT IN ' in str(err.value) + def test_plain_json_attributes_list_ordering(self, json_asserter): + response = self.build_response([EXAMPLE_PLAIN, EXAMPLE_PLAIN_2]) + + json_asserter.HTTP_200(response, vnd=False, is_list=True, attributes=[EXAMPLE_PLAIN, EXAMPLE_PLAIN_2], + check_ordering=True) + + def test_plain_json_attributes_list_wrong_ordering(self, json_asserter): + response = self.build_response([EXAMPLE_PLAIN, EXAMPLE_PLAIN_2]) + + with pytest.raises(AssertionError) as err: + json_asserter.HTTP_200(response, vnd=False, is_list=True, attributes=[EXAMPLE_PLAIN_2, EXAMPLE_PLAIN], + check_ordering=True) + assert f'Attribute Value incorrect ' in str(err.value) + + def test_plain_json_attributes_list_wrong_ordering_size(self, json_asserter): + response = self.build_response([EXAMPLE_PLAIN, EXAMPLE_PLAIN_2]) + + with pytest.raises(AssertionError) as err: + json_asserter.HTTP_200(response, vnd=False, is_list=True, check_ordering=True, + attributes=[EXAMPLE_PLAIN, EXAMPLE_PLAIN_2, EXAMPLE_PLAIN]) + assert 'Error: more attributes supplied than available in response. 3 found asserted 2' in str(err.value) + def test_plain_json_attributes_list_nested_missing(self, json_asserter): response = self.build_response([EXAMPLE_PLAIN, EXAMPLE_PLAIN_2]) @@ -921,6 +1065,23 @@ def test_plain_json_attributes_list_nested_mismatch(self, json_asserter): json_asserter.HTTP_200(response, vnd=False, is_list=True, attributes=invalid_attributes) assert f'{invalid_attributes} NOT IN ' in str(err.value) + def test_plain_json_list_count(self, json_asserter): + response = self.build_response([EXAMPLE_PLAIN, EXAMPLE_PLAIN_2]) + json_asserter.HTTP_200(response, vnd=False, is_list=True, count=2, attributes=[EXAMPLE_PLAIN, EXAMPLE_PLAIN_2]) + + def test_plain_json_list_wrong_count(self, json_asserter): + response = self.build_response([EXAMPLE_PLAIN, EXAMPLE_PLAIN_2]) + with pytest.raises(AssertionError) as err: + json_asserter.HTTP_200(response, vnd=False, attributes=[EXAMPLE_PLAIN, EXAMPLE_PLAIN_2], is_list=True, + count=1) + assert 'Difference in count of response_data, got 2 expected 1' in str(err.value) + + def test_plain_json_single_count(self, json_asserter, vnd_single): + response = self.build_response(vnd_single) + with pytest.raises(AssertionError) as err: + json_asserter.HTTP_200(response, count=1) + assert f'Count is only checked when response is list' in str(err.value) + class TestJsonAsserterMixin(JsonAsserterMixin): def test_has_asserter(self): From 6992e6d0d109a9f59f99445493f16bdc1dbde0bc Mon Sep 17 00:00:00 2001 From: James Neyer Date: Mon, 2 Mar 2020 09:04:34 -0500 Subject: [PATCH 2/4] Change how response errors are checked --- .../test_utils/json_asserter.py | 77 +++++++++---------- tests/test_json_asserter.py | 10 +-- 2 files changed, 41 insertions(+), 46 deletions(-) diff --git a/src/shipchain_common/test_utils/json_asserter.py b/src/shipchain_common/test_utils/json_asserter.py index 50ef690..d710a4b 100644 --- a/src/shipchain_common/test_utils/json_asserter.py +++ b/src/shipchain_common/test_utils/json_asserter.py @@ -33,32 +33,42 @@ def __str__(self): f'attributes: {self.attributes}; relationships: {self.relationships}' -def response_has_error(response, error, pointer=None): - if error is not None: - response_json = response.json() - assert 'errors' in response_json, f'Malformed error response: {response_json}' - assert isinstance(response_json['errors'], list), f'Error response not a list: {response_json}' +def _vnd_has_error(response_json, error, pointer=None): + assert 'errors' in response_json, f'Malformed error response: {response_json}' + errors = response_json['errors'] + assert isinstance(errors, list), f'Error response not a list: {errors}' + error_found = False - error_found = False + for single_error in errors: + if error in single_error['detail']: + error_found = True + if pointer: + found_pointer = single_error['source']['pointer'] + assert pointer in found_pointer, f'Error `{pointer}` not found in {found_pointer}' - for single_error in response_json['errors']: - if error in single_error['detail']: - error_found = True - if pointer: - found_pointer = single_error['source']['pointer'] - assert pointer in found_pointer, f'Error `{pointer}` not found in {found_pointer}' + if not error_found: + assert False, f'Error `{error}` not found in {errors}' - if not error_found: - assert False, f'Error `{error}` not found in {response_json}' +def _json_has_error(errors, error): + assert isinstance(errors, dict), f'Error response not a dict: {errors}' -def response_has_json_error(response, error): - if error is not None: - response_json = response.json() - assert 'detail' in response_json, f'Malformed error response: {response_json}' - assert isinstance(response_json, dict), f'Error response not a dict: {response_json}' + assert errors['detail'] == error, f'Error {error} not found in {errors}' - assert response_json['detail'] == error, f'Error {error} not found in {response_json["detail"]}' + +def response_has_error(response, error, pointer=None, vnd=True): + if error is None: + return + + response_json = response.json() + + # application/vnd.api+json + if vnd: + _vnd_has_error(response_json, error, pointer) + + # application/json + else: + _json_has_error(response_json, error) def _vnd_assert_attributes(response_data, attributes): @@ -245,7 +255,7 @@ def _test_vnd_json(response, entity_refs=None, included=None, is_list=False, cou for iteration, entity_ref in enumerate(entity_refs): _vnd_assertions(response_data[iteration], entity_ref) - if not (count is None): + if count is not None: assert len(response_data) == count, \ f'Difference in count of response_data, got {len(response_data)} expected {count}' @@ -369,46 +379,31 @@ def assert_204(response): def assert_400(response, error=None, pointer=None, vnd=True): assert response is not None assert response.status_code == status.HTTP_400_BAD_REQUEST, f'status_code {response.status_code} != 400' - if vnd: - response_has_error(response, error, pointer) - else: - response_has_json_error(response, error) + response_has_error(response, error, pointer, vnd) def assert_401(response, error='Authentication credentials were not provided', vnd=True): assert response is not None assert response.status_code == status.HTTP_401_UNAUTHORIZED, f'status_code {response.status_code} != 401' - if vnd: - response_has_error(response, error) - else: - response_has_json_error(response, error) + response_has_error(response, error, vnd=vnd) def assert_403(response, error='You do not have permission to perform this action', vnd=True): assert response is not None assert response.status_code == status.HTTP_403_FORBIDDEN, f'status_code {response.status_code} != 403' - if vnd: - response_has_error(response, error) - else: - response_has_json_error(response, error) + response_has_error(response, error, vnd=vnd) def assert_404(response, error='Not found', pointer=None, vnd=True): assert response is not None assert response.status_code == status.HTTP_404_NOT_FOUND, f'status_code {response.status_code} != 404' - if vnd: - response_has_error(response, error, pointer) - else: - response_has_json_error(response, error) + response_has_error(response, error, pointer, vnd) def assert_405(response, error='Method not allowed', pointer=None, vnd=True): assert response is not None assert response.status_code == status.HTTP_405_METHOD_NOT_ALLOWED, f'status_code {response.status_code} != 405' - if vnd: - response_has_error(response, error, pointer) - else: - response_has_json_error(response, error) + response_has_error(response, error, pointer, vnd) def assert_500(response, error='A server error occurred.', pointer=None): diff --git a/tests/test_json_asserter.py b/tests/test_json_asserter.py index b375a59..4817a7b 100644 --- a/tests/test_json_asserter.py +++ b/tests/test_json_asserter.py @@ -325,7 +325,7 @@ def test_status_400_json(self, json_asserter, vnd_single, json_error): with pytest.raises(AssertionError) as err: response = self.build_response(json_error, status_code=status.HTTP_400_BAD_REQUEST) json_asserter.HTTP_400(response, error='Different error', vnd=False) - assert f'Error Different error not found in {json_error["detail"]}' in str(err.value) + assert f'Error Different error not found in {json_error}' in str(err.value) def test_status_401(self, json_asserter, vnd_single, vnd_error_401): response = self.build_response(vnd_error_401, status_code=status.HTTP_401_UNAUTHORIZED) @@ -348,7 +348,7 @@ def test_status_401_json(self, json_asserter, vnd_single, json_error): with pytest.raises(AssertionError) as err: response = self.build_response(json_error, status_code=status.HTTP_401_UNAUTHORIZED) json_asserter.HTTP_401(response, error='Different error', vnd=False) - assert f'Error Different error not found in {json_error["detail"]}' in str(err.value) + assert f'Error Different error not found in {json_error}' in str(err.value) def test_status_403(self, json_asserter, vnd_single, vnd_error_403): response = self.build_response(vnd_error_403, status_code=status.HTTP_403_FORBIDDEN) @@ -371,7 +371,7 @@ def test_status_403_json(self, json_asserter, vnd_single, json_error): with pytest.raises(AssertionError) as err: response = self.build_response(json_error, status_code=status.HTTP_403_FORBIDDEN) json_asserter.HTTP_403(response, error='Different error', vnd=False) - assert f'Error Different error not found in {json_error["detail"]}' in str(err.value) + assert f'Error Different error not found in {json_error}' in str(err.value) def test_status_404(self, json_asserter, vnd_single, vnd_error_404): response = self.build_response(vnd_error_404, status_code=status.HTTP_404_NOT_FOUND) @@ -394,7 +394,7 @@ def test_status_404_json(self, json_asserter, vnd_single, json_error): with pytest.raises(AssertionError) as err: response = self.build_response(json_error, status_code=status.HTTP_404_NOT_FOUND) json_asserter.HTTP_404(response, error='Different error', vnd=False) - assert f'Error Different error not found in {json_error["detail"]}' in str(err.value) + assert f'Error Different error not found in {json_error}' in str(err.value) def test_status_405(self, json_asserter, vnd_single, vnd_error_405): response = self.build_response(vnd_error_405, status_code=status.HTTP_405_METHOD_NOT_ALLOWED) @@ -417,7 +417,7 @@ def test_status_405_json(self, json_asserter, vnd_single, json_error): with pytest.raises(AssertionError) as err: response = self.build_response(json_error, status_code=status.HTTP_405_METHOD_NOT_ALLOWED) json_asserter.HTTP_405(response, error='Different error', vnd=False) - assert f'Error Different error not found in {json_error["detail"]}' in str(err.value) + assert f'Error Different error not found in {json_error}' in str(err.value) def test_status_500(self, json_asserter, vnd_single, vnd_error): vnd_error['errors'][0]['detail'] = 'A server error occurred.' From f0635215e2e57c66282b00c4e9f4d3af3afe8d04 Mon Sep 17 00:00:00 2001 From: James Neyer Date: Mon, 2 Mar 2020 10:38:29 -0500 Subject: [PATCH 3/4] Change count is none check --- src/shipchain_common/test_utils/json_asserter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shipchain_common/test_utils/json_asserter.py b/src/shipchain_common/test_utils/json_asserter.py index d710a4b..7734b19 100644 --- a/src/shipchain_common/test_utils/json_asserter.py +++ b/src/shipchain_common/test_utils/json_asserter.py @@ -299,7 +299,7 @@ def _test_regular_json(response, entity_refs=None, included=None, is_list=False, f'{len(attributes)} found asserted {len(response)}' for iteration, attribute in enumerate(attributes): _plain_assert_attributes_in_response(response[iteration], attribute) - if not (count is None): + if count is not None: assert len(response) == count,\ f'Difference in count of response_data, got {len(response)} expected {count}' else: From 896a0848f207e9bae7ad524c871296749a8231e0 Mon Sep 17 00:00:00 2001 From: James Neyer Date: Tue, 3 Mar 2020 10:10:51 -0500 Subject: [PATCH 4/4] Add detail check for json error check --- src/shipchain_common/test_utils/json_asserter.py | 3 ++- tests/test_json_asserter.py | 10 +++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/shipchain_common/test_utils/json_asserter.py b/src/shipchain_common/test_utils/json_asserter.py index 7734b19..1f7048c 100644 --- a/src/shipchain_common/test_utils/json_asserter.py +++ b/src/shipchain_common/test_utils/json_asserter.py @@ -52,8 +52,9 @@ def _vnd_has_error(response_json, error, pointer=None): def _json_has_error(errors, error): assert isinstance(errors, dict), f'Error response not a dict: {errors}' + assert 'detail' in errors, f'Malformed error response: {errors}' - assert errors['detail'] == error, f'Error {error} not found in {errors}' + assert errors['detail'] == error, f'Error {error} not found in {errors["detail"]}' def response_has_error(response, error, pointer=None, vnd=True): diff --git a/tests/test_json_asserter.py b/tests/test_json_asserter.py index 4817a7b..b375a59 100644 --- a/tests/test_json_asserter.py +++ b/tests/test_json_asserter.py @@ -325,7 +325,7 @@ def test_status_400_json(self, json_asserter, vnd_single, json_error): with pytest.raises(AssertionError) as err: response = self.build_response(json_error, status_code=status.HTTP_400_BAD_REQUEST) json_asserter.HTTP_400(response, error='Different error', vnd=False) - assert f'Error Different error not found in {json_error}' in str(err.value) + assert f'Error Different error not found in {json_error["detail"]}' in str(err.value) def test_status_401(self, json_asserter, vnd_single, vnd_error_401): response = self.build_response(vnd_error_401, status_code=status.HTTP_401_UNAUTHORIZED) @@ -348,7 +348,7 @@ def test_status_401_json(self, json_asserter, vnd_single, json_error): with pytest.raises(AssertionError) as err: response = self.build_response(json_error, status_code=status.HTTP_401_UNAUTHORIZED) json_asserter.HTTP_401(response, error='Different error', vnd=False) - assert f'Error Different error not found in {json_error}' in str(err.value) + assert f'Error Different error not found in {json_error["detail"]}' in str(err.value) def test_status_403(self, json_asserter, vnd_single, vnd_error_403): response = self.build_response(vnd_error_403, status_code=status.HTTP_403_FORBIDDEN) @@ -371,7 +371,7 @@ def test_status_403_json(self, json_asserter, vnd_single, json_error): with pytest.raises(AssertionError) as err: response = self.build_response(json_error, status_code=status.HTTP_403_FORBIDDEN) json_asserter.HTTP_403(response, error='Different error', vnd=False) - assert f'Error Different error not found in {json_error}' in str(err.value) + assert f'Error Different error not found in {json_error["detail"]}' in str(err.value) def test_status_404(self, json_asserter, vnd_single, vnd_error_404): response = self.build_response(vnd_error_404, status_code=status.HTTP_404_NOT_FOUND) @@ -394,7 +394,7 @@ def test_status_404_json(self, json_asserter, vnd_single, json_error): with pytest.raises(AssertionError) as err: response = self.build_response(json_error, status_code=status.HTTP_404_NOT_FOUND) json_asserter.HTTP_404(response, error='Different error', vnd=False) - assert f'Error Different error not found in {json_error}' in str(err.value) + assert f'Error Different error not found in {json_error["detail"]}' in str(err.value) def test_status_405(self, json_asserter, vnd_single, vnd_error_405): response = self.build_response(vnd_error_405, status_code=status.HTTP_405_METHOD_NOT_ALLOWED) @@ -417,7 +417,7 @@ def test_status_405_json(self, json_asserter, vnd_single, json_error): with pytest.raises(AssertionError) as err: response = self.build_response(json_error, status_code=status.HTTP_405_METHOD_NOT_ALLOWED) json_asserter.HTTP_405(response, error='Different error', vnd=False) - assert f'Error Different error not found in {json_error}' in str(err.value) + assert f'Error Different error not found in {json_error["detail"]}' in str(err.value) def test_status_500(self, json_asserter, vnd_single, vnd_error): vnd_error['errors'][0]['detail'] = 'A server error occurred.'