From ee74a94e98bbe79905649ed38af530392df5900c Mon Sep 17 00:00:00 2001 From: Ben Einaudi Date: Sat, 28 Dec 2019 12:54:21 +0100 Subject: [PATCH] Enforce entity attribute check This change enforce type checking for entity attribute in object returned See #56 --- main/cloudfoundry_client/v2/entities.py | 3 +- ...valid_entity_with_invalid_entity_type.json | 9 +++ .../GET_invalid_entity_with_null_entity.json | 9 +++ .../GET_invalid_entity_without_entity.json | 8 +++ test/v2/test_entities.py | 64 +++++++++++++++---- 5 files changed, 81 insertions(+), 12 deletions(-) create mode 100644 test/fixtures/fake/GET_invalid_entity_with_invalid_entity_type.json create mode 100644 test/fixtures/fake/GET_invalid_entity_with_null_entity.json create mode 100644 test/fixtures/fake/GET_invalid_entity_without_entity.json diff --git a/main/cloudfoundry_client/v2/entities.py b/main/cloudfoundry_client/v2/entities.py index 3db4480..cbaf34b 100644 --- a/main/cloudfoundry_client/v2/entities.py +++ b/main/cloudfoundry_client/v2/entities.py @@ -18,7 +18,7 @@ def __init__(self, target_endpoint: str, client: 'CloudFoundryClient', *args, ** self.target_endpoint = target_endpoint self.client = client try: - if 'entity' not in self: + if not (isinstance(self.get('entity'), dict)): raise InvalidEntity(**self) for attribute, value in list(self['entity'].items()): @@ -48,6 +48,7 @@ def __init__(self, target_endpoint: str, client: 'CloudFoundryClient', *args, ** PaginateEntities = Generator[Entity, None, None] + class EntityManager(object): list_query_parameters = ['page', 'results-per-page', 'order-direction'] diff --git a/test/fixtures/fake/GET_invalid_entity_with_invalid_entity_type.json b/test/fixtures/fake/GET_invalid_entity_with_invalid_entity_type.json new file mode 100644 index 0000000..1269121 --- /dev/null +++ b/test/fixtures/fake/GET_invalid_entity_with_invalid_entity_type.json @@ -0,0 +1,9 @@ +{ + "metadata": { + "guid": "any-id", + "url": "/fake/any-id", + "created_at": "2015-11-30T23:38:33Z", + "updated_at": "2015-11-30T23:38:33Z" + }, + "entity": [] +} \ No newline at end of file diff --git a/test/fixtures/fake/GET_invalid_entity_with_null_entity.json b/test/fixtures/fake/GET_invalid_entity_with_null_entity.json new file mode 100644 index 0000000..186e6b9 --- /dev/null +++ b/test/fixtures/fake/GET_invalid_entity_with_null_entity.json @@ -0,0 +1,9 @@ +{ + "metadata": { + "guid": "any-id", + "url": "/fake/any-id", + "created_at": "2015-11-30T23:38:33Z", + "updated_at": "2015-11-30T23:38:33Z" + }, + "entity": null +} \ No newline at end of file diff --git a/test/fixtures/fake/GET_invalid_entity_without_entity.json b/test/fixtures/fake/GET_invalid_entity_without_entity.json new file mode 100644 index 0000000..d977346 --- /dev/null +++ b/test/fixtures/fake/GET_invalid_entity_without_entity.json @@ -0,0 +1,8 @@ +{ + "metadata": { + "guid": "any-id", + "url": "/fake/any-id", + "created_at": "2015-11-30T23:38:33Z", + "updated_at": "2015-11-30T23:38:33Z" + } +} \ No newline at end of file diff --git a/test/v2/test_entities.py b/test/v2/test_entities.py index dce4ce2..612b3e0 100644 --- a/test/v2/test_entities.py +++ b/test/v2/test_entities.py @@ -3,37 +3,79 @@ from http import HTTPStatus from unittest.mock import MagicMock, call +from cloudfoundry_client.errors import InvalidEntity from cloudfoundry_client.v2.entities import EntityManager from fake_requests import TARGET_ENDPOINT, mock_response class TestEntities(unittest.TestCase): + + def test_invalid_entity_without_entity_attribute(self): + client = MagicMock() + entity_manager = EntityManager(TARGET_ENDPOINT, client, '/fake/anyone') + + client.get.return_value = mock_response( + '/fake/anyone/any-id', + HTTPStatus.OK, + None, + 'fake', 'GET_invalid_entity_without_entity.json') + + self.assertRaises(InvalidEntity, lambda: entity_manager['any-id']) + + def test_invalid_entity_with_null_entity(self): + client = MagicMock() + entity_manager = EntityManager(TARGET_ENDPOINT, client, '/fake/anyone') + + client.get.return_value = mock_response( + '/fake/anyone/any-id', + HTTPStatus.OK, + None, + 'fake', 'GET_invalid_entity_with_null_entity.json') + + self.assertRaises(InvalidEntity, lambda: entity_manager['any-id']) + + def test_invalid_entity_with_invalid_entity_type(self): + client = MagicMock() + entity_manager = EntityManager(TARGET_ENDPOINT, client, '/fake/anyone') + + client.get.return_value = mock_response( + '/fake/anyone/any-id', + HTTPStatus.OK, + None, + 'fake', 'GET_invalid_entity_with_invalid_entity_type.json') + + self.assertRaises(InvalidEntity, lambda: entity_manager['any-id']) + def test_query(self): url = EntityManager('http://cf.api', None, '/v2/apps')._get_url_filtered('/v2/apps', **{'results-per-page': 20, - 'order-direction': 'asc', - 'page': 1, - 'space_guid': 'id', - 'order-by': 'id'}) + 'order-direction': 'asc', + 'page': 1, + 'space_guid': 'id', + 'order-by': 'id'}) self.assertEqual('/v2/apps?order-by=id&order-direction=asc&page=1&results-per-page=20&q=space_guid%3Aid', url) def test_query_multi_order_by(self): - url = EntityManager('http://cf.api', None, '/v2/apps')._get_url_filtered('/v2/apps', **{'order-by': ['timestamp', 'id']}) + url = EntityManager('http://cf.api', None, '/v2/apps')._get_url_filtered('/v2/apps', + **{'order-by': ['timestamp', 'id']}) self.assertEqual('/v2/apps?order-by=timestamp&order-by=id', url) def test_query_single_order_by(self): - url = EntityManager('http://cf.api', None, '/v2/apps')._get_url_filtered('/v2/apps', **{'order-by': 'timestamp'}) + url = EntityManager('http://cf.api', None, '/v2/apps')._get_url_filtered('/v2/apps', + **{'order-by': 'timestamp'}) self.assertEqual('/v2/apps?order-by=timestamp', url) def test_query_in(self): url = EntityManager('http://cf.api', None, '/v2/apps')._get_url_filtered('/v2/apps', **{'results-per-page': 20, - 'order-direction': 'asc', - 'page': 1, - 'space_guid': ['id1', 'id2']}) + 'order-direction': 'asc', + 'page': 1, + 'space_guid': ['id1', + 'id2']}) self.assertEqual('/v2/apps?order-direction=asc&page=1&results-per-page=20&q=space_guid%20IN%20id1%2Cid2', url) def test_multi_query(self): - url = EntityManager('http://cf.api', None, '/v2/events')._get_url_filtered('/v2/events', **{'type': ['create', 'update'], - 'organization_guid': 'org-id'}) + url = EntityManager('http://cf.api', None, '/v2/events')._get_url_filtered('/v2/events', + **{'type': ['create', 'update'], + 'organization_guid': 'org-id'}) self.assertEqual('/v2/events?q=organization_guid%3Aorg-id&q=type%20IN%20create%2Cupdate', url) def test_list(self):