From bdeb08e39f635e28930ce6135dc05995eaaace1f Mon Sep 17 00:00:00 2001 From: "sonu.kumar" Date: Tue, 5 Apr 2016 15:12:19 +0900 Subject: [PATCH] Resolves metadata field output on rest call to zone import and export Earlier on REST API call to zones/tasks/imports or zones/tasks/exports, metadata field was displayed with no key/val pair. This patch makes {'total_count : #val'} to be be produced as output in metadata field on execution of those REST API call. Closes-Bug: #1532925 Change-Id: I566e370edce5f29aafe793d5fdf7fe2fb7b3a856 --- designate/storage/impl_sqlalchemy/__init__.py | 29 ++++++++++++++- designate/tests/__init__.py | 34 +++++++++++++++++ .../test_api/test_v2/test_import_export.py | 37 +++++++++++++++++++ designate/tests/test_storage/__init__.py | 27 ++++++++++++++ 4 files changed, 125 insertions(+), 2 deletions(-) diff --git a/designate/storage/impl_sqlalchemy/__init__.py b/designate/storage/impl_sqlalchemy/__init__.py index 16bf77e5c..8e2c153e0 100644 --- a/designate/storage/impl_sqlalchemy/__init__.py +++ b/designate/storage/impl_sqlalchemy/__init__.py @@ -1823,11 +1823,17 @@ class SQLAlchemyStorage(sqlalchemy_base.SQLAlchemy, storage_base.Storage): if not criterion: criterion = {} criterion['task_type'] = 'IMPORT' - return self._find( + zone_imports = self._find( context, tables.zone_tasks, objects.ZoneImport, objects.ZoneImportList, exceptions.ZoneImportNotFound, criterion, one, marker, limit, sort_key, sort_dir) + if not one: + zone_imports.total_count = self.count_zone_tasks( + context, criterion) + + return zone_imports + def create_zone_import(self, context, zone_import): return self._create( tables.zone_tasks, zone_import, exceptions.DuplicateZoneImport) @@ -1863,10 +1869,15 @@ class SQLAlchemyStorage(sqlalchemy_base.SQLAlchemy, storage_base.Storage): if not criterion: criterion = {} criterion['task_type'] = 'EXPORT' - return self._find( + zone_exports = self._find( context, tables.zone_tasks, objects.ZoneExport, objects.ZoneExportList, exceptions.ZoneExportNotFound, criterion, one, marker, limit, sort_key, sort_dir) + if not one: + zone_exports.total_count = self.count_zone_tasks( + context, criterion) + + return zone_exports def create_zone_export(self, context, zone_export): return self._create( @@ -1897,6 +1908,20 @@ class SQLAlchemyStorage(sqlalchemy_base.SQLAlchemy, storage_base.Storage): return self._delete(context, tables.zone_tasks, zone_export, exceptions.ZoneExportNotFound) + def count_zone_tasks(self, context, criterion=None): + query = select([func.count(tables.zone_tasks.c.id)]) + query = self._apply_criterion(tables.zone_tasks, query, criterion) + query = self._apply_tenant_criteria(context, tables.zone_tasks, query) + query = self._apply_deleted_criteria(context, tables.zone_tasks, query) + + resultproxy = self.session.execute(query) + result = resultproxy.fetchone() + + if result is None: + return 0 + + return result[0] + # diagnostics def ping(self, context): start_time = time.time() diff --git a/designate/tests/__init__.py b/designate/tests/__init__.py index b3e0e99a3..25447abda 100644 --- a/designate/tests/__init__.py +++ b/designate/tests/__init__.py @@ -284,6 +284,23 @@ class TestCase(base.BaseTestCase): 'task_type': 'IMPORT' }] + zone_export_fixtures = [{ + 'status': 'PENDING', + 'zone_id': None, + 'message': None, + 'task_type': 'EXPORT' + }, { + 'status': 'ERROR', + 'zone_id': None, + 'message': None, + 'task_type': 'EXPORT' + }, { + 'status': 'COMPLETE', + 'zone_id': '6ca6baef-3305-4ad0-a52b-a82df5752b62', + 'message': None, + 'task_type': 'EXPORT' + }] + def setUp(self): super(TestCase, self).setUp() @@ -580,6 +597,13 @@ class TestCase(base.BaseTestCase): _values.update(values) return _values + def get_zone_export_fixture(self, fixture=0, values=None): + values = values or {} + + _values = copy.copy(self.zone_export_fixtures[fixture]) + _values.update(values) + return _values + def create_tld(self, **kwargs): context = kwargs.pop('context', self.admin_context) fixture = kwargs.pop('fixture', 0) @@ -733,6 +757,16 @@ class TestCase(base.BaseTestCase): return self.storage.create_zone_import( context, objects.ZoneImport.from_dict(zone_import)) + def create_zone_export(self, **kwargs): + context = kwargs.pop('context', self.admin_context) + fixture = kwargs.pop('fixture', 0) + + zone_export = self.get_zone_export_fixture(fixture=fixture, + values=kwargs) + + return self.storage.create_zone_export( + context, objects.ZoneExport.from_dict(zone_export)) + def wait_for_import(self, zone_import_id, errorok=False): """ Zone imports spawn a thread to parse the zone file and diff --git a/designate/tests/test_api/test_v2/test_import_export.py b/designate/tests/test_api/test_v2/test_import_export.py index 54d06ef97..2c1db36c9 100644 --- a/designate/tests/test_api/test_v2/test_import_export.py +++ b/designate/tests/test_api/test_v2/test_import_export.py @@ -133,3 +133,40 @@ class APIV2ZoneImportExportTest(ApiV2TestCase): exported.delete_rdataset(exported.origin, 'NS') imported.delete_rdataset('delegation', 'NS') self.assertEqual(imported, exported) + + # Metadata tests + def test_metadata_exists_imports(self): + response = self.client.get('/zones/tasks/imports') + + # Make sure the fields exist + self.assertIn('metadata', response.json) + self.assertIn('total_count', response.json['metadata']) + + def test_metadata_exists_exports(self): + response = self.client.get('/zones/tasks/imports') + + # Make sure the fields exist + self.assertIn('metadata', response.json) + self.assertIn('total_count', response.json['metadata']) + + def test_total_count_imports(self): + response = self.client.get('/zones/tasks/imports') + + # There are no imported zones by default + self.assertEqual(0, response.json['metadata']['total_count']) + + # Create a zone import + response = self.client.post('/zones/tasks/imports', + self.get_zonefile_fixture(), + headers={'Content-type': 'text/dns'}) + + response = self.client.get('/zones/tasks/imports') + + # Make sure total_count picked it up + self.assertEqual(1, response.json['metadata']['total_count']) + + def test_total_count_exports(self): + response = self.client.get('/zones/tasks/exports') + + # There are no exported zones by default + self.assertEqual(0, response.json['metadata']['total_count']) diff --git a/designate/tests/test_storage/__init__.py b/designate/tests/test_storage/__init__.py index 670d391df..aa63c1d03 100644 --- a/designate/tests/test_storage/__init__.py +++ b/designate/tests/test_storage/__init__.py @@ -3091,6 +3091,33 @@ class StorageTestCase(object): self.assertEqual(zt_accept.id, result.id) self.assertEqual(zt_accept.zone_id, result.zone_id) + def test_count_zone_tasks(self): + # in the beginning, there should be nothing + zones = self.storage.count_zone_tasks(self.admin_context) + self.assertEqual(0, zones) + + values = { + 'status': 'PENDING', + 'task_type': 'IMPORT' + } + + self.storage.create_zone_import( + self.admin_context, objects.ZoneImport.from_dict(values)) + + # count imported zones + zones = self.storage.count_zone_tasks(self.admin_context) + + # well, did we get 1? + self.assertEqual(1, zones) + + def test_count_zone_tasks_none_result(self): + rp = mock.Mock() + rp.fetchone.return_value = None + with mock.patch.object(self.storage.session, 'execute', + return_value=rp): + zones = self.storage.count_zone_tasks(self.admin_context) + self.assertEqual(0, zones) + # Zone Import Tests def test_create_zone_import(self): values = {