def create_domain(self, context, values): domain = models.Domain() domain.update(values) try: domain.save(self.session) except exceptions.Duplicate: raise exceptions.DuplicateDomain() return dict(domain)
def update_domain(self, context, domain_id, values): domain = self._find_domains(context, {'id': domain_id}, one=True) domain.update(values) try: domain.save(self.session) except exceptions.Duplicate: raise exceptions.DuplicateDomain() return dict(domain)
def create_domain(self, context, domain): storage_domain = models.Domain() storage_domain.update(domain) try: storage_domain.save(self.session) except exceptions.Duplicate: raise exceptions.DuplicateDomain() return objects.Domain.from_sqla(storage_domain)
class ApiV2ZonesTest(ApiV2TestCase): __test__ = True def setUp(self): super(ApiV2ZonesTest, self).setUp() # Create a server self.create_server() def test_missing_accept(self): self.client.get('/zones/123', status=400) def test_bad_accept(self): self.client.get('/zones/123', headers={'Accept': 'test/goat'}, status=406) def test_missing_content_type(self): self.client.post('/zones', status=415) def test_bad_content_type(self): self.client.post('/zones', headers={'Content-type': 'test/goat'}, status=415) def test_create_zone(self): # Create a zone fixture = self.get_domain_fixture(0) response = self.client.post_json('/zones/', {'zone': fixture}) # Check the headers are what we expect self.assertEqual(201, response.status_int) self.assertEqual('application/json', response.content_type) # Check the body structure is what we expect self.assertIn('zone', response.json) self.assertIn('links', response.json['zone']) self.assertIn('self', response.json['zone']['links']) # Check the values returned are what we expect self.assertIn('id', response.json['zone']) self.assertIn('created_at', response.json['zone']) self.assertEqual('ACTIVE', response.json['zone']['status']) self.assertIsNone(response.json['zone']['updated_at']) for k in fixture: self.assertEqual(fixture[k], response.json['zone'][k]) def test_create_zone_validation(self): # NOTE: The schemas should be tested separatly to the API. So we # don't need to test every variation via the API itself. # Fetch a fixture fixture = self.get_domain_fixture(0) # Add a junk field to the wrapper body = {'zone': fixture, 'junk': 'Junk Field'} # Ensure it fails with a 400 response = self.client.post_json('/zones/', body, status=400) self.assertEqual(400, response.status_int) # Add a junk field to the body fixture['junk'] = 'Junk Field' # Ensure it fails with a 400 body = {'zone': fixture} self.client.post_json('/zones/', body, status=400) @patch.object(central_service.Service, 'create_domain', side_effect=rpc_common.Timeout()) def test_create_zone_timeout(self, _): fixture = self.get_domain_fixture(0) body = {'zone': fixture} self.client.post_json('/zones/', body, status=504) @patch.object(central_service.Service, 'create_domain', side_effect=exceptions.DuplicateDomain()) def test_create_zone_duplicate(self, _): fixture = self.get_domain_fixture(0) body = {'zone': fixture} self.client.post_json('/zones/', body, status=409) def test_get_zones(self): response = self.client.get('/zones/') # Check the headers are what we expect self.assertEqual(200, response.status_int) self.assertEqual('application/json', response.content_type) # Check the body structure is what we expect self.assertIn('zones', response.json) self.assertIn('links', response.json) self.assertIn('self', response.json['links']) # We should start with 0 zones self.assertEqual(0, len(response.json['zones'])) # Test with 1 zone self.create_domain() response = self.client.get('/zones/') self.assertIn('zones', response.json) self.assertEqual(1, len(response.json['zones'])) # test with 2 zones self.create_domain(fixture=1) response = self.client.get('/zones/') self.assertIn('zones', response.json) self.assertEqual(2, len(response.json['zones'])) @patch.object(central_service.Service, 'find_domains', side_effect=rpc_common.Timeout()) def test_get_zones_timeout(self, _): self.client.get('/zones/', status=504) def test_get_zone(self): # Create a zone zone = self.create_domain() response = self.client.get('/zones/%s' % zone['id'], headers=[('Accept', 'application/json')]) # Check the headers are what we expect self.assertEqual(200, response.status_int) self.assertEqual('application/json', response.content_type) # Check the body structure is what we expect self.assertIn('zone', response.json) self.assertIn('links', response.json['zone']) self.assertIn('self', response.json['zone']['links']) # Check the values returned are what we expect self.assertIn('id', response.json['zone']) self.assertIn('created_at', response.json['zone']) self.assertEqual('ACTIVE', response.json['zone']['status']) self.assertIsNone(response.json['zone']['updated_at']) self.assertEqual(zone['name'], response.json['zone']['name']) self.assertEqual(zone['email'], response.json['zone']['email']) @patch.object(central_service.Service, 'get_domain', side_effect=rpc_common.Timeout()) def test_get_zone_timeout(self, _): self.client.get('/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', headers={'Accept': 'application/json'}, status=504) @patch.object(central_service.Service, 'get_domain', side_effect=exceptions.DomainNotFound()) def test_get_zone_missing(self, _): self.client.get('/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', headers={'Accept': 'application/json'}, status=404) def test_get_zone_invalid_id(self): self.skip('We don\'t guard against this in APIv2 yet') # The letter "G" is not valid in a UUID self.client.get('/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff9GG', headers={'Accept': 'application/json'}, status=404) # Badly formed UUID self.client.get('/zones/2fdadfb1cf964259ac6bbb7b6d2ff9GG', headers={'Accept': 'application/json'}, status=404) # Integer self.client.get('/zones/12345', headers={'Accept': 'application/json'}, status=404) def test_update_zone(self): # Create a zone zone = self.create_domain() # Prepare an update body body = {'zone': {'email': 'prefix-%s' % zone['email']}} response = self.client.patch_json('/zones/%s' % zone['id'], body, status=200) # Check the headers are what we expect self.assertEqual(200, response.status_int) self.assertEqual('application/json', response.content_type) # Check the body structure is what we expect self.assertIn('zone', response.json) self.assertIn('links', response.json['zone']) self.assertIn('self', response.json['zone']['links']) self.assertIn('status', response.json['zone']) # Check the values returned are what we expect self.assertIn('id', response.json['zone']) self.assertIsNotNone(response.json['zone']['updated_at']) self.assertEqual('prefix-%s' % zone['email'], response.json['zone']['email']) def test_update_zone_validation(self): # NOTE: The schemas should be tested separatly to the API. So we # don't need to test every variation via the API itself. # Create a zone zone = self.create_domain() # Prepare an update body with junk in the wrapper body = { 'zone': { 'email': 'prefix-%s' % zone['email'] }, 'junk': 'Junk Field' } # Ensure it fails with a 400 self.client.patch_json('/zones/%s' % zone['id'], body, status=400) # Prepare an update body with junk in the body body = { 'zone': { 'email': 'prefix-%s' % zone['email'], 'junk': 'Junk Field' } } # Ensure it fails with a 400 self.client.patch_json('/zones/%s' % zone['id'], body, status=400) @patch.object(central_service.Service, 'get_domain', side_effect=exceptions.DuplicateDomain()) def test_update_zone_duplicate(self, _): # Prepare an update body body = {'zone': {'email': '*****@*****.**'}} # Ensure it fails with a 409 self.client.patch_json('/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', body, status=409) @patch.object(central_service.Service, 'get_domain', side_effect=rpc_common.Timeout()) def test_update_zone_timeout(self, _): # Prepare an update body body = {'zone': {'email': '*****@*****.**'}} # Ensure it fails with a 504 self.client.patch_json('/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', body, status=504) @patch.object(central_service.Service, 'get_domain', side_effect=exceptions.DomainNotFound()) def test_update_zone_missing(self, _): # Prepare an update body body = {'zone': {'email': '*****@*****.**'}} # Ensure it fails with a 404 self.client.patch_json('/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', body, status=404) def test_update_zone_invalid_id(self): self.skip('We don\'t guard against this in APIv2 yet') # Prepare an update body body = {'zone': {'email': '*****@*****.**'}} # The letter "G" is not valid in a UUID self.client.patch_json('/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff9GG', body, status=404) # Badly formed UUID self.client.patch_json('/zones/2fdadfb1cf964259ac6bbb7b6d2ff980', body, status=404) # Integer self.client.patch_json('/zones/12345', body, status=404) def test_delete_zone(self): zone = self.create_domain() self.client.delete('/zones/%s' % zone['id'], status=204) @patch.object(central_service.Service, 'delete_domain', side_effect=rpc_common.Timeout()) def test_delete_zone_timeout(self, _): self.client.delete('/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', status=504) @patch.object(central_service.Service, 'delete_domain', side_effect=exceptions.DomainNotFound()) def test_delete_zone_missing(self, _): self.client.delete('/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', status=404) def test_delete_zone_invalid_id(self): self.skip('We don\'t guard against this in APIv2 yet') # The letter "G" is not valid in a UUID self.client.delete('/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff9GG', status=404) # Badly formed UUID self.client.delete('/zones/2fdadfb1cf964259ac6bbb7b6d2ff980', status=404) # Integer self.client.delete('/zones/12345', status=404) # Zone import/export def test_missing_origin(self): self.client.post('/zones', self.get_zonefile_fixture(variant='noorigin'), headers={'Content-type': 'text/dns'}, status=400) def test_missing_soa(self): self.client.post('/zones', self.get_zonefile_fixture(variant='nosoa'), headers={'Content-type': 'text/dns'}, status=400) def test_malformed_zonefile(self): self.client.post('/zones', self.get_zonefile_fixture(variant='malformed'), headers={'Content-type': 'text/dns'}, status=400) def test_import_export(self): # Since v2 doesn't support getting records, import and export the # fixture, making sure they're the same according to dnspython post_response = self.client.post('/zones', self.get_zonefile_fixture(), headers={'Content-type': 'text/dns'}) get_response = self.client.get('/zones/%s' % post_response.json['zone']['id'], headers={'Accept': 'text/dns'}) exported_zonefile = get_response.body imported = dnszone.from_text(self.get_zonefile_fixture()) exported = dnszone.from_text(exported_zonefile) # Compare SOA emails, since zone comparison takes care of origin imported_soa = imported.get_rdataset(imported.origin, 'SOA') imported_email = imported_soa[0].rname.to_text() exported_soa = exported.get_rdataset(exported.origin, 'SOA') exported_email = exported_soa[0].rname.to_text() self.assertEqual(imported_email, exported_email) # Delete SOAs since they have, at the very least, different serials, # and dnspython considers that to be not equal. imported.delete_rdataset(imported.origin, 'SOA') exported.delete_rdataset(exported.origin, 'SOA') # Delete non-delegation NS, since they won't be the same imported.delete_rdataset(imported.origin, 'NS') exported.delete_rdataset(exported.origin, 'NS') self.assertEqual(imported, exported)
class ApiV2ZonesTest(ApiV2TestCase): def setUp(self): super(ApiV2ZonesTest, self).setUp() # Create the default TLDs self.create_default_tlds() def test_create_zone(self): # Create a zone fixture = self.get_domain_fixture(fixture=0) response = self.client.post_json('/zones/', fixture) # Check the headers are what we expect self.assertEqual(202, response.status_int) self.assertEqual('application/json', response.content_type) # Check the body structure is what we expect self.assertIn('links', response.json) self.assertIn('self', response.json['links']) # Check the values returned are what we expect self.assertIn('id', response.json) self.assertIn('created_at', response.json) self.assertEqual('PENDING', response.json['status']) self.assertEqual('PRIMARY', response.json['type']) self.assertEqual([], response.json['masters']) self.assertIsNone(response.json['updated_at']) for k in fixture: self.assertEqual(fixture[k], response.json[k]) def test_create_zone_no_type(self): # Create a zone fixture = self.get_domain_fixture(fixture=0) del fixture['type'] response = self.client.post_json('/zones/', fixture) # Check the headers are what we expect self.assertEqual(202, response.status_int) self.assertEqual('application/json', response.content_type) # Check the body structure is what we expect self.assertIn('links', response.json) self.assertIn('self', response.json['links']) # Check the values returned are what we expect self.assertIn('id', response.json) self.assertIn('created_at', response.json) self.assertEqual('PENDING', response.json['status']) self.assertEqual('PRIMARY', response.json['type']) self.assertEqual([], response.json['masters']) self.assertIsNone(response.json['updated_at']) for k in fixture: self.assertEqual(fixture[k], response.json[k]) def test_create_zone_validation(self): # NOTE: The schemas should be tested separately to the API. So we # don't need to test every variation via the API itself. # Fetch a fixture fixture = self.get_domain_fixture(fixture=0) # Add a junk field to the body fixture['junk'] = 'Junk Field' # Ensure it fails with a 400 body = fixture self._assert_exception('invalid_object', 400, self.client.post_json, '/zones', body) def test_create_zone_body_validation(self): fixture = self.get_domain_fixture(fixture=0) # Add id to the body fixture['id'] = '2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980' # Ensure it fails with a 400 body = fixture self._assert_exception('invalid_object', 400, self.client.post_json, '/zones', body) fixture = self.get_domain_fixture(fixture=0) # Add created_at to the body fixture['created_at'] = '2014-03-12T19:07:53.000000' # Ensure it fails with a 400 body = fixture self._assert_exception('invalid_object', 400, self.client.post_json, '/zones', body) def test_create_zone_invalid_name(self): # Try to create a zone with an invalid name fixture = self.get_domain_fixture(fixture=-1) # Ensure it fails with a 400 self._assert_exception('invalid_object', 400, self.client.post_json, '/zones', fixture) @patch.object(central_service.Service, 'create_domain', side_effect=messaging.MessagingTimeout()) def test_create_zone_timeout(self, _): fixture = self.get_domain_fixture(fixture=0) body = fixture self._assert_exception('timeout', 504, self.client.post_json, '/zones/', body) @patch.object(central_service.Service, 'create_domain', side_effect=exceptions.DuplicateDomain()) def test_create_zone_duplicate(self, _): fixture = self.get_domain_fixture(fixture=0) body = fixture self._assert_exception('duplicate_domain', 409, self.client.post_json, '/zones/', body) def test_create_zone_missing_content_type(self): self._assert_exception('unsupported_content_type', 415, self.client.post, '/zones') def test_create_zone_bad_content_type(self): self._assert_exception('unsupported_content_type', 415, self.client.post, '/zones', headers={'Content-type': 'test/goat'}) def test_zone_invalid_url(self): url = '/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980/invalid' self._assert_exception('not_found', 404, self.client.get, url, headers={'Accept': 'application/json'}) self._assert_exception('not_found', 404, self.client.patch_json, url) self._assert_exception('not_found', 404, self.client.delete, url) # Pecan returns a 405 for post response = self.client.post(url, status=405) self.assertEqual(405, response.status_int) def test_get_zones(self): response = self.client.get('/zones/') # Check the headers are what we expect self.assertEqual(200, response.status_int) self.assertEqual('application/json', response.content_type) # Check the body structure is what we expect self.assertIn('zones', response.json) self.assertIn('links', response.json) self.assertIn('self', response.json['links']) # We should start with 0 zones self.assertEqual(0, len(response.json['zones'])) # We should start with 0 zones self.assertEqual(0, len(response.json['zones'])) data = [self.create_domain(name='x-%s.com.' % i) for i in 'abcdefghij'] self._assert_paging(data, '/zones', key='zones') self._assert_invalid_paging(data, '/zones', key='zones') @patch.object(central_service.Service, 'find_domains', side_effect=messaging.MessagingTimeout()) def test_get_zones_timeout(self, _): self._assert_exception('timeout', 504, self.client.get, '/zones/') def test_get_zone(self): # Create a zone zone = self.create_domain() response = self.client.get('/zones/%s' % zone['id'], headers=[('Accept', 'application/json')]) # Check the headers are what we expect self.assertEqual(200, response.status_int) self.assertEqual('application/json', response.content_type) # Check the body structure is what we expect self.assertIn('links', response.json) self.assertIn('self', response.json['links']) # Check the values returned are what we expect self.assertIn('id', response.json) self.assertIn('created_at', response.json) self.assertEqual('PENDING', response.json['status']) self.assertIsNone(response.json['updated_at']) self.assertEqual(zone['name'], response.json['name']) self.assertEqual(zone['email'], response.json['email']) def test_get_zone_invalid_id(self): self._assert_invalid_uuid(self.client.get, '/zones/%s') @patch.object(central_service.Service, 'get_domain', side_effect=messaging.MessagingTimeout()) def test_get_zone_timeout(self, _): url = '/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980' self._assert_exception('timeout', 504, self.client.get, url, headers={'Accept': 'application/json'}) @patch.object(central_service.Service, 'get_domain', side_effect=exceptions.DomainNotFound()) def test_get_zone_missing(self, _): url = '/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980' self._assert_exception('domain_not_found', 404, self.client.get, url, headers={'Accept': 'application/json'}) def test_get_zone_bad_accept(self): url = '/zones/6e2146f3-87bc-4f47-adc5-4df0a5c78218' self.client.get(url, headers={'Accept': 'test/goat'}, status=406) def test_update_zone(self): # Create a zone zone = self.create_domain() # Prepare an update body body = {'email': 'prefix-%s' % zone['email']} response = self.client.patch_json('/zones/%s' % zone['id'], body, status=202) # Check the headers are what we expect self.assertEqual(202, response.status_int) self.assertEqual('application/json', response.content_type) # Check the body structure is what we expect self.assertIn('links', response.json) self.assertIn('self', response.json['links']) self.assertIn('status', response.json) # Check the values returned are what we expect self.assertIn('id', response.json) self.assertIsNotNone(response.json['updated_at']) self.assertEqual('prefix-%s' % zone['email'], response.json['email']) def test_update_zone_invalid_id(self): self._assert_invalid_uuid(self.client.patch_json, '/zones/%s') def test_update_zone_validation(self): # NOTE: The schemas should be tested separatly to the API. So we # don't need to test every variation via the API itself. # Create a zone zone = self.create_domain() # Prepare an update body with junk in the body body = {'email': 'prefix-%s' % zone['email'], 'junk': 'Junk Field'} url = '/zones/%s' % zone['id'] # Ensure it fails with a 400 self._assert_exception('invalid_object', 400, self.client.patch_json, url, body) # Prepare an update body with negative ttl in the body body = {'email': 'prefix-%s' % zone['email'], 'ttl': -20} # Ensure it fails with a 400 self._assert_exception('invalid_object', 400, self.client.patch_json, url, body) # Prepare an update body with ttl > maximum (2147483647) in the body body = {'email': 'prefix-%s' % zone['email'], 'ttl': 2147483648} # Ensure it fails with a 400 self._assert_exception('invalid_object', 400, self.client.patch_json, url, body) @patch.object(central_service.Service, 'get_domain', side_effect=exceptions.DuplicateDomain()) def test_update_zone_duplicate(self, _): # Prepare an update body body = {'email': '*****@*****.**'} url = '/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980' # Ensure it fails with a 409 self._assert_exception('duplicate_domain', 409, self.client.patch_json, url, body) @patch.object(central_service.Service, 'get_domain', side_effect=messaging.MessagingTimeout()) def test_update_zone_timeout(self, _): # Prepare an update body body = {'email': '*****@*****.**'} url = '/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980' # Ensure it fails with a 504 self._assert_exception('timeout', 504, self.client.patch_json, url, body) @patch.object(central_service.Service, 'get_domain', side_effect=exceptions.DomainNotFound()) def test_update_zone_missing(self, _): # Prepare an update body body = {'email': '*****@*****.**'} url = '/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980' # Ensure it fails with a 404 self._assert_exception('domain_not_found', 404, self.client.patch_json, url, body) def test_delete_zone(self): zone = self.create_domain() response = self.client.delete('/zones/%s' % zone['id'], status=202) # Check the headers are what we expect self.assertEqual(202, response.status_int) self.assertEqual('application/json', response.content_type) self.assertEqual('DELETE', response.json['action']) self.assertEqual('PENDING', response.json['status']) def test_delete_zone_invalid_id(self): self._assert_invalid_uuid(self.client.delete, '/zones/%s') @patch.object(central_service.Service, 'delete_domain', side_effect=messaging.MessagingTimeout()) def test_delete_zone_timeout(self, _): url = '/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980' self._assert_exception('timeout', 504, self.client.delete, url) @patch.object(central_service.Service, 'delete_domain', side_effect=exceptions.DomainNotFound()) def test_delete_zone_missing(self, _): url = '/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980' self._assert_exception('domain_not_found', 404, self.client.delete, url) def test_post_abandon_zone(self): zone = self.create_domain() url = '/zones/%s/tasks/abandon' % zone.id # Ensure that we get permission denied self._assert_exception('forbidden', 403, self.client.post_json, url) # Ensure that abandon zone succeeds with the right policy self.policy({'abandon_domain': '@'}) response = self.client.post_json(url) self.assertEqual(204, response.status_int) def test_get_abandon_zone(self): zone = self.create_domain() url = '/zones/%s/tasks/abandon' % zone.id self._assert_exception('method_not_allowed', 405, self.client.get, url) def test_get_invalid_abandon(self): # This is an invalid endpoint - should return 404 url = '/zones/tasks/abandon' self._assert_exception('not_found', 404, self.client.get, url) def test_get_zone_tasks(self): # This is an invalid endpoint - should return 404 zone = self.create_domain() url = '/zones/%s/tasks' % zone.id self._assert_exception('not_found', 404, self.client.get, url) def test_create_secondary(self): # Create a zone fixture = self.get_domain_fixture('SECONDARY', 0) fixture['masters'] = ["10.0.0.1"] response = self.client.post_json('/zones/', fixture) # Check the headers are what we expect self.assertEqual(202, response.status_int) self.assertEqual('application/json', response.content_type) # Check the body structure is what we expect self.assertIn('links', response.json) self.assertIn('self', response.json['links']) # Check the values returned are what we expect self.assertIn('id', response.json) self.assertIn('created_at', response.json) self.assertEqual('PENDING', response.json['status']) self.assertEqual(cfg.CONF['service:central'].managed_resource_email, response.json['email']) self.assertIsNone(response.json['updated_at']) # Zone is not transferred yet self.assertIsNone(response.json['transferred_at']) # Serial defaults to 1 self.assertEqual(response.json['serial'], 1) for k in fixture: self.assertEqual(fixture[k], response.json[k]) def test_create_secondary_no_masters(self): # Create a zone fixture = self.get_domain_fixture('SECONDARY', 0) self._assert_exception('invalid_object', 400, self.client.post_json, '/zones/', fixture) def test_update_secondary(self): # Create a zone fixture = self.get_domain_fixture('SECONDARY', 0) fixture['email'] = cfg.CONF['service:central'].managed_resource_email fixture['attributes'] = [{"key": "master", "value": "10.0.0.10"}] # Create a zone zone = self.create_domain(**fixture) masters = ['10.0.0.1', '10.0.0.2'] # Prepare an update body body = {'masters': masters} response = self.client.patch_json('/zones/%s' % zone['id'], body, status=202) # Check the headers are what we expect self.assertEqual(202, response.status_int) self.assertEqual('application/json', response.content_type) # Check the body structure is what we expect self.assertIn('links', response.json) self.assertIn('self', response.json['links']) self.assertIn('status', response.json) # Check the values returned are what we expect self.assertIn('id', response.json) self.assertIsNotNone(response.json['updated_at']) self.assertEqual(masters, response.json['masters']) self.assertEqual(1, response.json['serial']) def test_xfr_request(self): # Create a zone fixture = self.get_domain_fixture('SECONDARY', 0) fixture['email'] = cfg.CONF['service:central'].managed_resource_email fixture['attributes'] = [{"key": "master", "value": "10.0.0.10"}] # Create a zone zone = self.create_domain(**fixture) response = self.client.post_json('/zones/%s/tasks/xfr' % zone['id'], None, status=202) # Check the headers are what we expect self.assertEqual(202, response.status_int) self.assertEqual('application/json', response.content_type) def test_invalid_xfr_request(self): # Create a zone # Create a zone zone = self.create_domain() response = self.client.post_json('/zones/%s/tasks/xfr' % zone['id'], None, status=400) # Check the headers are what we expect self.assertEqual(400, response.status_int) self.assertEqual('application/json', response.content_type) def test_update_secondary_email_invalid_object(self): # Create a zone fixture = self.get_domain_fixture('SECONDARY', 0) fixture['email'] = cfg.CONF['service:central'].managed_resource_email # Create a zone zone = self.create_domain(**fixture) body = {'email': '*****@*****.**'} self._assert_exception('invalid_object', 400, self.client.patch_json, '/zones/%s' % zone['id'], body) # Metadata tests def test_metadata_exists(self): response = self.client.get('/zones/') # Make sure the fields exist self.assertIn('metadata', response.json) self.assertIn('total_count', response.json['metadata']) def test_total_count(self): response = self.client.get('/zones/') # There are no zones by default self.assertEqual(0, response.json['metadata']['total_count']) # Create a zone fixture = self.get_domain_fixture(fixture=0) response = self.client.post_json('/zones/', fixture) response = self.client.get('/zones/') # Make sure total_count picked it up self.assertEqual(1, response.json['metadata']['total_count']) def test_total_count_pagination(self): # Create two zones fixture = self.get_domain_fixture(fixture=0) response = self.client.post_json('/zones/', fixture) fixture = self.get_domain_fixture(fixture=1) response = self.client.post_json('/zones/', fixture) # Paginate so that there is only one zone returned response = self.client.get('/zones?limit=1') self.assertEqual(1, len(response.json['zones'])) # The total_count should know there are two self.assertEqual(2, response.json['metadata']['total_count']) def test_no_update_deleting(self): # Create a zone zone = self.create_domain() # Prepare an update body body = {'zone': {'email': 'prefix-%s' % zone['email']}} self.client.delete('/zones/%s' % zone['id'], status=202) self._assert_exception('bad_request', 400, self.client.patch_json, '/zones/%s' % zone['id'], body) def test_get_nameservers(self): # Create a zone zone = self.create_domain() # Prepare an update body response = self.client.get('/zones/%s/nameservers' % zone['id'], headers=[('Accept', 'application/json')]) self.assertIn('nameservers', response.json) self.assertEqual(1, len(response.json['nameservers'])) self.assertIn('hostname', response.json['nameservers'][0]) self.assertIn('priority', response.json['nameservers'][0])
class ApiV1DomainsTest(ApiV1Test): def test_create_domain(self): # Create a domain fixture = self.get_domain_fixture(0) # V1 doesn't have these del fixture['type'] response = self.post('domains', data=fixture) self.assertIn('id', response.json) self.assertIn('name', response.json) self.assertEqual(response.json['name'], fixture['name']) def test_create_domain_junk(self): # Create a domain fixture = self.get_domain_fixture(0) # Add a junk property fixture['junk'] = 'Junk Field' # Ensure it fails with a 400 self.post('domains', data=fixture, status_code=400) @patch.object(central_service.Service, 'create_domain', side_effect=messaging.MessagingTimeout()) def test_create_domain_timeout(self, _): # Create a domain fixture = self.get_domain_fixture(0) # V1 doesn't have these del fixture['type'] self.post('domains', data=fixture, status_code=504) @patch.object(central_service.Service, 'create_domain', side_effect=exceptions.DuplicateDomain()) def test_create_domain_duplicate(self, _): # Create a domain fixture = self.get_domain_fixture(0) # V1 doesn't have these del fixture['type'] self.post('domains', data=fixture, status_code=409) def test_create_domain_null_ttl(self): # Create a domain fixture = self.get_domain_fixture(0) fixture['ttl'] = None self.post('domains', data=fixture, status_code=400) def test_create_domain_negative_ttl(self): # Create a domain fixture = self.get_domain_fixture(0) fixture['ttl'] = -1 self.post('domains', data=fixture, status_code=400) def test_create_domain_invalid_ttl(self): # Create a domain fixture = self.get_domain_fixture(0) fixture['ttl'] = "$?>&" self.post('domains', data=fixture, status_code=400) def test_create_domain_utf_description(self): # Create a domain fixture = self.get_domain_fixture(0) # V1 doesn't have type del fixture['type'] # Give it a UTF-8 filled description fixture['description'] = "utf-8:2H₂+O₂⇌2H₂O,R=4.7kΩ,⌀200mm∮E⋅da=Q,n" \ ",∑f(i)=∏g(i),∀x∈ℝ:⌈x⌉" # Create the domain, ensuring it succeeds, thus UTF-8 is supported self.post('domains', data=fixture) def test_create_domain_description_too_long(self): # Create a domain fixture = self.get_domain_fixture(0) fixture['description'] = "x" * 161 # Create the domain, ensuring it fails with a 400 self.post('domains', data=fixture, status_code=400) def test_create_domain_with_unwanted_attributes(self): domain_id = "2d1d1d1d-1324-4a80-aa32-1f69a91bf2c8" created_at = datetime.datetime(2014, 6, 22, 21, 50, 0) updated_at = datetime.datetime(2014, 6, 22, 21, 50, 0) serial = 1234567 # Create a domain fixture = self.get_domain_fixture(0) fixture['id'] = domain_id fixture['created_at'] = created_at fixture['updated_at'] = updated_at fixture['serial'] = serial self.post('domains', data=fixture, status_code=400) def test_create_invalid_name(self): # Prepare a domain fixture = self.get_domain_fixture(0) invalid_names = [ 'org', 'example.org', 'example.321', ] for invalid_name in invalid_names: fixture['name'] = invalid_name # Create a record response = self.post('domains', data=fixture, status_code=400) self.assertNotIn('id', response.json) def test_create_invalid_email(self): # Prepare a domain fixture = self.get_domain_fixture(0) invalid_emails = [ 'org', 'example.org', 'bla.example.org', 'org.', 'example.org.', 'bla.example.org.', 'bla.example.org.', ] for invalid_email in invalid_emails: fixture['email'] = invalid_email # Create a record response = self.post('domains', data=fixture, status_code=400) self.assertNotIn('id', response.json) def test_get_domains(self): response = self.get('domains') self.assertIn('domains', response.json) self.assertEqual(0, len(response.json['domains'])) # Create a domain self.create_domain() response = self.get('domains') self.assertIn('domains', response.json) self.assertEqual(1, len(response.json['domains'])) # Create a second domain self.create_domain(fixture=1) response = self.get('domains') self.assertIn('domains', response.json) self.assertEqual(2, len(response.json['domains'])) def test_get_domain_servers(self): # Create a domain domain = self.create_domain() response = self.get('domains/%s/servers' % domain['id']) # Verify length of domain servers self.assertEqual(1, len(response.json['servers'])) @patch.object(central_service.Service, 'find_domains', side_effect=messaging.MessagingTimeout()) def test_get_domains_timeout(self, _): self.get('domains', status_code=504) def test_get_domain(self): # Create a domain domain = self.create_domain() response = self.get('domains/%s' % domain['id']) self.assertIn('id', response.json) self.assertEqual(response.json['id'], domain['id']) @patch.object(central_service.Service, 'find_domain', side_effect=messaging.MessagingTimeout()) def test_get_domain_timeout(self, _): # Create a domain domain = self.create_domain() self.get('domains/%s' % domain['id'], status_code=504) def test_get_domain_missing(self): self.get('domains/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', status_code=404) def test_get_domain_invalid_id(self): # The letter "G" is not valid in a UUID self.get('domains/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff9GG', status_code=404) self.get('domains/2fdadfb1cf964259ac6bbb7b6d2ff980', status_code=404) def test_update_domain(self): # Create a domain domain = self.create_domain() data = {'email': 'prefix-%s' % domain['email']} response = self.put('domains/%s' % domain['id'], data=data) self.assertIn('id', response.json) self.assertEqual(response.json['id'], domain['id']) self.assertIn('email', response.json) self.assertEqual(response.json['email'], 'prefix-%s' % domain['email']) def test_update_domain_junk(self): # Create a domain domain = self.create_domain() data = {'email': 'prefix-%s' % domain['email'], 'junk': 'Junk Field'} self.put('domains/%s' % domain['id'], data=data, status_code=400) def test_update_domain_name_fail(self): # Create a domain domain = self.create_domain() data = {'name': 'renamed.com.'} self.put('domains/%s' % domain['id'], data=data, status_code=400) def test_update_domain_null_ttl(self): # Create a domain domain = self.create_domain() data = {'ttl': None} self.put('domains/%s' % domain['id'], data=data, status_code=400) def test_update_domain_negative_ttl(self): # Create a domain domain = self.create_domain() data = {'ttl': -1} self.put('domains/%s' % domain['id'], data=data, status_code=400) @patch.object(central_service.Service, 'update_domain', side_effect=messaging.MessagingTimeout()) def test_update_domain_timeout(self, _): # Create a domain domain = self.create_domain() data = {'email': 'prefix-%s' % domain['email']} self.put('domains/%s' % domain['id'], data=data, status_code=504) @patch.object(central_service.Service, 'update_domain', side_effect=exceptions.DuplicateDomain()) def test_update_domain_duplicate(self, _): # Create a domain domain = self.create_domain() data = {'email': 'prefix-%s' % domain['email']} self.put('domains/%s' % domain['id'], data=data, status_code=409) def test_update_domain_missing(self): data = {'email': '*****@*****.**'} self.put('domains/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', data=data, status_code=404) def test_update_domain_invalid_id(self): data = {'email': '*****@*****.**'} # The letter "G" is not valid in a UUID self.put('domains/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff9GG', data=data, status_code=404) self.put('domains/2fdadfb1cf964259ac6bbb7b6d2ff980', data=data, status_code=404) def test_delete_domain(self): # Create a domain domain = self.create_domain() self.delete('domains/%s' % domain['id']) # Simulate the domain having been deleted on the backend domain_serial = self.central_service.get_domain( self.admin_context, domain['id']).serial self.central_service.update_status(self.admin_context, domain['id'], "SUCCESS", domain_serial) # Ensure we can no longer fetch the domain self.get('domains/%s' % domain['id'], status_code=404) @patch.object(central_service.Service, 'delete_domain', side_effect=messaging.MessagingTimeout()) def test_delete_domain_timeout(self, _): # Create a domain domain = self.create_domain() self.delete('domains/%s' % domain['id'], status_code=504) def test_delete_domain_missing(self): self.delete('domains/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', status_code=404) def test_delete_domain_invalid_id(self): # The letter "G" is not valid in a UUID self.delete('domains/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff9GG', status_code=404) self.delete('domains/2fdadfb1cf964259ac6bbb7b6d2ff980', status_code=404) def test_get_secondary_missing(self): fixture = self.get_domain_fixture('SECONDARY', 0) fixture['email'] = cfg.CONF['service:central'].managed_resource_email domain = self.create_domain(**fixture) self.get('domains/%s' % domain.id, status_code=404) def test_update_secondary_missing(self): fixture = self.get_domain_fixture('SECONDARY', 0) fixture['email'] = cfg.CONF['service:central'].managed_resource_email domain = self.create_domain(**fixture) self.put('domains/%s' % domain.id, {}, status_code=404) def test_delete_secondary_missing(self): fixture = self.get_domain_fixture('SECONDARY', 0) fixture['email'] = cfg.CONF['service:central'].managed_resource_email domain = self.create_domain(**fixture) self.delete('domains/%s' % domain.id, status_code=404) def test_get_domain_servers_from_secondary(self): fixture = self.get_domain_fixture('SECONDARY', 0) fixture['email'] = cfg.CONF['service:central'].managed_resource_email domain = self.create_domain(**fixture) self.get('domains/%s/servers' % domain.id, status_code=404)
class ApiV1DomainsTest(ApiV1Test): __test__ = True def test_create_domain(self): # Create a server self.create_server() # Create a domain fixture = self.get_domain_fixture(0) response = self.post('domains', data=fixture) self.assertIn('id', response.json) self.assertIn('name', response.json) self.assertEqual(response.json['name'], fixture['name']) @patch.object(central_service.Service, 'create_domain') def test_create_domain_trailing_slash(self, mock): # Create a server self.create_server() self.post('domains/', data=self.get_domain_fixture(0)) # verify that the central service is called self.assertTrue(mock.called) def test_create_domain_junk(self): # Create a server self.create_server() # Create a domain fixture = self.get_domain_fixture(0) # Add a junk property fixture['junk'] = 'Junk Field' # Ensure it fails with a 400 self.post('domains', data=fixture, status_code=400) def test_create_domain_no_servers(self): # Create a domain fixture = self.get_domain_fixture(0) self.post('domains', data=fixture, status_code=500) @patch.object(central_service.Service, 'create_domain', side_effect=rpc_common.Timeout()) def test_create_domain_timeout(self, _): # Create a domain fixture = self.get_domain_fixture(0) self.post('domains', data=fixture, status_code=504) @patch.object(central_service.Service, 'create_domain', side_effect=exceptions.DuplicateDomain()) def test_create_domain_duplicate(self, _): # Create a domain fixture = self.get_domain_fixture(0) self.post('domains', data=fixture, status_code=409) def test_create_domain_null_ttl(self): # Create a domain fixture = self.get_domain_fixture(0) fixture['ttl'] = None self.post('domains', data=fixture, status_code=400) def test_create_domain_negative_ttl(self): # Create a domain fixture = self.get_domain_fixture(0) fixture['ttl'] = -1 self.post('domains', data=fixture, status_code=400) def test_create_domain_utf_description(self): # Create a server self.create_server() # Create a domain fixture = self.get_domain_fixture(0) #Give it a UTF-8 filled description fixture['description'] = "utf-8:2H₂+O₂⇌2H₂O,R=4.7kΩ,⌀200mm∮E⋅da=Q,n" \ ",∑f(i)=∏g(i),∀x∈ℝ:⌈x⌉" #Create the domain, ensuring it suceeds, thus UTF-8 is supported self.post('domains', data=fixture) def test_create_domain_description_too_long(self): # Create a server self.create_server() # Create a domain fixture = self.get_domain_fixture(0) fixture['description'] = "x" * 161 #Create the domain, ensuring it fails with a 400 self.post('domains', data=fixture, status_code=400) def test_create_invalid_name(self): # Prepare a domain fixture = self.get_domain_fixture(0) invalid_names = [ 'org', 'example.org', 'example.321', ] for invalid_name in invalid_names: fixture['name'] = invalid_name # Create a record response = self.post('domains', data=fixture, status_code=400) self.assertNotIn('id', response.json) def test_create_invalid_email(self): # Prepare a domain fixture = self.get_domain_fixture(0) invalid_emails = [ 'org', 'example.org', 'bla.example.org', 'org.', 'example.org.', 'bla.example.org.', 'bla.example.org.', ] for invalid_email in invalid_emails: fixture['email'] = invalid_email # Create a record response = self.post('domains', data=fixture, status_code=400) self.assertNotIn('id', response.json) def test_get_domains(self): response = self.get('domains') self.assertIn('domains', response.json) self.assertEqual(0, len(response.json['domains'])) # Create a domain self.create_domain() response = self.get('domains') self.assertIn('domains', response.json) self.assertEqual(1, len(response.json['domains'])) # Create a second domain self.create_domain(fixture=1) response = self.get('domains') self.assertIn('domains', response.json) self.assertEqual(2, len(response.json['domains'])) @patch.object(central_service.Service, 'find_domains') def test_get_domains_trailing_slash(self, mock): self.get('domains/') # verify that the central service is called self.assertTrue(mock.called) @patch.object(central_service.Service, 'find_domains', side_effect=rpc_common.Timeout()) def test_get_domains_timeout(self, _): self.get('domains', status_code=504) def test_get_domain(self): # Create a domain domain = self.create_domain() response = self.get('domains/%s' % domain['id']) self.assertIn('id', response.json) self.assertEqual(response.json['id'], domain['id']) @patch.object(central_service.Service, 'get_domain') def test_get_domain_trailing_slash(self, mock): # Create a domain domain = self.create_domain() self.get('domains/%s/' % domain['id']) # verify that the central service is called self.assertTrue(mock.called) @patch.object(central_service.Service, 'get_domain', side_effect=rpc_common.Timeout()) def test_get_domain_timeout(self, _): # Create a domain domain = self.create_domain() self.get('domains/%s' % domain['id'], status_code=504) def test_get_domain_missing(self): self.get('domains/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', status_code=404) def test_get_domain_invalid_id(self): # The letter "G" is not valid in a UUID self.get('domains/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff9GG', status_code=404) self.get('domains/2fdadfb1cf964259ac6bbb7b6d2ff980', status_code=404) def test_update_domain(self): # Create a domain domain = self.create_domain() data = {'email': 'prefix-%s' % domain['email']} response = self.put('domains/%s' % domain['id'], data=data) self.assertIn('id', response.json) self.assertEqual(response.json['id'], domain['id']) self.assertIn('email', response.json) self.assertEqual(response.json['email'], 'prefix-%s' % domain['email']) @patch.object(central_service.Service, 'update_domain') def test_update_domain_trailing_slash(self, mock): # Create a domain domain = self.create_domain() data = {'email': 'prefix-%s' % domain['email']} self.put('domains/%s/' % domain['id'], data=data) # verify that the central service is called self.assertTrue(mock.called) def test_update_domain_junk(self): # Create a domain domain = self.create_domain() data = {'email': 'prefix-%s' % domain['email'], 'junk': 'Junk Field'} self.put('domains/%s' % domain['id'], data=data, status_code=400) def test_update_domain_name_fail(self): # Create a domain domain = self.create_domain() data = {'name': 'renamed.com.'} self.put('domains/%s' % domain['id'], data=data, status_code=400) def test_update_domain_null_ttl(self): # Create a domain domain = self.create_domain() data = {'ttl': None} self.put('domains/%s' % domain['id'], data=data, status_code=400) @patch.object(central_service.Service, 'update_domain', side_effect=rpc_common.Timeout()) def test_update_domain_timeout(self, _): # Create a domain domain = self.create_domain() data = {'email': 'prefix-%s' % domain['email']} self.put('domains/%s' % domain['id'], data=data, status_code=504) @patch.object(central_service.Service, 'update_domain', side_effect=exceptions.DuplicateDomain()) def test_update_domain_duplicate(self, _): # Create a domain domain = self.create_domain() data = {'email': 'prefix-%s' % domain['email']} self.put('domains/%s' % domain['id'], data=data, status_code=409) def test_update_domain_missing(self): data = {'email': '*****@*****.**'} self.put('domains/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', data=data, status_code=404) def test_update_domain_invalid_id(self): data = {'email': '*****@*****.**'} # The letter "G" is not valid in a UUID self.put('domains/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff9GG', data=data, status_code=404) self.put('domains/2fdadfb1cf964259ac6bbb7b6d2ff980', data=data, status_code=404) def test_delete_domain(self): # Create a domain domain = self.create_domain() self.delete('domains/%s' % domain['id']) # Esnure we can no longer fetch the domain self.get('domains/%s' % domain['id'], status_code=404) @patch.object(central_service.Service, 'delete_domain') def test_delete_domain_trailing_slash(self, mock): # Create a domain domain = self.create_domain() self.delete('domains/%s/' % domain['id']) # verify that the central service is called self.assertTrue(mock.called) @patch.object(central_service.Service, 'delete_domain', side_effect=rpc_common.Timeout()) def test_delete_domain_timeout(self, _): # Create a domain domain = self.create_domain() self.delete('domains/%s' % domain['id'], status_code=504) def test_delete_domain_missing(self): self.delete('domains/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', status_code=404) def test_delete_domain_invalid_id(self): # The letter "G" is not valid in a UUID self.delete('domains/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff9GG', status_code=404) self.delete('domains/2fdadfb1cf964259ac6bbb7b6d2ff980', status_code=404)
def get_response(self, request): raise exceptions.DuplicateDomain()
class ApiV2RecordSetsTest(ApiV2TestCase): def setUp(self): super(ApiV2RecordSetsTest, self).setUp() # Create a domain self.domain = self.create_domain() def test_create_recordset(self): # Create a zone fixture = self.get_recordset_fixture(self.domain['name'], fixture=0) response = self.client.post_json( '/zones/%s/recordsets' % self.domain['id'], {'recordset': fixture}) # Check the headers are what we expect self.assertEqual(201, response.status_int) self.assertEqual('application/json', response.content_type) # Check the body structure is what we expect self.assertIn('recordset', response.json) self.assertIn('links', response.json['recordset']) self.assertIn('self', response.json['recordset']['links']) # Check the values returned are what we expect self.assertIn('id', response.json['recordset']) self.assertIn('created_at', response.json['recordset']) self.assertIsNone(response.json['recordset']['updated_at']) for k in fixture: self.assertEqual(fixture[k], response.json['recordset'][k]) def test_create_recordset_validation(self): # NOTE: The schemas should be tested separatly to the API. So we # don't need to test every variation via the API itself. # Fetch a fixture fixture = self.get_recordset_fixture(self.domain['name'], fixture=0) # Add a junk field to the wrapper body = {'recordset': fixture, 'junk': 'Junk Field'} # Ensure it fails with a 400 response = self.client.post_json('/zones/%s/recordsets' % self.domain['id'], body, status=400) self.assertEqual(400, response.status_int) # Add a junk field to the body fixture['junk'] = 'Junk Field' body = {'recordset': fixture} # Ensure it fails with a 400 response = self.client.post_json('/zones/%s/recordsets' % self.domain['id'], body, status=400) @patch.object(central_service.Service, 'create_recordset', side_effect=rpc_common.Timeout()) def test_create_recordset_timeout(self, _): fixture = self.get_recordset_fixture(self.domain['name'], fixture=0) body = {'recordset': fixture} self.client.post_json('/zones/%s/recordsets' % self.domain['id'], body, status=504) @patch.object(central_service.Service, 'create_recordset', side_effect=exceptions.DuplicateDomain()) def test_create_recordset_duplicate(self, _): fixture = self.get_recordset_fixture(self.domain['name'], fixture=0) body = {'recordset': fixture} self.client.post_json('/zones/%s/recordsets' % self.domain['id'], body, status=409) def test_create_recordset_invalid_domain(self): fixture = self.get_recordset_fixture(self.domain['name'], fixture=0) body = {'recordset': fixture} self.client.post_json( '/zones/ba751950-6193-11e3-949a-0800200c9a66/recordsets', body, status=404) def test_get_recordsets(self): response = self.client.get('/zones/%s/recordsets' % self.domain['id']) # Check the headers are what we expect self.assertEqual(200, response.status_int) self.assertEqual('application/json', response.content_type) # Check the body structure is what we expect self.assertIn('recordsets', response.json) self.assertIn('links', response.json) self.assertIn('self', response.json['links']) # We should start with 0 recordsets self.assertEqual(0, len(response.json['recordsets'])) data = [ self.create_recordset(self.domain, name='x-%s.%s' % (i, self.domain['name'])) for i in xrange(0, 10) ] url = '/zones/%s/recordsets' % self.domain['id'] self._assert_paging(data, url, key='recordsets') @patch.object(central_service.Service, 'find_recordsets', side_effect=rpc_common.Timeout()) def test_get_recordsets_timeout(self, _): self.client.get( '/zones/ba751950-6193-11e3-949a-0800200c9a66/recordsets', status=504) def test_get_recordset(self): # Create a recordset recordset = self.create_recordset(self.domain) url = '/zones/%s/recordsets/%s' % (self.domain['id'], recordset['id']) response = self.client.get(url) # Check the headers are what we expect self.assertEqual(200, response.status_int) self.assertEqual('application/json', response.content_type) # Check the body structure is what we expect self.assertIn('recordset', response.json) self.assertIn('links', response.json['recordset']) self.assertIn('self', response.json['recordset']['links']) # Check the values returned are what we expect self.assertIn('id', response.json['recordset']) self.assertIn('created_at', response.json['recordset']) self.assertIsNone(response.json['recordset']['updated_at']) self.assertEqual(recordset['name'], response.json['recordset']['name']) self.assertEqual(recordset['type'], response.json['recordset']['type']) @patch.object(central_service.Service, 'get_recordset', side_effect=rpc_common.Timeout()) def test_get_recordset_timeout(self, _): self.client.get('/zones/%s/recordsets/ba751950-6193-11e3-949a-0800200c' '9a66' % self.domain['id'], headers={'Accept': 'application/json'}, status=504) @patch.object(central_service.Service, 'get_recordset', side_effect=exceptions.RecordSetNotFound()) def test_get_recordset_missing(self, _): self.client.get('/zones/%s/recordsets/ba751950-6193-11e3-949a-0800200c' '9a66' % self.domain['id'], headers={'Accept': 'application/json'}, status=404) def test_get_recordset_invalid_id(self): self.skip('We don\'t guard against this in APIv2 yet') def test_update_recordset(self): # Create a recordset recordset = self.create_recordset(self.domain) # Prepare an update body body = {'recordset': {'description': 'Tester'}} url = '/zones/%s/recordsets/%s' % (recordset['domain_id'], recordset['id']) response = self.client.patch_json(url, body, status=200) # Check the headers are what we expect self.assertEqual(200, response.status_int) self.assertEqual('application/json', response.content_type) # Check the body structure is what we expect self.assertIn('recordset', response.json) self.assertIn('links', response.json['recordset']) self.assertIn('self', response.json['recordset']['links']) # Check the values returned are what we expect self.assertIn('id', response.json['recordset']) self.assertIsNotNone(response.json['recordset']['updated_at']) self.assertEqual('Tester', response.json['recordset']['description']) def test_update_recordset_validation(self): # NOTE: The schemas should be tested separatly to the API. So we # don't need to test every variation via the API itself. # Create a zone recordset = self.create_recordset(self.domain) # Prepare an update body with junk in the wrapper body = {'recordset': {'description': 'Tester'}, 'junk': 'Junk Field'} # Ensure it fails with a 400 url = '/zones/%s/recordsets/%s' % (recordset['domain_id'], recordset['id']) self.client.patch_json(url, body, status=400) # Prepare an update body with junk in the body body = {'recordset': {'description': 'Tester', 'junk': 'Junk Field'}} # Ensure it fails with a 400 url = '/zones/%s/recordsets/%s' % (recordset['domain_id'], recordset['id']) self.client.patch_json(url, body, status=400) @patch.object(central_service.Service, 'get_recordset', side_effect=exceptions.DuplicateRecordSet()) def test_update_recordset_duplicate(self, _): # Prepare an update body body = {'recordset': {'description': 'Tester'}} # Ensure it fails with a 409 url = ('/zones/%s/recordsets/ba751950-6193-11e3-949a-0800200c9a66' % (self.domain['id'])) self.client.patch_json(url, body, status=409) @patch.object(central_service.Service, 'get_recordset', side_effect=rpc_common.Timeout()) def test_update_recordset_timeout(self, _): # Prepare an update body body = {'recordset': {'description': 'Tester'}} # Ensure it fails with a 504 url = ('/zones/%s/recordsets/ba751950-6193-11e3-949a-0800200c9a66' % (self.domain['id'])) self.client.patch_json(url, body, status=504) @patch.object(central_service.Service, 'get_recordset', side_effect=exceptions.RecordSetNotFound()) def test_update_recordset_missing(self, _): # Prepare an update body body = {'recordset': {'description': 'Tester'}} # Ensure it fails with a 404 url = ('/zones/%s/recordsets/ba751950-6193-11e3-949a-0800200c9a66' % (self.domain['id'])) self.client.patch_json(url, body, status=404) def test_update_recordset_invalid_id(self): self.skip('We don\'t guard against this in APIv2 yet') def test_delete_recordset(self): recordset = self.create_recordset(self.domain) url = '/zones/%s/recordsets/%s' % (recordset['domain_id'], recordset['id']) self.client.delete(url, status=204) @patch.object(central_service.Service, 'delete_recordset', side_effect=rpc_common.Timeout()) def test_delete_recordset_timeout(self, _): url = ('/zones/%s/recordsets/ba751950-6193-11e3-949a-0800200c9a66' % (self.domain['id'])) self.client.delete(url, status=504) @patch.object(central_service.Service, 'delete_recordset', side_effect=exceptions.RecordSetNotFound()) def test_delete_recordset_missing(self, _): url = ('/zones/%s/recordsets/ba751950-6193-11e3-949a-0800200c9a66' % (self.domain['id'])) self.client.delete(url, status=404) def test_delete_recordset_invalid_id(self): self.skip('We don\'t guard against this in APIv2 yet')
class ApiV2ZonesTest(ApiV2TestCase): def setUp(self): super(ApiV2ZonesTest, self).setUp() # Create a server self.create_server() # Create the default TLDs self.create_default_tlds() def test_create_zone(self): # Create a zone fixture = self.get_domain_fixture(0) response = self.client.post_json('/zones/', {'zone': fixture}) # Check the headers are what we expect self.assertEqual(201, response.status_int) self.assertEqual('application/json', response.content_type) # Check the body structure is what we expect self.assertIn('zone', response.json) self.assertIn('links', response.json['zone']) self.assertIn('self', response.json['zone']['links']) # Check the values returned are what we expect self.assertIn('id', response.json['zone']) self.assertIn('created_at', response.json['zone']) self.assertEqual('ACTIVE', response.json['zone']['status']) self.assertIsNone(response.json['zone']['updated_at']) for k in fixture: self.assertEqual(fixture[k], response.json['zone'][k]) def test_create_zone_validation(self): # NOTE: The schemas should be tested separately to the API. So we # don't need to test every variation via the API itself. # Fetch a fixture fixture = self.get_domain_fixture(0) # Add a junk field to the wrapper body = {'zone': fixture, 'junk': 'Junk Field'} # Ensure it fails with a 400 self._assert_exception('invalid_object', 400, self.client.post_json, '/zones', body) # Add a junk field to the body fixture['junk'] = 'Junk Field' # Ensure it fails with a 400 body = {'zone': fixture} self._assert_exception('invalid_object', 400, self.client.post_json, '/zones', body) def test_create_zone_body_validation(self): fixture = self.get_domain_fixture(0) # Add id to the body fixture['id'] = '2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980' # Ensure it fails with a 400 body = {'zone': fixture} self._assert_exception('invalid_object', 400, self.client.post_json, '/zones', body) fixture = self.get_domain_fixture(0) # Add created_at to the body fixture['created_at'] = '2014-03-12T19:07:53.000000' # Ensure it fails with a 400 body = {'zone': fixture} self._assert_exception('invalid_object', 400, self.client.post_json, '/zones', body) def test_create_zone_invalid_name(self): # Try to create a zone with an invalid name fixture = self.get_domain_fixture(-1) # Ensure it fails with a 400 self._assert_exception('invalid_object', 400, self.client.post_json, '/zones', {'zone': fixture}) @patch.object(central_service.Service, 'create_domain', side_effect=messaging.MessagingTimeout()) def test_create_zone_timeout(self, _): fixture = self.get_domain_fixture(0) body = {'zone': fixture} self._assert_exception('timeout', 504, self.client.post_json, '/zones/', body) @patch.object(central_service.Service, 'create_domain', side_effect=exceptions.DuplicateDomain()) def test_create_zone_duplicate(self, _): fixture = self.get_domain_fixture(0) body = {'zone': fixture} self._assert_exception('duplicate_domain', 409, self.client.post_json, '/zones/', body) def test_create_zone_missing_content_type(self): self._assert_exception('unsupported_content_type', 415, self.client.post, '/zones') def test_create_zone_bad_content_type(self): self._assert_exception('unsupported_content_type', 415, self.client.post, '/zones', headers={'Content-type': 'test/goat'}) def test_zone_invalid_url(self): url = '/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980/invalid' self._assert_exception('not_found', 404, self.client.get, url, headers={'Accept': 'application/json'}) self._assert_exception('not_found', 404, self.client.patch_json, url) self._assert_exception('not_found', 404, self.client.delete, url) # Pecan returns a 405 for post response = self.client.post(url, status=405) self.assertEqual(405, response.status_int) def test_get_zones(self): response = self.client.get('/zones/') # Check the headers are what we expect self.assertEqual(200, response.status_int) self.assertEqual('application/json', response.content_type) # Check the body structure is what we expect self.assertIn('zones', response.json) self.assertIn('links', response.json) self.assertIn('self', response.json['links']) # We should start with 0 zones self.assertEqual(0, len(response.json['zones'])) # We should start with 0 zones self.assertEqual(0, len(response.json['zones'])) data = [self.create_domain(name='x-%s.com.' % i) for i in 'abcdefghij'] self._assert_paging(data, '/zones', key='zones') self._assert_invalid_paging(data, '/zones', key='zones') @patch.object(central_service.Service, 'find_domains', side_effect=messaging.MessagingTimeout()) def test_get_zones_timeout(self, _): self._assert_exception('timeout', 504, self.client.get, '/zones/') def test_get_zone(self): # Create a zone zone = self.create_domain() response = self.client.get('/zones/%s' % zone['id'], headers=[('Accept', 'application/json')]) # Check the headers are what we expect self.assertEqual(200, response.status_int) self.assertEqual('application/json', response.content_type) # Check the body structure is what we expect self.assertIn('zone', response.json) self.assertIn('links', response.json['zone']) self.assertIn('self', response.json['zone']['links']) # Check the values returned are what we expect self.assertIn('id', response.json['zone']) self.assertIn('created_at', response.json['zone']) self.assertEqual('ACTIVE', response.json['zone']['status']) self.assertIsNone(response.json['zone']['updated_at']) self.assertEqual(zone['name'], response.json['zone']['name']) self.assertEqual(zone['email'], response.json['zone']['email']) def test_get_zone_invalid_id(self): self._assert_invalid_uuid(self.client.get, '/zones/%s') @patch.object(central_service.Service, 'get_domain', side_effect=messaging.MessagingTimeout()) def test_get_zone_timeout(self, _): url = '/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980' self._assert_exception('timeout', 504, self.client.get, url, headers={'Accept': 'application/json'}) @patch.object(central_service.Service, 'get_domain', side_effect=exceptions.DomainNotFound()) def test_get_zone_missing(self, _): url = '/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980' self._assert_exception('domain_not_found', 404, self.client.get, url, headers={'Accept': 'application/json'}) def test_get_zone_missing_accept(self): url = '/zones/6e2146f3-87bc-4f47-adc5-4df0a5c78218' self._assert_exception('bad_request', 400, self.client.get, url) def test_get_zone_bad_accept(self): url = '/zones/6e2146f3-87bc-4f47-adc5-4df0a5c78218' self.client.get(url, headers={'Accept': 'test/goat'}, status=406) def test_update_zone(self): # Create a zone zone = self.create_domain() # Prepare an update body body = {'zone': {'email': 'prefix-%s' % zone['email']}} response = self.client.patch_json('/zones/%s' % zone['id'], body, status=200) # Check the headers are what we expect self.assertEqual(200, response.status_int) self.assertEqual('application/json', response.content_type) # Check the body structure is what we expect self.assertIn('zone', response.json) self.assertIn('links', response.json['zone']) self.assertIn('self', response.json['zone']['links']) self.assertIn('status', response.json['zone']) # Check the values returned are what we expect self.assertIn('id', response.json['zone']) self.assertIsNotNone(response.json['zone']['updated_at']) self.assertEqual('prefix-%s' % zone['email'], response.json['zone']['email']) def test_update_zone_invalid_id(self): self._assert_invalid_uuid(self.client.patch_json, '/zones/%s') def test_update_zone_validation(self): # NOTE: The schemas should be tested separatly to the API. So we # don't need to test every variation via the API itself. # Create a zone zone = self.create_domain() # Prepare an update body with junk in the wrapper body = { 'zone': { 'email': 'prefix-%s' % zone['email'] }, 'junk': 'Junk Field' } url = '/zones/%s' % zone['id'] # Ensure it fails with a 400 self._assert_exception('invalid_object', 400, self.client.patch_json, url, body) # Prepare an update body with junk in the body body = { 'zone': { 'email': 'prefix-%s' % zone['email'], 'junk': 'Junk Field' } } # Ensure it fails with a 400 self._assert_exception('invalid_object', 400, self.client.patch_json, url, body) @patch.object(central_service.Service, 'get_domain', side_effect=exceptions.DuplicateDomain()) def test_update_zone_duplicate(self, _): # Prepare an update body body = {'zone': {'email': '*****@*****.**'}} url = '/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980' # Ensure it fails with a 409 self._assert_exception('duplicate_domain', 409, self.client.patch_json, url, body) @patch.object(central_service.Service, 'get_domain', side_effect=messaging.MessagingTimeout()) def test_update_zone_timeout(self, _): # Prepare an update body body = {'zone': {'email': '*****@*****.**'}} url = '/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980' # Ensure it fails with a 504 self._assert_exception('timeout', 504, self.client.patch_json, url, body) @patch.object(central_service.Service, 'get_domain', side_effect=exceptions.DomainNotFound()) def test_update_zone_missing(self, _): # Prepare an update body body = {'zone': {'email': '*****@*****.**'}} url = '/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980' # Ensure it fails with a 404 self._assert_exception('domain_not_found', 404, self.client.patch_json, url, body) def test_delete_zone(self): zone = self.create_domain() self.client.delete('/zones/%s' % zone['id'], status=204) def test_delete_zone_invalid_id(self): self._assert_invalid_uuid(self.client.delete, '/zones/%s') @patch.object(central_service.Service, 'delete_domain', side_effect=messaging.MessagingTimeout()) def test_delete_zone_timeout(self, _): url = '/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980' self._assert_exception('timeout', 504, self.client.delete, url) @patch.object(central_service.Service, 'delete_domain', side_effect=exceptions.DomainNotFound()) def test_delete_zone_missing(self, _): url = '/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980' self._assert_exception('domain_not_found', 404, self.client.delete, url) # Zone import/export def test_missing_origin(self): fixture = self.get_zonefile_fixture(variant='noorigin') self._assert_exception('bad_request', 400, self.client.post, '/zones', fixture, headers={'Content-type': 'text/dns'}) def test_missing_soa(self): fixture = self.get_zonefile_fixture(variant='nosoa') self._assert_exception('bad_request', 400, self.client.post, '/zones', fixture, headers={'Content-type': 'text/dns'}) def test_malformed_zonefile(self): fixture = self.get_zonefile_fixture(variant='malformed') self._assert_exception('bad_request', 400, self.client.post, '/zones', fixture, headers={'Content-type': 'text/dns'}) def test_import_export(self): # Since v2 doesn't support getting records, import and export the # fixture, making sure they're the same according to dnspython post_response = self.client.post('/zones', self.get_zonefile_fixture(), headers={'Content-type': 'text/dns'}) get_response = self.client.get('/zones/%s' % post_response.json['zone']['id'], headers={'Accept': 'text/dns'}) exported_zonefile = get_response.body imported = dnszone.from_text(self.get_zonefile_fixture()) exported = dnszone.from_text(exported_zonefile) # Compare SOA emails, since zone comparison takes care of origin imported_soa = imported.get_rdataset(imported.origin, 'SOA') imported_email = imported_soa[0].rname.to_text() exported_soa = exported.get_rdataset(exported.origin, 'SOA') exported_email = exported_soa[0].rname.to_text() self.assertEqual(imported_email, exported_email) # Delete SOAs since they have, at the very least, different serials, # and dnspython considers that to be not equal. imported.delete_rdataset(imported.origin, 'SOA') exported.delete_rdataset(exported.origin, 'SOA') # Delete non-delegation NS, since they won't be the same imported.delete_rdataset(imported.origin, 'NS') exported.delete_rdataset(exported.origin, 'NS') self.assertEqual(imported, exported)