diff --git a/designate/objects/adapters/api_v2/recordset.py b/designate/objects/adapters/api_v2/recordset.py index 7324997d1..afb32caeb 100644 --- a/designate/objects/adapters/api_v2/recordset.py +++ b/designate/objects/adapters/api_v2/recordset.py @@ -104,10 +104,9 @@ class RecordSetAPIv2Adapter(base.APIv2Adapter): new_recordset_records = objects.RecordList() # Remove deleted records if we have provided a records array - if record_update: - for record in recordset.records: - if record.data not in records_to_rm: - new_recordset_records.append(record) + for record in recordset.records: + if record.data not in records_to_rm: + new_recordset_records.append(record) # Add new records for record in records_to_add: diff --git a/designate/objects/adapters/api_v2/zone.py b/designate/objects/adapters/api_v2/zone.py index b25ae427f..e2f5ab2e5 100644 --- a/designate/objects/adapters/api_v2/zone.py +++ b/designate/objects/adapters/api_v2/zone.py @@ -77,7 +77,8 @@ class ZoneAPIv2Adapter(base.APIv2Adapter): del values['attributes'] return super(ZoneAPIv2Adapter, cls).parse_object( - values, obj, *args, **kwargs) + values, obj, *args, **kwargs + ) class ZoneListAPIv2Adapter(base.APIv2Adapter): diff --git a/designate/tests/unit/objects/test_adapters.py b/designate/tests/unit/objects/test_adapters.py index c5d30ff8a..39f197eb2 100644 --- a/designate/tests/unit/objects/test_adapters.py +++ b/designate/tests/unit/objects/test_adapters.py @@ -14,7 +14,6 @@ # License for the specific language governing permissions and limitations # under the License. import datetime -from unittest.mock import Mock from oslo_log import log as logging from oslo_utils import timeutils @@ -138,15 +137,3 @@ class DesignateAdapterTest(oslotest.base.BaseTestCase): ), test_obj.created_at ) - - -class RecordSetAPIv2AdapterTest(oslotest.base.BaseTestCase): - def test_get_path(self): - request = Mock() - request.path = '/v2/recordsets' - recordset = Mock() - recordset.zone_id = 'a-b-c-d' - expected_path = '/v2/zones/a-b-c-d/recordsets' - - path = adapters.RecordSetAPIv2Adapter._get_path(request, recordset) - self.assertEqual(expected_path, path) diff --git a/designate/tests/unit/objects/test_adapters_v2_api.py b/designate/tests/unit/objects/test_adapters_v2_api.py new file mode 100644 index 000000000..a86a07f63 --- /dev/null +++ b/designate/tests/unit/objects/test_adapters_v2_api.py @@ -0,0 +1,424 @@ +# Copyright 2014 Hewlett-Packard Development Company, L.P. +# +# Author: Kiall Mac Innes <kiall@hpe.com> +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +from unittest import mock + +from oslo_config import cfg +from oslo_config import fixture as cfg_fixture +from oslo_log import log as logging +import oslotest.base + +from designate import exceptions +from designate import objects +from designate.objects import adapters +from designate.objects.adapters.api_v2 import base + +CONF = cfg.CONF +LOG = logging.getLogger(__name__) + + +class APIv2AdapterTest(oslotest.base.BaseTestCase): + def setUp(self): + super(APIv2AdapterTest, self).setUp() + self.useFixture(cfg_fixture.Config(CONF)) + + def test_get_base_url(self): + CONF.set_override('enable_host_header', False, 'service:api') + + mock_request = mock.Mock() + mock_request.GET = {'foo': 'bar'} + mock_request.host_url = 'http://127.0.0.1' + mock_request.path = '/v2/zones' + + base_url = base.APIv2Adapter._get_base_url(mock_request) + self.assertEqual('http://127.0.0.1:9001', base_url) + + def test_get_base_url_enable_host_header(self): + CONF.set_override('enable_host_header', True, 'service:api') + + mock_request = mock.Mock() + mock_request.GET = {'foo': 'bar'} + mock_request.host_url = 'http://192.0.2.1' + mock_request.path = '/v2/zones' + + base_url = base.APIv2Adapter._get_base_url(mock_request) + self.assertEqual('http://192.0.2.1', base_url) + + def test_get_base_url_enable_host_header_exception_raised(self): + CONF.set_override('enable_host_header', True, 'service:api') + + mock_host_url = mock.PropertyMock(side_effect=Exception) + mock_request = mock.Mock() + mock_request.GET = {'foo': 'bar'} + type(mock_request).host_url = mock_host_url + mock_request.path = '/v2/zones' + + base_url = base.APIv2Adapter._get_base_url(mock_request) + self.assertEqual('http://127.0.0.1:9001', base_url) + + +class RecordAPIv2AdapterTest(oslotest.base.BaseTestCase): + def test_parse_object(self): + values = '192.0.2.1' + + parsed_object = adapters.RecordAPIv2Adapter.parse_object( + values, objects.Record() + ) + + self.assertEqual('192.0.2.1', parsed_object.data) + + def test_render_object(self): + values = '192.0.2.1' + + parsed_object = adapters.RecordAPIv2Adapter.parse_object( + values, objects.Record() + ) + + self.assertEqual('192.0.2.1', parsed_object.data) + + render_object = adapters.RecordAPIv2Adapter.render_object( + parsed_object + ) + + self.assertEqual(values, render_object) + + +class RecordSetAPIv2AdapterTest(oslotest.base.BaseTestCase): + def test_parse_object(self): + values = {'name': 'example.org.'} + + parsed_object = adapters.RecordSetAPIv2Adapter.parse_object( + values, objects.RecordSet() + ) + + self.assertEqual(values['name'], parsed_object.name) + + def test_parse_object_invalid_records(self): + values = {'name': 'example.org.', 'records': {'foo': 'bar'}} + + self.assertRaisesRegex( + exceptions.InvalidObject, + 'Provided object does not match schema', + adapters.RecordSetAPIv2Adapter.parse_object, values, + objects.RecordSet() + ) + + def test_render_object(self): + values = {'name': 'example.org.', 'records': []} + + parsed_object = adapters.RecordSetAPIv2Adapter.parse_object( + values, objects.RecordSet() + ) + + self.assertEqual(values['name'], parsed_object.name) + + render_object = adapters.RecordSetAPIv2Adapter.render_object( + parsed_object + ) + + self.assertIsInstance(render_object, dict) + self.assertEqual(values['name'], parsed_object.name) + + def test_get_path(self): + mock_request = mock.Mock() + mock_request.path = '/v2/recordsets' + mock_recordset = mock.Mock() + mock_recordset.zone_id = 'a-b-c-d' + expected_path = '/v2/zones/a-b-c-d/recordsets' + + path = adapters.RecordSetAPIv2Adapter._get_path( + mock_request, mock_recordset + ) + self.assertEqual(expected_path, path) + + +class SharedZoneAPIv2AdapterTest(oslotest.base.BaseTestCase): + def test_render_object(self): + values = { + 'target_project_id': '60b1dd98-49a7-403b-901a-291ca555da56', + } + + parsed_object = adapters.SharedZoneAPIv2Adapter.parse_object( + values, objects.SharedZone() + ) + + render_object = adapters.SharedZoneAPIv2Adapter.render_object( + parsed_object, + ) + + self.assertIsInstance(render_object, dict) + self.assertEqual( + '60b1dd98-49a7-403b-901a-291ca555da56', + render_object['target_project_id'] + ) + + def test_render_object_links(self): + share_id = '9edbb487-3ca1-4e9c-9503-6dd08a04b8c2' + zone_id = '9207ed7d-2094-4622-bce9-1af1886e958a' + + mock_request = mock.Mock() + mock_request.host_url = 'http://192.0.2.1' + mock_request.path = '/v2/zones/{zone_id}/shares/{zone_share_id}' + values = { + 'target_project_id': '60b1dd98-49a7-403b-901a-291ca555da56', + } + + parsed_object = adapters.SharedZoneAPIv2Adapter.parse_object( + values, objects.SharedZone() + ) + parsed_object.id = share_id + parsed_object.zone_id = zone_id + + render_object = adapters.SharedZoneAPIv2Adapter.render_object( + parsed_object, request=mock_request, + ) + + self.assertEqual( + f'{mock_request.host_url}/v2/zones/{zone_id}/shares/{share_id}', + render_object['links']['self'] + ) + self.assertEqual( + f'{mock_request.host_url}/v2/zones/{zone_id}', + render_object['links']['zone'] + ) + + +class SharedZoneListAPIv2AdapterTest(oslotest.base.BaseTestCase): + def test_get_collection_href(self): + mock_request = mock.Mock() + mock_request.GET = {'foo': 'bar'} + mock_request.host_url = 'http://192.0.2.1' + mock_request.path = '/v2/zones/{zone_id}/shares' + + self.assertEqual( + 'http://192.0.2.1/v2/zones/{zone_id}/shares?foo=bar', + adapters.SharedZoneListAPIv2Adapter._get_collection_href( + mock_request, {} + ) + ) + + +class ZoneAPIv2AdapterTest(oslotest.base.BaseTestCase): + def test_parse_object(self): + values = { + 'masters': ['192.0.2.1'], + 'attributes': {'foo': 'bar'}, + } + + adapter = adapters.ZoneAPIv2Adapter.parse_object( + values, objects.Zone() + ) + + self.assertFalse(values) + self.assertEqual(1, len(adapter.attributes)) + self.assertEqual('foo', adapter.attributes[0].key) + self.assertEqual('bar', adapter.attributes[0].value) + + +class ZoneAttributeAPIv2AdapterTest(oslotest.base.BaseTestCase): + def test_parse_object(self): + values = { + 'foo': 'bar' + } + + parsed_object = adapters.ZoneAttributeAPIv2Adapter.parse_object( + values, objects.ZoneAttribute() + ) + + self.assertEqual('foo', parsed_object.key) + self.assertEqual('bar', parsed_object.value) + + def test_render_object(self): + values = { + 'foo': 'bar' + } + + parsed_object = adapters.ZoneAttributeAPIv2Adapter.parse_object( + values, objects.ZoneAttribute() + ) + + self.assertEqual('foo', parsed_object.key) + self.assertEqual('bar', parsed_object.value) + + render_object = adapters.ZoneAttributeAPIv2Adapter.render_object( + parsed_object + ) + + self.assertIsInstance(render_object, dict) + self.assertEqual(values, render_object) + + +class ZoneAttributeListAPIv2AdapterTest(oslotest.base.BaseTestCase): + def test_parse_list(self): + zone_attribute = objects.ZoneAttribute(key='foo', value='bar') + + parsed_object = adapters.ZoneAttributeListAPIv2Adapter.parse_object( + {}, objects.ZoneAttributeList(objects=[zone_attribute]) + ) + + self.assertEqual(1, len(parsed_object)) + + def test_render_list(self): + zone_attribute = objects.ZoneAttribute(key='foo', value='bar') + + parsed_object = adapters.ZoneAttributeListAPIv2Adapter.parse_object( + {}, objects.ZoneAttributeList(objects=[zone_attribute]) + ) + + self.assertEqual(1, len(parsed_object)) + + render_object = adapters.ZoneAttributeListAPIv2Adapter.render_list( + parsed_object + ) + + self.assertEqual({'foo': 'bar'}, render_object) + + +class ZoneExportAPIv2AdapterTest(oslotest.base.BaseTestCase): + def test_render_object_links(self): + export_id = '51790877-ddb7-4351-b3af-23fb6e53098b' + + mock_request = mock.Mock() + mock_request.GET = {'foo': 'bar'} + mock_request.host_url = 'designate://192.0.2.1' + mock_request.path = '/v2/zones/{zone_id}/tasks/export' + + parsed_object = adapters.ZoneExportAPIv2Adapter.parse_object( + {}, objects.ZoneExport() + ) + parsed_object.location = ( + 'designate://192.0.2.1/v2/zones/{zone_id}/tasks/export' + ) + parsed_object.id = export_id + render_object = adapters.ZoneExportAPIv2Adapter.render_object( + parsed_object, request=mock_request, + ) + + self.assertEqual( + 'designate://192.0.2.1/192.0.2.1/v2/zones/{zone_id}/tasks/export', + render_object['links']['export'] + ) + self.assertEqual( + f'designate://192.0.2.1/v2/zones/tasks/exports/{export_id}', + render_object['links']['self'] + ) + + +class ZoneMasterAPIv2AdapterTest(oslotest.base.BaseTestCase): + def test_parse_object(self): + value = '192.0.2.1:5353' + + parsed_object = adapters.ZoneMasterAPIv2Adapter.parse_object( + value, objects.ZoneMaster() + ) + + self.assertEqual('192.0.2.1', parsed_object.host) + self.assertEqual(5353, parsed_object.port) + + def test_render_object(self): + value = '192.0.2.1:5353' + + parsed_object = adapters.ZoneMasterAPIv2Adapter.parse_object( + value, objects.ZoneMaster() + ) + + self.assertEqual('192.0.2.1', parsed_object.host) + self.assertEqual(5353, parsed_object.port) + + render_object = adapters.ZoneMasterAPIv2Adapter.render_object( + parsed_object + ) + + self.assertEqual('192.0.2.1:5353', render_object) + + def test_render_object_standard_dns_port(self): + value = '192.0.2.1:53' + + parsed_object = adapters.ZoneMasterAPIv2Adapter.parse_object( + value, objects.ZoneMaster() + ) + + self.assertEqual('192.0.2.1', parsed_object.host) + self.assertEqual(53, parsed_object.port) + + render_object = adapters.ZoneMasterAPIv2Adapter.render_object( + parsed_object + ) + + self.assertEqual('192.0.2.1', render_object) + + +class ZoneTransferRequestAPIv2AdapterTest(oslotest.base.BaseTestCase): + def test_parse_object(self): + values = { + 'target_project_id': '60b1dd98-49a7-403b-901a-291ca555da56', + } + + parsed_object = adapters.ZoneTransferRequestAPIv2Adapter.parse_object( + values, objects.ZoneTransferRequest() + ) + + self.assertEqual( + '60b1dd98-49a7-403b-901a-291ca555da56', + parsed_object.target_tenant_id + ) + + @mock.patch('designate.policy.check', mock.Mock()) + def test_render_object(self): + mock_context = mock.Mock() + values = { + 'target_project_id': '60b1dd98-49a7-403b-901a-291ca555da56', + } + + parsed_object = adapters.ZoneTransferRequestAPIv2Adapter.parse_object( + values, objects.ZoneTransferRequest() + ) + + self.assertEqual( + '60b1dd98-49a7-403b-901a-291ca555da56', + parsed_object.target_tenant_id + ) + + render_object = adapters.ZoneTransferRequestAPIv2Adapter.render_object( + parsed_object, context=mock_context + ) + + self.assertEqual( + '60b1dd98-49a7-403b-901a-291ca555da56', + render_object['target_project_id'] + ) + + @mock.patch('designate.policy.check') + def test_render_object_forbidden_raised(self, mock_policy_check): + mock_policy_check.side_effect = exceptions.Forbidden() + mock_context = mock.Mock() + values = { + 'target_project_id': '60b1dd98-49a7-403b-901a-291ca555da56', + } + + parsed_object = adapters.ZoneTransferRequestAPIv2Adapter.parse_object( + values, objects.ZoneTransferRequest() + ) + + self.assertEqual( + '60b1dd98-49a7-403b-901a-291ca555da56', + parsed_object.target_tenant_id + ) + + render_object = adapters.ZoneTransferRequestAPIv2Adapter.render_object( + parsed_object, context=mock_context + ) + + self.assertNotIn('target_project_id', render_object) diff --git a/designate/tests/unit/objects/test_yaml_adapters.py b/designate/tests/unit/objects/test_adapters_yaml.py similarity index 100% rename from designate/tests/unit/objects/test_yaml_adapters.py rename to designate/tests/unit/objects/test_adapters_yaml.py