class SchedulerClientTestCase(test.TestCase): def setUp(self): super(SchedulerClientTestCase, self).setUp() self.client = scheduler_client.SchedulerClient() def test_constructor(self): self.assertIsNotNone(self.client.queryclient) self.assertIsNotNone(self.client.reportclient) @mock.patch.object(scheduler_query_client.SchedulerQueryClient, 'select_destinations') def test_select_destinations(self, mock_select_destinations): self.assertIsNone(self.client.queryclient.instance) self.client.select_destinations('ctxt', 'fake_spec', 'fake_prop') self.assertIsNotNone(self.client.queryclient.instance) mock_select_destinations.assert_called_once_with( 'ctxt', 'fake_spec', 'fake_prop') @mock.patch.object(scheduler_query_client.SchedulerQueryClient, 'select_destinations', side_effect=messaging.MessagingTimeout()) def test_select_destinations_timeout(self, mock_select_destinations): # check if the scheduler service times out properly fake_args = ['ctxt', 'fake_spec', 'fake_prop'] self.assertRaises(messaging.MessagingTimeout, self.client.select_destinations, *fake_args) mock_select_destinations.assert_has_calls([mock.call(*fake_args)] * 2) @mock.patch.object( scheduler_query_client.SchedulerQueryClient, 'select_destinations', side_effect=[messaging.MessagingTimeout(), mock.DEFAULT]) def test_select_destinations_timeout_once(self, mock_select_destinations): # scenario: the scheduler service times out & recovers after failure fake_args = ['ctxt', 'fake_spec', 'fake_prop'] self.client.select_destinations(*fake_args) mock_select_destinations.assert_has_calls([mock.call(*fake_args)] * 2) @mock.patch.object(scheduler_report_client.SchedulerReportClient, 'update_resource_stats') def test_update_resource_stats(self, mock_update_resource_stats): self.assertIsNone(self.client.reportclient.instance) self.client.update_resource_stats('ctxt', 'fake_name', 'fake_stats') self.assertIsNotNone(self.client.reportclient.instance) mock_update_resource_stats.assert_called_once_with( 'ctxt', 'fake_name', 'fake_stats')
def _get_single_host(): hosts = self.get_hosts(target) try: if not hosts: err_msg = "No hosts were found for target %s." % target LOG.error(err_msg) raise oslo_messaging.InvalidTarget(err_msg, target) if len(hosts) == 1: host = hosts[0] LOG.info(_LI( "A single host %(host)s found for target %(target)s.") % {"host": host, "target": target}) else: host = random.choice(hosts) LOG.warning(_LW( "Multiple hosts %(hosts)s were found for target " " %(target)s. Using the random one - %(host)s.") % {"hosts": hosts, "target": target, "host": host}) return host except oslo_messaging.InvalidTarget as ex: if timeout: raise oslo_messaging.MessagingTimeout() else: raise ex
def _send(self, target, ctxt, message, wait_for_reply=None, timeout=None): self._check_serialize(message) exchange = self._exchange_manager.get_exchange(target.exchange) reply_q = None if wait_for_reply: reply_q = moves.queue.Queue() exchange.deliver_message(target.topic, ctxt, message, server=target.server, fanout=target.fanout, reply_q=reply_q) if wait_for_reply: try: reply, failure = reply_q.get(timeout=timeout) if failure: raise failure else: return reply except moves.queue.Empty: raise oslo_messaging.MessagingTimeout( 'No reply on topic %s' % target.topic) return None
def get(self, msg_id, timeout): try: return self._queues[msg_id].get(block=True, timeout=timeout) except moves.queue.Empty: raise oslo_messaging.MessagingTimeout( 'Timed out waiting for a reply ' 'to message ID %s' % msg_id)
def test_get_status_not_ok_timeout(self): with mock.patch('pecan.request') as request: client = mock.Mock() client.call.side_effect = oslo_messaging.MessagingTimeout() request.client.prepare.return_value = client resp = self.get_json('/status/', expect_errors=True) self.assertEqual(503, resp.status_code) self.assertIn('vitrage-graph is not available', resp.text)
def get_reply(self, timeout): """Retrieve the reply.""" if not self._reply_queue: return None try: return self._reply_queue.get(timeout=timeout) except moves.queue.Empty: raise oslo_messaging.MessagingTimeout( 'Timed out waiting for a reply')
def test_engine_alive_timeout(self): slock = stack_lock.StackLock(self.context, self.stack, self.engine_id) mget_client = self.patchobject(stack_lock.rpc_messaging, 'get_rpc_client') mclient = mget_client.return_value mclient_ctx = mclient.prepare.return_value mclient_ctx.call.side_effect = messaging.MessagingTimeout('too slow') ret = slock.engine_alive(self.context, self.engine_id) self.assertIs(False, ret) mclient.prepare.assert_called_once_with(timeout=2) mclient_ctx.call.assert_called_once_with(self.context, 'listening')
def test_conductor_alive_timeout(self, mock_listener_api_new): mock_listener_api = mock.MagicMock() mock_listener_api.ping_conductor.side_effect = ( messaging.MessagingTimeout('too slow')) mock_listener_api_new.return_value = mock_listener_api baylock = bay_lock.BayLock(self.context, self.bay, self.conductor_id) ret = baylock.conductor_alive(self.context, self.conductor_id) self.assertIs(False, ret) self.assertEqual(1, mock_listener_api_new.call_count)
def send_request(self, request): reply_future = self.sender.send_request(request) try: reply = reply_future.result(timeout=request.timeout) except futures.TimeoutError: raise oslo_messaging.MessagingTimeout( "Timeout %s seconds was reached" % request.timeout) finally: self.reply_waiter.untrack_id(request.message_id) LOG.debug("Received reply %s", reply) if reply[zmq_names.FIELD_FAILURE]: raise rpc_common.deserialize_remote_exception( reply[zmq_names.FIELD_FAILURE], request.allowed_remote_exmods) else: return reply[zmq_names.FIELD_REPLY]
def _receive_reply(socket, request): def _receive_method(socket): return socket.recv_pyobj() # NOTE(ozamiatin): Check for retry here (no retries now) with contextlib.closing(zmq_async.get_reply_poller()) as poller: poller.register(socket, recv_method=_receive_method) reply, socket = poller.poll(timeout=request.timeout) if reply is None: raise oslo_messaging.MessagingTimeout( "Timeout %s seconds was reached" % request.timeout) if reply[zmq_names.FIELD_FAILURE]: raise rpc_common.deserialize_remote_exception( reply[zmq_names.FIELD_FAILURE], request.allowed_remote_exmods) else: return reply[zmq_names.FIELD_REPLY]
def test_get_dvr_mac_address_retried(self): valid_entry = {'host': 'cn1', 'mac_address': 'aa:22:33:44:55:66'} raise_timeout = oslo_messaging.MessagingTimeout() # Raise a timeout the first 2 times it calls get_dvr_mac_address() self._setup_for_dvr_test() self.agent.dvr_agent.dvr_mac_address = None with mock.patch.object(self.agent.dvr_agent.plugin_rpc, 'get_dvr_mac_address_by_host', side_effect=(raise_timeout, raise_timeout, valid_entry)): self.agent.dvr_agent.get_dvr_mac_address() self.assertEqual('aa:22:33:44:55:66', self.agent.dvr_agent.dvr_mac_address) self.assertTrue(self.agent.dvr_agent.in_distributed_mode()) self.assertEqual( self.agent.dvr_agent.plugin_rpc.get_dvr_mac_address_by_host. call_count, 3)
def test_get_dvr_mac_address_retried_max(self): raise_timeout = oslo_messaging.MessagingTimeout() # Raise a timeout every time until we give up, currently 5 tries self._setup_for_dvr_test() self.agent.dvr_agent.dvr_mac_address = None with contextlib.nested( mock.patch.object(self.agent.dvr_agent.plugin_rpc, 'get_dvr_mac_address_by_host', side_effect=raise_timeout), mock.patch.object(utils, "execute"), ) as (rpc_mock, execute_mock): self.agent.dvr_agent.get_dvr_mac_address() self.assertIsNone(self.agent.dvr_agent.dvr_mac_address) self.assertFalse(self.agent.dvr_agent.in_distributed_mode()) self.assertEqual( self.agent.dvr_agent.plugin_rpc.get_dvr_mac_address_by_host. call_count, 5)
def test_engine_alive_timeout(self, rpc_client_method): mock_rpc_client = rpc_client_method.return_value mock_prepare_method = mock_rpc_client.prepare mock_prepare_client = mock_prepare_method.return_value mock_cnxt = mock.Mock() listener_client = rpc_client.EngineListenerClient('engine-007') rpc_client_method.assert_called_once_with( version=rpc_client.EngineListenerClient.BASE_RPC_API_VERSION, topic=rpc_api.LISTENER_TOPIC, server='engine-007', ) mock_prepare_method.assert_called_once_with(timeout=2) self.assertEqual(mock_prepare_client, listener_client._client, "Failed to create RPC client") mock_prepare_client.call.side_effect = messaging.MessagingTimeout( 'too slow') ret = listener_client.is_alive(mock_cnxt) self.assertFalse(ret) mock_prepare_client.call.assert_called_once_with( mock_cnxt, 'listening')
def send_request(self, request): reply_future = self.sender.send_request(request) try: reply = reply_future.result(timeout=request.timeout) LOG.debug("Received reply %s", request.message_id) except AssertionError: LOG.error(_LE("Message format error in reply %s"), request.message_id) return None except futures.TimeoutError: raise oslo_messaging.MessagingTimeout( "Timeout %(tout)s seconds was reached for message %(id)s" % { "tout": request.timeout, "id": request.message_id }) finally: self.reply_waiter.untrack_id(request.message_id) if reply.failure: raise rpc_common.deserialize_remote_exception( reply.failure, request.allowed_remote_exmods) else: return reply.reply_body
def _raise_timeout_exception(msg_id): raise oslo_messaging.MessagingTimeout( _('Timed out waiting for a reply to message ID %s.') % msg_id)
class SchedulerClientTestCase(test.NoDBTestCase): def setUp(self): super(SchedulerClientTestCase, self).setUp() self.client = scheduler_client.SchedulerClient() def test_constructor(self): self.assertIsNotNone(self.client.queryclient) self.assertIsNotNone(self.client.reportclient) @mock.patch.object(scheduler_query_client.SchedulerQueryClient, 'select_destinations') def test_select_destinations(self, mock_select_destinations): fake_spec = objects.RequestSpec() fake_spec.instance_uuid = uuids.instance self.client.select_destinations('ctxt', fake_spec, [fake_spec.instance_uuid]) mock_select_destinations.assert_called_once_with('ctxt', fake_spec, [fake_spec.instance_uuid], False, False) @mock.patch.object(scheduler_query_client.SchedulerQueryClient, 'select_destinations', side_effect=messaging.MessagingTimeout()) def test_select_destinations_timeout(self, mock_select_destinations): # check if the scheduler service times out properly fake_spec = objects.RequestSpec() fake_spec.instance_uuid = uuids.instance fake_args = ['ctxt', fake_spec, [fake_spec.instance_uuid], False, False] self.assertRaises(messaging.MessagingTimeout, self.client.select_destinations, *fake_args) mock_select_destinations.assert_has_calls([mock.call(*fake_args)] * 2) @mock.patch.object(scheduler_query_client.SchedulerQueryClient, 'select_destinations', side_effect=[ messaging.MessagingTimeout(), mock.DEFAULT]) def test_select_destinations_timeout_once(self, mock_select_destinations): # scenario: the scheduler service times out & recovers after failure fake_spec = objects.RequestSpec() fake_spec.instance_uuid = uuids.instance fake_args = ['ctxt', fake_spec, [fake_spec.instance_uuid], False, False] self.client.select_destinations(*fake_args) mock_select_destinations.assert_has_calls([mock.call(*fake_args)] * 2) @mock.patch.object(scheduler_query_client.SchedulerQueryClient, 'update_aggregates') def test_update_aggregates(self, mock_update_aggs): aggregates = [objects.Aggregate(id=1)] self.client.update_aggregates( context='context', aggregates=aggregates) mock_update_aggs.assert_called_once_with( 'context', aggregates) @mock.patch.object(scheduler_query_client.SchedulerQueryClient, 'delete_aggregate') def test_delete_aggregate(self, mock_delete_agg): aggregate = objects.Aggregate(id=1) self.client.delete_aggregate( context='context', aggregate=aggregate) mock_delete_agg.assert_called_once_with( 'context', aggregate) @mock.patch.object(scheduler_report_client.SchedulerReportClient, 'update_compute_node') def test_update_compute_node(self, mock_update_compute_node): self.client.update_compute_node(mock.sentinel.ctx, mock.sentinel.cn) mock_update_compute_node.assert_called_once_with( mock.sentinel.ctx, mock.sentinel.cn) @mock.patch.object(scheduler_report_client.SchedulerReportClient, 'set_inventory_for_provider') def test_set_inventory_for_provider(self, mock_set): self.client.set_inventory_for_provider( mock.sentinel.ctx, mock.sentinel.rp_uuid, mock.sentinel.rp_name, mock.sentinel.inv_data, ) mock_set.assert_called_once_with( mock.sentinel.ctx, mock.sentinel.rp_uuid, mock.sentinel.rp_name, mock.sentinel.inv_data, parent_provider_uuid=None, ) # Pass the optional parent_provider_uuid mock_set.reset_mock() self.client.set_inventory_for_provider( mock.sentinel.ctx, mock.sentinel.child_uuid, mock.sentinel.child_name, mock.sentinel.inv_data2, parent_provider_uuid=mock.sentinel.rp_uuid, ) mock_set.assert_called_once_with( mock.sentinel.ctx, mock.sentinel.child_uuid, mock.sentinel.child_name, mock.sentinel.inv_data2, parent_provider_uuid=mock.sentinel.rp_uuid, )
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])
def _raise_timeout(request): raise oslo_messaging.MessagingTimeout( "Timeout %(tout)s seconds was reached for message %(msg_id)s" % { "tout": request.timeout, "msg_id": request.message_id })
class ApiV2TsigKeysTest(ApiV2TestCase): def setUp(self): super(ApiV2TsigKeysTest, self).setUp() # Set the policy to accept everyone as an admin, as this is an # admin-only API self.policy({'admin': '@'}) def test_create_tsigkey(self): # Create a TSIG Key fixture = self.get_tsigkey_fixture(0) response = self.client.post_json('/tsigkeys/', 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('links', response.json) self.assertIn('self', response.json['links']) # Check the generated values returned are what we expect self.assertIn('id', response.json) self.assertIn('created_at', response.json) self.assertIsNone(response.json['updated_at']) # Check the supplied values returned are what we expect self.assertDictContainsSubset(fixture, response.json) def test_create_tsigkey_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_tsigkey_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, '/tsigkeys', body) def test_create_tsigkey_duplicate(self): # Prepare a TSIG Key fixture fixture = self.get_tsigkey_fixture(0) body = fixture # Create the first TSIG Key response = self.client.post_json('/tsigkeys', body) self.assertEqual(201, response.status_int) self._assert_exception('duplicate_tsigkey', 409, self.client.post_json, '/tsigkeys', body) def test_get_tsigkeys(self): response = self.client.get('/tsigkeys/') # 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('tsigkeys', response.json) self.assertIn('links', response.json) self.assertIn('self', response.json['links']) # We should start with 0 tsigkeys self.assertEqual(0, len(response.json['tsigkeys'])) data = [self.create_tsigkey(name='tsigkey-%s' % i) for i in range(1, 10)] self._assert_paging(data, '/tsigkeys', key='tsigkeys') self._assert_invalid_paging(data, '/tsigkeys', key='tsigkeys') @patch.object(central_service.Service, 'find_tsigkeys', side_effect=messaging.MessagingTimeout()) def test_get_tsigkeys_timeout(self, _): self._assert_exception('timeout', 504, self.client.get, '/tsigkeys/') def test_get_tsigkey(self): # Create a tsigkey tsigkey = self.create_tsigkey() response = self.client.get('/tsigkeys/%s' % tsigkey.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 generated values returned are what we expect self.assertIn('id', response.json) self.assertIn('created_at', response.json) self.assertIsNone(response.json['updated_at']) # Check the supplied values returned are what we expect self.assertEqual(tsigkey.name, response.json['name']) self.assertEqual( tsigkey.algorithm, response.json['algorithm']) self.assertEqual(tsigkey.secret, response.json['secret']) self.assertEqual(tsigkey.scope, response.json['scope']) self.assertEqual( tsigkey.resource_id, response.json['resource_id']) def test_get_tsigkey_invalid_id(self): self._assert_invalid_uuid(self.client.get, '/tsigkeys/%s') @patch.object(central_service.Service, 'get_tsigkey', side_effect=messaging.MessagingTimeout()) def test_get_tsigkey_timeout(self, _): url = '/tsigkeys/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980' self._assert_exception('timeout', 504, self.client.get, url, headers={'Accept': 'application/json'}) @patch.object(central_service.Service, 'get_tsigkey', side_effect=exceptions.TsigKeyNotFound()) def test_get_tsigkey_missing(self, _): url = '/tsigkeys/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980' self._assert_exception('tsigkey_not_found', 404, self.client.get, url, headers={'Accept': 'application/json'}) def test_update_tsigkey(self): # Create a TSIG Key tsigkey = self.create_tsigkey() # Prepare an update body body = {'secret': 'prefix-%s' % tsigkey.secret} response = self.client.patch_json('/tsigkeys/%s' % tsigkey.id, body) # 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.assertIsNotNone(response.json['updated_at']) self.assertEqual('prefix-%s' % tsigkey['secret'], response.json['secret']) def test_update_tsigkey_invalid_id(self): self._assert_invalid_uuid(self.client.patch_json, '/tsigkeys/%s') @patch.object(central_service.Service, 'get_tsigkey', side_effect=exceptions.DuplicateTsigKey()) def test_update_tsigkey_duplicate(self, _): # Prepare an update body body = {'name': 'AnyOldName'} url = '/tsigkeys/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980' # Ensure it fails with a 409 self._assert_exception('duplicate_tsigkey', 409, self.client.patch_json, url, body) @patch.object(central_service.Service, 'get_tsigkey', side_effect=messaging.MessagingTimeout()) def test_update_tsigkey_timeout(self, _): # Prepare an update body body = {'name': 'AnyOldName'} url = '/tsigkeys/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_tsigkey', side_effect=exceptions.TsigKeyNotFound()) def test_update_tsigkey_missing(self, _): # Prepare an update body body = {'name': 'AnyOldName'} url = '/tsigkeys/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980' # Ensure it fails with a 404 self._assert_exception('tsigkey_not_found', 404, self.client.patch_json, url, body) def test_delete_tsigkey(self): tsigkey = self.create_tsigkey() self.client.delete('/tsigkeys/%s' % tsigkey['id'], status=204) def test_delete_tsigkey_invalid_id(self): self._assert_invalid_uuid(self.client.delete, '/tsigkeys/%s') @patch.object(central_service.Service, 'delete_tsigkey', side_effect=messaging.MessagingTimeout()) def test_delete_tsigkey_timeout(self, _): url = '/tsigkeys/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980' self._assert_exception('timeout', 504, self.client.delete, url) @patch.object(central_service.Service, 'delete_tsigkey', side_effect=exceptions.TsigKeyNotFound()) def test_delete_tsigkey_missing(self, _): url = '/tsigkeys/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980' self._assert_exception('tsigkey_not_found', 404, self.client.delete, url)
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 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_zone_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_zone_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_zone_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_email_too_long(self): fixture = self.get_zone_fixture(fixture=0) fixture.update({'email': 'a' * 255 + '@abc.com'}) body = fixture self._assert_exception('invalid_object', 400, self.client.post_json, '/zones', body) def test_create_zone_invalid_email(self): invalid_emails = [ 'org', 'example.org', 'bla.example.org', 'org.', 'example.org.', 'bla.example.org.', ] fixture = self.get_zone_fixture(fixture=0) for email in invalid_emails: fixture.update({'email': email}) body = fixture self._assert_exception('invalid_object', 400, self.client.post_json, '/zones', body) def test_create_zone_email_missing(self): fixture = self.get_zone_fixture(fixture=0) del fixture['email'] body = fixture self._assert_exception('invalid_object', 400, self.client.post_json, '/zones', body) def test_create_zone_ttl_less_than_zero(self): fixture = self.get_zone_fixture(fixture=0) fixture['ttl'] = -1 body = fixture self._assert_exception('invalid_object', 400, self.client.post_json, '/zones', body) def test_create_zone_ttl_is_zero(self): fixture = self.get_zone_fixture(fixture=0) fixture['ttl'] = 0 body = fixture self._assert_exception('invalid_object', 400, self.client.post_json, '/zones', body) def test_create_zone_ttl_is_greater_than_max(self): fixture = self.get_zone_fixture(fixture=0) fixture['ttl'] = 2174483648 body = fixture self._assert_exception('invalid_object', 400, self.client.post_json, '/zones', body) def test_create_zone_ttl_is_invalid(self): fixture = self.get_zone_fixture(fixture=0) fixture['ttl'] = "!@?>" body = fixture self._assert_exception('invalid_object', 400, self.client.post_json, '/zones', body) def test_create_zone_ttl_is_not_required_field(self): fixture = self.get_zone_fixture(fixture=0) body = fixture response = self.client.post_json('/zones', body) self.assertEqual(202, response.status_int) self.assertEqual('application/json', response.content_type) def test_create_zone_description_too_long(self): fixture = self.get_zone_fixture(fixture=0) fixture['description'] = "a" * 161 body = fixture self._assert_exception('invalid_object', 400, self.client.post_json, '/zones', body) def test_create_zone_name_is_missing(self): fixture = self.get_zone_fixture(fixture=0) del fixture['name'] body = fixture self._assert_exception('invalid_object', 400, self.client.post_json, '/zones', body) def test_create_zone_name_too_long(self): fixture = self.get_zone_fixture(fixture=0) fixture['name'] = 'x' * 255 + ".com" body = fixture self._assert_exception('invalid_object', 400, self.client.post_json, '/zones', body) def test_create_zone_body_validation(self): fixture = self.get_zone_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_zone_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_zone_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_zone', side_effect=messaging.MessagingTimeout()) def test_create_zone_timeout(self, _): fixture = self.get_zone_fixture(fixture=0) body = fixture self._assert_exception('timeout', 504, self.client.post_json, '/zones/', body) @patch.object(central_service.Service, 'create_zone', side_effect=exceptions.DuplicateZone()) def test_create_zone_duplicate(self, _): fixture = self.get_zone_fixture(fixture=0) body = fixture self._assert_exception('duplicate_zone', 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_zone(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_zones', 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_zone() 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_zone', 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_zone', side_effect=exceptions.ZoneNotFound()) def test_get_zone_missing(self, _): url = '/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980' self._assert_exception('zone_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_zone() # 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_zone() # 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_zone', side_effect=exceptions.DuplicateZone()) 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_zone', 409, self.client.patch_json, url, body) @patch.object(central_service.Service, 'get_zone', 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_zone', side_effect=exceptions.ZoneNotFound()) 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('zone_not_found', 404, self.client.patch_json, url, body) def test_delete_zone(self): zone = self.create_zone() 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']) # The deleted zone should still be listed zones = self.client.get('/zones/') self.assertEqual(1, len(zones.json['zones'])) def test_delete_zone_invalid_id(self): self._assert_invalid_uuid(self.client.delete, '/zones/%s') @patch.object(central_service.Service, 'delete_zone', 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_zone', side_effect=exceptions.ZoneNotFound()) def test_delete_zone_missing(self, _): url = '/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980' self._assert_exception('zone_not_found', 404, self.client.delete, url) def test_post_abandon_zone(self): zone = self.create_zone() 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_zone': '@'}) response = self.client.post_json(url) self.assertEqual(204, response.status_int) def test_get_abandon_zone(self): zone = self.create_zone() 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_zone() 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_zone_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_zone_fixture('SECONDARY', 0) self._assert_exception('invalid_object', 400, self.client.post_json, '/zones/', fixture) def test_update_secondary(self): # Create a zone zone = objects.Zone(name='example.com.', type='SECONDARY', masters=objects.ZoneMasterList.from_list([{ 'host': '1.0.0.0', 'port': 69 }, { 'host': '2.0.0.0', 'port': 69 }])) zone.email = cfg.CONF['service:central'].managed_resource_email # Create a zone zone = self.central_service.create_zone(self.admin_context, zone) 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_zone_fixture('SECONDARY', 0) fixture['email'] = cfg.CONF['service:central'].managed_resource_email fixture['masters'] = [{"host": "10.0.0.10", "port": 53}] # Create a zone zone = self.create_zone(**fixture) mdns = mock.Mock() with mock.patch.object(mdns_api.MdnsAPI, 'get_instance') as get_mdns: get_mdns.return_value = mdns mdns.get_serial_number.return_value = ( 'SUCCESS', 10, 1, ) response = self.client.post_json('/zones/%s/tasks/xfr' % zone['id'], None, status=202) self.assertTrue(mdns.perform_zone_xfr.called) # Check the headers are what we expect self.assertEqual(202, response.status_int) self.assertEqual('application/json', response.content_type) self.assertEqual(b'""', response.body) def test_invalid_xfr_request(self): # Create a zone zone = self.create_zone() 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_zone_fixture('SECONDARY', 0) fixture['email'] = cfg.CONF['service:central'].managed_resource_email # Create a zone zone = self.create_zone(**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_zone_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_zone_fixture(fixture=0) response = self.client.post_json('/zones/', fixture) fixture = self.get_zone_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_zone() # 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_zone() # 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]) def test_get_zones_filter(self): # Add zones for testing fixtures = [ self.get_zone_fixture('PRIMARY', fixture=0, values={ 'ttl': 3600, 'description': 'test1' }), self.get_zone_fixture('PRIMARY', fixture=1, values={ 'ttl': 4000, 'description': 'test2' }) ] for fixture in fixtures: response = self.client.post_json('/zones/', fixture) get_urls = [ # Filter by Type '/zones?type=%s' % fixtures[0]['type'], # Filter by Name '/zones?name=%s' % fixtures[0]['name'], # Filter by Email '/zones?email=example*', '/zones?email=%s' % fixtures[1]['email'], # Filter by TTL '/zones?ttl=3600', # Filter by Description '/zones?description=test1', '/zones?description=test*' ] correct_results = [2, 1, 2, 1, 1, 1, 2] for get_url, correct_result in zip(get_urls, correct_results): response = self.client.get(get_url) # Check the headers are what we expect self.assertEqual(200, response.status_int) self.assertEqual('application/json', response.content_type) # Check that the correct number of zones match self.assertEqual(correct_result, len(response.json['zones'])) def test_invalid_zones_filter(self): invalid_url = '/zones?id=155477ef-e6c5-4b94-984d-8fc68c0c1a14' self._assert_exception('bad_request', 400, self.client.get, invalid_url)
class SchedulerClientTestCase(test.NoDBTestCase): def setUp(self): super(SchedulerClientTestCase, self).setUp() self.client = scheduler_client.SchedulerClient() def test_constructor(self): self.assertIsNotNone(self.client.queryclient) self.assertIsNotNone(self.client.reportclient) @mock.patch.object(scheduler_query_client.SchedulerQueryClient, 'select_destinations') def test_select_destinations(self, mock_select_destinations): fake_spec = objects.RequestSpec() self.assertIsNone(self.client.queryclient.instance) self.client.select_destinations('ctxt', fake_spec) self.assertIsNotNone(self.client.queryclient.instance) mock_select_destinations.assert_called_once_with('ctxt', fake_spec) @mock.patch.object(scheduler_query_client.SchedulerQueryClient, 'select_destinations', side_effect=messaging.MessagingTimeout()) def test_select_destinations_timeout(self, mock_select_destinations): # check if the scheduler service times out properly fake_spec = objects.RequestSpec() fake_args = ['ctxt', fake_spec] self.assertRaises(messaging.MessagingTimeout, self.client.select_destinations, *fake_args) mock_select_destinations.assert_has_calls([mock.call(*fake_args)] * 2) @mock.patch.object( scheduler_query_client.SchedulerQueryClient, 'select_destinations', side_effect=[messaging.MessagingTimeout(), mock.DEFAULT]) def test_select_destinations_timeout_once(self, mock_select_destinations): # scenario: the scheduler service times out & recovers after failure fake_spec = objects.RequestSpec() fake_args = ['ctxt', fake_spec] self.client.select_destinations(*fake_args) mock_select_destinations.assert_has_calls([mock.call(*fake_args)] * 2) @mock.patch.object(scheduler_query_client.SchedulerQueryClient, 'update_aggregates') def test_update_aggregates(self, mock_update_aggs): aggregates = [objects.Aggregate(id=1)] self.client.update_aggregates(context='context', aggregates=aggregates) mock_update_aggs.assert_called_once_with('context', aggregates) @mock.patch.object(scheduler_query_client.SchedulerQueryClient, 'delete_aggregate') def test_delete_aggregate(self, mock_delete_agg): aggregate = objects.Aggregate(id=1) self.client.delete_aggregate(context='context', aggregate=aggregate) mock_delete_agg.assert_called_once_with('context', aggregate) @mock.patch.object(scheduler_report_client.SchedulerReportClient, 'update_resource_stats') def test_update_resource_stats(self, mock_update_resource_stats): self.assertIsNone(self.client.reportclient.instance) self.client.update_resource_stats(mock.sentinel.cn) self.assertIsNotNone(self.client.reportclient.instance) mock_update_resource_stats.assert_called_once_with(mock.sentinel.cn)
class ApiV1RecordsTest(ApiV1Test): def setUp(self): super(ApiV1RecordsTest, self).setUp() self.domain = self.create_domain() self.recordset = self.create_recordset(self.domain, 'A') def test_create_record(self): recordset_fixture = self.get_recordset_fixture(self.domain['name']) fixture = self.get_record_fixture(recordset_fixture['type']) fixture.update({ 'name': recordset_fixture['name'], 'type': recordset_fixture['type'], }) # Create a record response = self.post('domains/%s/records' % self.domain['id'], data=fixture) self.assertIn('id', response.json) self.assertIn('name', response.json) self.assertEqual(response.json['name'], fixture['name']) def test_create_record_existing_recordset(self): fixture = self.get_record_fixture(self.recordset['type']) fixture.update({ 'name': self.recordset['name'], 'type': self.recordset['type'], }) # Create a record response = self.post('domains/%s/records' % self.domain['id'], data=fixture) self.assertIn('id', response.json) self.assertIn('name', response.json) self.assertEqual(response.json['name'], fixture['name']) def test_create_record_name_reuse(self): fixture_1 = self.get_record_fixture(self.recordset['type']) fixture_1.update({ 'name': self.recordset['name'], 'type': self.recordset['type'], }) fixture_2 = self.get_record_fixture(self.recordset['type'], fixture=1) fixture_2.update({ 'name': self.recordset['name'], 'type': self.recordset['type'], }) # Create 2 records record_1 = self.post('domains/%s/records' % self.domain['id'], data=fixture_1) record_2 = self.post('domains/%s/records' % self.domain['id'], data=fixture_2) # Delete record 1, this should not have any side effects self.delete('domains/%s/records/%s' % (self.domain['id'], record_1.json['id'])) # Simulate the record 1 having been deleted on the backend domain_serial = self.central_service.get_domain( self.admin_context, self.domain['id']).serial self.central_service.update_status(self.admin_context, self.domain['id'], "SUCCESS", domain_serial) # Get the record 2 to ensure recordset did not get deleted rec_2_get_response = self.get('domains/%s/records/%s' % (self.domain['id'], record_2.json['id'])) self.assertIn('id', rec_2_get_response.json) self.assertIn('name', rec_2_get_response.json) self.assertEqual(rec_2_get_response.json['name'], fixture_1['name']) # Delete record 2, this should delete the null recordset too self.delete('domains/%s/records/%s' % (self.domain['id'], record_2.json['id'])) # Simulate the record 2 having been deleted on the backend domain_serial = self.central_service.get_domain( self.admin_context, self.domain['id']).serial self.central_service.update_status(self.admin_context, self.domain['id'], "SUCCESS", domain_serial) # Re-create as a different type, but use the same name fixture = self.get_record_fixture('CNAME') fixture.update({'name': self.recordset['name'], 'type': 'CNAME'}) response = self.post('domains/%s/records' % self.domain['id'], data=fixture) self.assertIn('id', response.json) self.assertIn('name', response.json) self.assertEqual(response.json['name'], fixture['name']) def test_create_record_junk(self): fixture = self.get_record_fixture(self.recordset['type']) fixture.update({ 'name': self.recordset['name'], 'type': self.recordset['type'], }) # Add a junk property fixture['junk'] = 'Junk Field' # Create a record, Ensuring it fails with a 400 self.post('domains/%s/records' % self.domain['id'], data=fixture, status_code=400) def test_create_wildcard_record_after_named(self): # We want to test that a wildcard record rs doesnt use the previous one # https://bugs.launchpad.net/designate/+bug/1391426 name = "foo.%s" % self.domain.name fixture = {"name": name, "type": "A", "data": "10.0.0.1"} self.post('domains/%s/records' % self.domain['id'], data=fixture) wildcard_name = '*.%s' % self.domain["name"] fixture['name'] = wildcard_name self.post('domains/%s/records' % self.domain['id'], data=fixture) named_rs = self.central_service.find_recordset(self.admin_context, {"name": name}) wildcard_rs = self.central_service.find_recordset( self.admin_context, {"name": wildcard_name}) self.assertNotEqual(named_rs.name, wildcard_rs.name) self.assertNotEqual(named_rs.id, wildcard_rs.id) def test_create_record_utf_description(self): fixture = self.get_record_fixture(self.recordset['type']) fixture.update({ 'name': self.recordset['name'], 'type': self.recordset['type'], }) # Add a UTF-8 riddled description fixture['description'] = "utf-8:2H₂+O₂⇌2H₂O,R=4.7kΩ,⌀200mm∮E⋅da=Q,n" \ ",∑f(i)=∏g(i),∀x∈ℝ:⌈x⌉" # Create a record, Ensuring it succeeds self.post('domains/%s/records' % self.domain['id'], data=fixture) def test_create_record_description_too_long(self): fixture = self.get_record_fixture(self.recordset['type']) fixture.update({ 'name': self.recordset['name'], 'type': self.recordset['type'], }) # Add a description that is too long fixture['description'] = "x" * 161 # Create a record, Ensuring it Fails with a 400 self.post('domains/%s/records' % self.domain['id'], data=fixture, status_code=400) def test_create_record_negative_ttl(self): fixture = self.get_record_fixture(self.recordset['type']) fixture.update({ 'name': self.recordset['name'], 'type': self.recordset['type'], }) # Set the TTL to a negative value fixture['ttl'] = -1 # Create a record, Ensuring it Fails with a 400 self.post('domains/%s/records' % self.domain['id'], data=fixture, status_code=400) def test_create_record_invalid_ttl(self): fixture = self.get_record_fixture(self.recordset['type']) fixture.update({ 'name': self.recordset['name'], 'type': self.recordset['type'], }) # Set the TTL to a invalid value fixture['ttl'] = "$?!." # Create a record, Ensuring it Fails with a 400 self.post('domains/%s/records' % self.domain['id'], data=fixture, status_code=400) @patch.object(central_service.Service, 'create_record', side_effect=messaging.MessagingTimeout()) def test_create_record_timeout(self, _): fixture = self.get_record_fixture(self.recordset['type']) fixture.update({ 'name': self.recordset['name'], 'type': self.recordset['type'], }) # Create a record self.post('domains/%s/records' % self.domain['id'], data=fixture, status_code=504) def test_create_wildcard_record(self): # Prepare a record fixture = self.get_record_fixture(self.recordset['type']) fixture.update({ 'name': '*.%s' % self.recordset['name'], 'type': self.recordset['type'], }) # Create a record response = self.post('domains/%s/records' % self.domain['id'], data=fixture) self.assertIn('id', response.json) self.assertIn('name', response.json) self.assertEqual(response.json['name'], fixture['name']) def test_create_srv_record(self): recordset_fixture = self.get_recordset_fixture(self.domain['name'], 'SRV') fixture = self.get_record_fixture(recordset_fixture['type']) priority, _, data = fixture['data'].partition(" ") fixture.update({ 'data': data, 'priority': int(priority), 'name': recordset_fixture['name'], 'type': recordset_fixture['type'], }) # Create a record response = self.post('domains/%s/records' % self.domain['id'], data=fixture) self.assertIn('id', response.json) self.assertEqual(response.json['type'], fixture['type']) self.assertEqual(response.json['name'], fixture['name']) self.assertEqual(response.json['priority'], fixture['priority']) self.assertEqual(response.json['data'], fixture['data']) def test_create_invalid_data_srv_record(self): recordset_fixture = self.get_recordset_fixture(self.domain['name'], 'SRV') fixture = self.get_record_fixture(recordset_fixture['type']) fixture.update({ 'name': recordset_fixture['name'], 'type': recordset_fixture['type'], }) invalid_datas = [ 'I 5060 sip.%s' % self.domain['name'], '5060 sip.%s' % self.domain['name'], '5060 I sip.%s' % self.domain['name'], '0 5060 sip', 'sip', 'sip.%s' % self.domain['name'], ] for invalid_data in invalid_datas: fixture['data'] = invalid_data # Attempt to create the record self.post('domains/%s/records' % self.domain['id'], data=fixture, status_code=400) def test_create_invalid_name_srv_record(self): recordset_fixture = self.get_recordset_fixture(self.domain['name'], 'SRV') fixture = self.get_record_fixture(recordset_fixture['type']) fixture.update({ 'name': recordset_fixture['name'], 'type': recordset_fixture['type'], }) invalid_names = [ '%s' % self.domain['name'], '_udp.%s' % self.domain['name'], 'sip._udp.%s' % self.domain['name'], '_sip.udp.%s' % self.domain['name'], ] for invalid_name in invalid_names: fixture['name'] = invalid_name # Attempt to create the record self.post('domains/%s/records' % self.domain['id'], data=fixture, status_code=400) def test_create_invalid_name(self): # Prepare a record fixture = self.get_record_fixture(self.recordset['type']) fixture.update({ 'name': self.recordset['name'], 'type': self.recordset['type'], }) invalid_names = [ 'org', 'example.org', '$$.example.org', '*example.org.', '*.*.example.org.', 'abc.*.example.org.', ] for invalid_name in invalid_names: fixture['name'] = invalid_name # Create a record response = self.post('domains/%s/records' % self.domain['id'], data=fixture, status_code=400) self.assertNotIn('id', response.json) def test_get_records(self): response = self.get('domains/%s/records' % self.domain['id']) # Verify that the SOA & NS records are already created self.assertIn('records', response.json) self.assertEqual(2, len(response.json['records'])) # Create a record self.create_record(self.domain, self.recordset) response = self.get('domains/%s/records' % self.domain['id']) # Verify that one more record has been added self.assertIn('records', response.json) self.assertEqual(3, len(response.json['records'])) # Create a second record self.create_record(self.domain, self.recordset, fixture=1) response = self.get('domains/%s/records' % self.domain['id']) # Verfiy that all 4 records are there self.assertIn('records', response.json) self.assertEqual(4, len(response.json['records'])) @patch.object(central_service.Service, 'find_records', side_effect=messaging.MessagingTimeout()) def test_get_records_timeout(self, _): self.get('domains/%s/records' % self.domain['id'], status_code=504) def test_get_records_missing_domain(self): self.get('domains/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980/records', status_code=404) def test_get_records_invalid_domain_id(self): self.get('domains/2fdadfb1cf964259ac6bbb7b6d2ff980/records', status_code=404) def test_get_record_missing(self): self.get('domains/%s/records/2fdadfb1-cf96-4259-ac6b-' 'bb7b6d2ff980' % self.domain['id'], status_code=404) def test_get_record_with_invalid_id(self): self.get('domains/%s/records/2fdadfb1-cf96-4259-ac6b-' 'bb7b6d2ff980GH' % self.domain['id'], status_code=404) def test_get_record(self): # Create a record record = self.create_record(self.domain, self.recordset) response = self.get('domains/%s/records/%s' % (self.domain['id'], record['id'])) self.assertIn('id', response.json) self.assertEqual(response.json['id'], record['id']) self.assertEqual(response.json['name'], self.recordset['name']) self.assertEqual(response.json['type'], self.recordset['type']) def test_update_record(self): # Create a record record = self.create_record(self.domain, self.recordset) # Fetch another fixture to use in the update fixture = self.get_record_fixture(self.recordset['type'], fixture=1) # Update the record data = {'data': fixture['data']} response = self.put('domains/%s/records/%s' % (self.domain['id'], record['id']), data=data) self.assertIn('id', response.json) self.assertEqual(response.json['id'], record['id']) self.assertEqual(response.json['data'], fixture['data']) self.assertEqual(response.json['type'], self.recordset['type']) def test_update_record_ttl(self): # Create a record record = self.create_record(self.domain, self.recordset) # Update the record data = {'ttl': 100} response = self.put('domains/%s/records/%s' % (self.domain['id'], record['id']), data=data) self.assertIn('id', response.json) self.assertEqual(response.json['id'], record['id']) self.assertEqual(response.json['data'], record['data']) self.assertEqual(response.json['type'], self.recordset['type']) self.assertEqual(response.json['ttl'], 100) def test_update_record_junk(self): # Create a record record = self.create_record(self.domain, self.recordset) data = {'ttl': 100, 'junk': 'Junk Field'} self.put('domains/%s/records/%s' % (self.domain['id'], record['id']), data=data, status_code=400) def test_update_record_negative_ttl(self): # Create a record record = self.create_record(self.domain, self.recordset) data = {'ttl': -1} self.put('domains/%s/records/%s' % (self.domain['id'], record['id']), data=data, status_code=400) def test_update_record_invalid_ttl(self): # Create a record record = self.create_record(self.domain, self.recordset) data = {'ttl': "$?>%"} self.put('domains/%s/records/%s' % (self.domain['id'], record['id']), data=data, status_code=400) def test_update_record_outside_domain_fail(self): # Create a record record = self.create_record(self.domain, self.recordset) data = {'name': 'test.someotherdomain.com.'} self.put('domains/%s/records/%s' % (self.domain['id'], record['id']), data=data, status_code=400) @patch.object(central_service.Service, 'find_domain', side_effect=messaging.MessagingTimeout()) def test_update_record_timeout(self, _): # Create a record record = self.create_record(self.domain, self.recordset) data = {'name': 'test.example.org.'} self.put('domains/%s/records/%s' % (self.domain['id'], record['id']), data=data, status_code=504) def test_update_record_missing(self): data = {'name': 'test.example.org.'} self.put('domains/%s/records/2fdadfb1-cf96-4259-ac6b-' 'bb7b6d2ff980' % self.domain['id'], data=data, status_code=404) def test_update_record_invalid_id(self): data = {'name': 'test.example.org.'} self.put('domains/%s/records/2fdadfb1cf964259ac6bbb7b6d2ff980' % self.domain['id'], data=data, status_code=404) def test_update_record_missing_domain(self): data = {'name': 'test.example.org.'} self.put( 'domains/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980/records/' '2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', data=data, status_code=404) def test_update_record_invalid_domain_id(self): data = {'name': 'test.example.org.'} self.put( 'domains/2fdadfb1cf964259ac6bbb7b6d2ff980/records/' '2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', data=data, status_code=404) def test_delete_record(self): # Create a record record = self.create_record(self.domain, self.recordset) self.delete('domains/%s/records/%s' % (self.domain['id'], record['id'])) # Simulate the record having been deleted on the backend domain_serial = self.central_service.get_domain( self.admin_context, self.domain['id']).serial self.central_service.update_status(self.admin_context, self.domain['id'], "SUCCESS", domain_serial) # Ensure we can no longer fetch the record self.get('domains/%s/records/%s' % (self.domain['id'], record['id']), status_code=404) @patch.object(central_service.Service, 'find_domain', side_effect=messaging.MessagingTimeout()) def test_delete_record_timeout(self, _): # Create a record record = self.create_record(self.domain, self.recordset) self.delete('domains/%s/records/%s' % (self.domain['id'], record['id']), status_code=504) def test_delete_record_missing(self): self.delete('domains/%s/records/2fdadfb1-cf96-4259-ac6b-' 'bb7b6d2ff980' % self.domain['id'], status_code=404) def test_delete_record_missing_domain(self): self.delete( 'domains/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980/records/' '2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', status_code=404) def test_delete_record_invalid_domain_id(self): self.delete( 'domains/2fdadfb1cf964259ac6bbb7b6d2ff980/records/' '2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', status_code=404) def test_delete_record_invalid_id(self): self.delete('domains/%s/records/2fdadfb1-cf96-4259-ac6b-' 'bb7b6d2ff980GH' % self.domain['id'], status_code=404) def test_get_record_in_secondary(self): fixture = self.get_domain_fixture('SECONDARY', 1) fixture['email'] = "*****@*****.**" domain = self.create_domain(**fixture) record = self.create_record(domain, self.recordset) url = 'domains/%s/records/%s' % (domain.id, record.id) self.get(url, status_code=404) def test_create_record_in_secondary(self): fixture = self.get_domain_fixture('SECONDARY', 1) fixture['email'] = "*****@*****.**" domain = self.create_domain(**fixture) record = { "name": "foo.%s" % domain.name, "type": "A", "data": "10.0.0.1" } url = 'domains/%s/records' % domain.id self.post(url, record, status_code=404) def test_update_record_in_secondary(self): fixture = self.get_domain_fixture('SECONDARY', 1) fixture['email'] = "*****@*****.**" domain = self.create_domain(**fixture) record = self.create_record(domain, self.recordset) url = 'domains/%s/records/%s' % (domain.id, record.id) self.put(url, {"data": "10.0.0.1"}, status_code=404) def test_delete_record_in_secondary(self): fixture = self.get_domain_fixture('SECONDARY', 1) fixture['email'] = "*****@*****.**" domain = self.create_domain(**fixture) record = self.create_record(domain, self.recordset) url = 'domains/%s/records/%s' % (domain.id, record.id) self.delete(url, status_code=404) def test_create_record_deleting_domain(self): recordset_fixture = self.get_recordset_fixture(self.domain['name']) fixture = self.get_record_fixture(recordset_fixture['type']) fixture.update({ 'name': recordset_fixture['name'], 'type': recordset_fixture['type'], }) self.delete('/domains/%s' % self.domain['id']) self.post('domains/%s/records' % self.domain['id'], data=fixture, status_code=400) def test_update_record_deleting_domain(self): # Create a record record = self.create_record(self.domain, self.recordset) # Fetch another fixture to use in the update fixture = self.get_record_fixture(self.recordset['type'], fixture=1) # Update the record data = {'data': fixture['data']} self.delete('/domains/%s' % self.domain['id']) self.put('domains/%s/records/%s' % (self.domain['id'], record['id']), data=data, status_code=400) def test_delete_record_deleting_domain(self): # Create a record record = self.create_record(self.domain, self.recordset) self.delete('/domains/%s' % self.domain['id']) self.delete('domains/%s/records/%s' % (self.domain['id'], record['id']), status_code=400)
class ApiV1ServersTest(ApiV1Test): def setUp(self): super(ApiV1ServersTest, self).setUp() # All Server Checks should be performed as an admin, so.. # Override to policy to make everyone an admin. self.policy({'admin': '@'}) def test_create_server(self): # Create a server fixture = self.get_server_fixture(0) response = self.post('servers', data=fixture) self.assertIn('id', response.json) self.assertIn('name', response.json) self.assertEqual(response.json['name'], fixture['name']) def test_create_server_junk(self): # Create a server fixture = self.get_server_fixture(0) # Add a junk property fixture['junk'] = 'Junk Field' # Ensure it fails with a 400 self.post('servers', data=fixture, status_code=400) def test_create_server_with_invalid_name(self): # Create a server fixture = self.get_server_fixture(0) # Add a invalid name fixture['name'] = '$#$%^^' # Ensure it fails with a 400 self.post('servers', data=fixture, status_code=400) @patch.object(central_service.Service, 'update_pool', side_effect=messaging.MessagingTimeout()) def test_create_server_timeout(self, _): # Create a server fixture = self.get_server_fixture(0) self.post('servers', data=fixture, status_code=504) @patch.object(central_service.Service, 'update_pool', side_effect=exceptions.DuplicateServer()) def test_create_server_duplicate(self, _): # Create a server fixture = self.get_server_fixture(0) self.post('servers', data=fixture, status_code=409) def test_get_servers(self): # Fetch the default pool pool = self.storage.get_pool(self.admin_context, default_pool_id) # Fetch the list of servers response = self.get('servers') self.assertIn('servers', response.json) self.assertEqual(len(pool.ns_records), len(response.json['servers'])) # Add a new NS record to the pool pool.ns_records.append( objects.PoolNsRecord(priority=0, hostname='new-ns1.example.org.')) # Save the pool to add a new nameserver self.storage.update_pool(self.admin_context, pool) # Fetch the list of servers response = self.get('servers') self.assertIn('servers', response.json) self.assertEqual(len(pool.ns_records), len(response.json['servers'])) # Add a new NS record to the pool pool.ns_records.append( objects.PoolNsRecord(priority=0, hostname='new-ns2.example.org.')) # Save the pool to add a new nameserver self.storage.update_pool(self.admin_context, pool) response = self.get('servers') self.assertIn('servers', response.json) self.assertEqual(len(pool.ns_records), len(response.json['servers'])) @patch.object(central_service.Service, 'get_pool', side_effect=messaging.MessagingTimeout()) def test_get_servers_timeout(self, _): self.get('servers', status_code=504) def test_get_server(self): # Fetch the default pool pool = self.storage.get_pool(self.admin_context, default_pool_id) # Fetch the Server from the pool response = self.get('servers/%s' % pool.ns_records[0].id) self.assertIn('id', response.json) self.assertEqual(response.json['id'], pool.ns_records[0]['id']) @patch.object(central_service.Service, 'get_pool', side_effect=messaging.MessagingTimeout()) def test_get_server_timeout(self, _): # Fetch the default pool pool = self.storage.get_pool(self.admin_context, default_pool_id) self.get('servers/%s' % pool.ns_records[0].id, status_code=504) def test_get_server_with_invalid_id(self): self.get('servers/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff98GH', status_code=404) def test_get_server_missing(self): self.get('servers/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', status_code=404) def test_update_server(self): # Fetch the default pool pool = self.storage.get_pool(self.admin_context, default_pool_id) data = {'name': 'new-ns1.example.org.'} response = self.put('servers/%s' % pool.ns_records[0].id, data=data) self.assertIn('id', response.json) self.assertEqual(response.json['id'], pool.ns_records[0].id) self.assertIn('name', response.json) self.assertEqual(response.json['name'], 'new-ns1.example.org.') def test_update_server_missing(self): data = {'name': 'test.example.org.'} self.put('servers/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', data=data, status_code=404) def test_update_server_junk(self): # Fetch the default pool pool = self.storage.get_pool(self.admin_context, default_pool_id) data = {'name': 'test.example.org.', 'junk': 'Junk Field'} self.put('servers/%s' % pool.ns_records[0].id, data=data, status_code=400) def test_delete_server(self): # Fetch the default pool pool = self.storage.get_pool(self.admin_context, default_pool_id) # Create a second server so that we can delete the first # because the last remaining server is not allowed to be deleted # Add a new NS record to the pool pool.ns_records.append( objects.PoolNsRecord(priority=0, hostname='new-ns2.example.org.')) # Save the pool to add a new nameserver self.storage.update_pool(self.admin_context, pool) # Now delete the server self.delete('servers/%s' % pool.ns_records[1].id) # Ensure we can no longer fetch the deleted server self.get('servers/%s' % pool.ns_records[1].id, status_code=404) # Also, verify we cannot delete last remaining server self.delete('servers/%s' % pool.ns_records[0].id, status_code=400) def test_delete_server_with_invalid_id(self): self.delete('servers/9fdadfb1-cf96-4259-ac6b-bb7b6d2ff98GH', status_code=404) def test_delete_server_missing(self): self.delete('servers/9fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', status_code=404)
class ApiV2RecordSetsTest(ApiV2TestCase): def setUp(self): super(ApiV2RecordSetsTest, self).setUp() # Create a domain self.domain = self.create_domain() def test_create_recordset(self): # Prepare a RecordSet fixture fixture = self.get_recordset_fixture(self.domain['name'], fixture=0) response = self.client.post_json( '/zones/%s/recordsets' % self.domain['id'], 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('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.assertIsNone(response.json['updated_at']) self.assertIn('records', response.json) # The action and status are NONE and ACTIVE as there are no records self.assertEqual('NONE', response.json['action']) self.assertEqual('ACTIVE', response.json['status']) def test_create_recordset_with_records(self): # Prepare a RecordSet fixture fixture = self.get_recordset_fixture( self.domain['name'], 'A', fixture=0, values={'records': [ '192.0.2.1', '192.0.2.2', ]} ) response = self.client.post_json( '/zones/%s/recordsets' % self.domain['id'], fixture) # Check the headers are what we expect self.assertEqual(202, response.status_int) self.assertEqual('application/json', response.content_type) # Check the values returned are what we expect self.assertIn('records', response.json) self.assertEqual(2, len(response.json['records'])) self.assertEqual('CREATE', response.json['action']) self.assertEqual('PENDING', response.json['status']) # Check the zone's status is as expected response = self.client.get('/zones/%s' % self.domain['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) self.assertEqual('UPDATE', response.json['action']) self.assertEqual('PENDING', response.json['status']) def test_create_recordset_with_invalid_name(self): # Prepare a RecordSet fixture body = self.get_recordset_fixture( self.domain['name'], 'A', fixture=0, values={ 'name': '`invalid`label`.%s' % self.domain['name'], 'records': [ '192.0.2.1', '192.0.2.2', ] } ) url = '/zones/%s/recordsets' % self.domain['id'] # Ensure it fails with a 400 self._assert_exception( 'invalid_object', 400, self.client.post_json, url, body) def test_create_recordset_with_name_too_long(self): fixture = self.get_recordset_fixture(self.domain['name'], fixture=0) fixture['name'] = 'x' * 255 + ".%s" % self.domain['name'] body = fixture url = '/zones/%s/recordsets' % self.domain['id'] self._assert_exception( 'invalid_object', 400, self.client.post_json, url, body) def test_create_recordset_with_name_missing(self): fixture = self.get_recordset_fixture(self.domain['name'], fixture=0) del fixture['name'] body = fixture url = '/zones/%s/recordsets' % self.domain['id'] self._assert_exception( 'invalid_object', 400, self.client.post_json, url, body) def test_create_recordset_type_is_missing(self): # Prepare a RecordSet fixture body = self.get_recordset_fixture( self.domain['name'], 'A', fixture=0, values={ 'name': 'name.%s' % self.domain['name'], 'records': [ '192.0.2.1', '192.0.2.2', ] } ) del body['type'] url = '/zones/%s/recordsets' % self.domain['id'] # Ensure it fails with a 400 self._assert_exception( 'invalid_object', 400, self.client.post_json, url, body) def test_create_recordset_with_invalid_type(self): fixture = self.get_recordset_fixture(self.domain['name'], fixture=0) fixture['type'] = "ABC" body = fixture url = '/zones/%s/recordsets' % self.domain['id'] self._assert_exception( 'invalid_object', 400, self.client.post_json, url, body) def test_create_recordset_description_too_long(self): fixture = self.get_recordset_fixture(self.domain['name'], fixture=0) fixture['description'] = "x" * 161 body = fixture url = '/zones/%s/recordsets' % self.domain['id'] self._assert_exception( 'invalid_object', 400, self.client.post_json, url, body) def test_create_recordset_with_negative_ttl(self): fixture = self.get_recordset_fixture(self.domain['name'], fixture=0) fixture['ttl'] = -1 body = fixture url = '/zones/%s/recordsets' % self.domain['id'] self._assert_exception( 'invalid_object', 400, self.client.post_json, url, body) def test_create_recordset_with_zero_ttl(self): fixture = self.get_recordset_fixture(self.domain['name'], fixture=0) fixture['ttl'] = 0 body = fixture url = '/zones/%s/recordsets' % self.domain['id'] self._assert_exception( 'invalid_object', 400, self.client.post_json, url, body) def test_create_recordset_with_ttl_greater_than_max(self): fixture = self.get_recordset_fixture(self.domain['name'], fixture=0) fixture['ttl'] = 2147483648 body = fixture url = '/zones/%s/recordsets' % self.domain['id'] self._assert_exception( 'invalid_object', 400, self.client.post_json, url, body) def test_create_recordset_with_invalid_ttl(self): fixture = self.get_recordset_fixture(self.domain['name'], fixture=0) fixture['ttl'] = ">?!?" body = fixture url = '/zones/%s/recordsets' % self.domain['id'] self._assert_exception( 'invalid_object', 400, self.client.post_json, url, body) def test_create_recordset_invalid_id(self): self._assert_invalid_uuid(self.client.post, '/zones/%s/recordsets') 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) url = '/zones/%s/recordsets' % self.domain['id'] # Add a junk field to the body fixture['junk'] = 'Junk Field' body = fixture # Ensure it fails with a 400 self._assert_exception( 'invalid_object', 400, self.client.post_json, url, body) @patch.object(central_service.Service, 'create_recordset', side_effect=messaging.MessagingTimeout()) def test_create_recordset_timeout(self, _): fixture = self.get_recordset_fixture(self.domain['name'], fixture=0) body = fixture url = '/zones/%s/recordsets' % self.domain['id'] self._assert_exception('timeout', 504, self.client.post_json, url, body) @patch.object(central_service.Service, 'create_recordset', side_effect=exceptions.DuplicateRecordSet()) def test_create_recordset_duplicate(self, _): fixture = self.get_recordset_fixture(self.domain['name'], fixture=0) body = fixture url = '/zones/%s/recordsets' % self.domain['id'] self._assert_exception('duplicate_recordset', 409, self.client.post_json, url, body) def test_create_recordset_invalid_domain(self): fixture = self.get_recordset_fixture(self.domain['name'], fixture=0) body = fixture url = '/zones/ba751950-6193-11e3-949a-0800200c9a66/recordsets' self._assert_exception('domain_not_found', 404, self.client.post_json, url, body) def test_recordsets_invalid_url(self): url = '/zones/recordsets' self._assert_exception('not_found', 404, self.client.get, url) self._assert_exception('not_found', 404, self.client.post_json, url) # Pecan returns a 405 for Patch and delete operations response = self.client.patch_json(url, status=405) self.assertEqual(405, response.status_int) response = self.client.delete(url, status=405) self.assertEqual(405, response.status_int) def test_get_recordsets(self): url = '/zones/%s/recordsets' % self.domain['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('recordsets', response.json) self.assertIn('links', response.json) self.assertIn('self', response.json['links']) # We should start with 2 pending recordsets for SOA & NS # pending because pool manager is not active self.assertEqual(2, len(response.json['recordsets'])) for recordset in response.json['recordsets']: self.assertEqual('CREATE', recordset['action']) self.assertEqual('PENDING', recordset['status']) soa = self.central_service.find_recordset( self.admin_context, criterion={'domain_id': self.domain['id'], 'type': 'SOA'}) ns = self.central_service.find_recordset( self.admin_context, criterion={'domain_id': self.domain['id'], 'type': 'NS'}) data = [self.create_recordset(self.domain, name='x-%s.%s' % (i, self.domain['name'])) for i in range(0, 10)] data.insert(0, ns) data.insert(0, soa) self._assert_paging(data, url, key='recordsets') self._assert_invalid_paging(data, url, key='recordsets') def test_get_recordsets_filter(self): # Add recordsets for testing fixtures = [ self.get_recordset_fixture( self.domain['name'], 'A', fixture=0, values={ 'records': ['192.0.2.1', '192.0.2.2'], 'description': 'Tester1', 'ttl': 3600 } ), self.get_recordset_fixture( self.domain['name'], 'A', fixture=1, values={ 'records': ['192.0.2.1'], 'description': 'Tester2', 'ttl': 4000 } ) ] for fixture in fixtures: response = self.client.post_json( '/zones/%s/recordsets' % self.domain['id'], fixture) get_urls = [ # Filter by Name '/zones/%s/recordsets?name=%s' % ( self.domain['id'], fixtures[0]['name']), '/zones/%s/recordsets?data=192.0.2.1&name=%s' % ( self.domain['id'], fixtures[1]['name']), # Filter by Type '/zones/%s/recordsets?type=A' % self.domain['id'], '/zones/%s/recordsets?type=A&name=%s' % ( self.domain['id'], fixtures[0]['name']), # Filter by TTL '/zones/%s/recordsets?ttl=3600' % self.domain['id'], # Filter by Data '/zones/%s/recordsets?data=192.0.2.1' % self.domain['id'], '/zones/%s/recordsets?data=192.0.2.2' % self.domain['id'], # Filter by Description '/zones/%s/recordsets?description=Tester1' % self.domain['id'] ] correct_results = [1, 1, 2, 1, 1, 2, 1, 1] for get_url, correct_result in \ six.moves.zip(get_urls, correct_results): response = self.client.get(get_url) # Check the headers are what we expect self.assertEqual(200, response.status_int) self.assertEqual('application/json', response.content_type) # Check that the correct number of recordsets match self.assertEqual(correct_result, len(response.json['recordsets'])) def test_get_recordsets_invalid_id(self): self._assert_invalid_uuid(self.client.get, '/zones/%s/recordsets') @patch.object(central_service.Service, 'get_domain', side_effect=messaging.MessagingTimeout()) def test_get_recordsets_timeout(self, _): url = '/zones/ba751950-6193-11e3-949a-0800200c9a66/recordsets' self._assert_exception('timeout', 504, self.client.get, url) def test_get_deleted_recordsets(self): zone = self.create_domain(fixture=1) self.create_recordset(zone) url = '/zones/%s/recordsets' % zone['id'] response = self.client.get(url) # Check the headers are what we expect self.assertEqual(200, response.status_int) # now delete the domain and get the recordsets self.client.delete('/zones/%s' % zone['id'], status=202) # Simulate the domain having been deleted on the backend domain_serial = self.central_service.get_domain( self.admin_context, zone['id']).serial self.central_service.update_status( self.admin_context, zone['id'], "SUCCESS", domain_serial) # Check that we get a domain_not_found error self._assert_exception('domain_not_found', 404, self.client.get, url) 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) 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.assertIsNone(response.json['updated_at']) self.assertEqual(recordset['name'], response.json['name']) self.assertEqual(recordset['type'], response.json['type']) # The action and status are NONE and ACTIVE as there are no records self.assertEqual('NONE', response.json['action']) self.assertEqual('ACTIVE', response.json['status']) def test_get_recordset_invalid_id(self): self._assert_invalid_uuid(self.client.get, '/zones/%s/recordsets/%s') @patch.object(central_service.Service, 'get_recordset', side_effect=messaging.MessagingTimeout()) def test_get_recordset_timeout(self, _): url = '/zones/%s/recordsets/ba751950-6193-11e3-949a-0800200c9a66' % ( self.domain['id']) self._assert_exception('timeout', 504, self.client.get, url, headers={'Accept': 'application/json'}) @patch.object(central_service.Service, 'get_recordset', side_effect=exceptions.RecordSetNotFound()) def test_get_recordset_missing(self, _): url = '/zones/%s/recordsets/ba751950-6193-11e3-949a-0800200c9a66' % ( self.domain['id']) self._assert_exception('recordset_not_found', 404, self.client.get, url, headers={'Accept': 'application/json'}) def test_update_recordset(self): # Create a recordset recordset = self.create_recordset(self.domain) # Prepare an update body body = {'description': 'Tester'} url = '/zones/%s/recordsets/%s' % (recordset['domain_id'], recordset['id']) response = self.client.put_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('links', response.json) self.assertIn('self', response.json['links']) # Check the values returned are what we expect self.assertIn('id', response.json) self.assertIsNotNone(response.json['updated_at']) self.assertEqual('Tester', response.json['description']) # The action and status are NONE and ACTIVE as there are no records self.assertEqual('NONE', response.json['action']) self.assertEqual('ACTIVE', response.json['status']) # Check the zone's status is as expected response = self.client.get('/zones/%s' % recordset['domain_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) self.assertEqual('UPDATE', response.json['action']) self.assertEqual('PENDING', response.json['status']) def test_update_recordset_with_record_create(self): # Create a recordset recordset = self.create_recordset(self.domain, 'A') # The action and status are NONE and ACTIVE as there are no records self.assertEqual('NONE', recordset['action']) self.assertEqual('ACTIVE', recordset['status']) # Prepare an update body body = {'description': 'Tester', 'type': 'A', 'records': ['192.0.2.1', '192.0.2.2']} url = '/zones/%s/recordsets/%s' % (recordset['domain_id'], recordset['id']) response = self.client.put_json(url, 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 values returned are what we expect self.assertIn('records', response.json) self.assertEqual(2, len(response.json['records'])) self.assertEqual(set(['192.0.2.1', '192.0.2.2']), set(response.json['records'])) self.assertEqual('UPDATE', response.json['action']) self.assertEqual('PENDING', response.json['status']) # Check the zone's status is as expected response = self.client.get('/zones/%s' % recordset['domain_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) self.assertEqual('UPDATE', response.json['action']) self.assertEqual('PENDING', response.json['status']) def test_update_recordset_with_record_replace(self): # Create a recordset with one record recordset = self.create_recordset(self.domain, 'A') self.create_record(self.domain, recordset) # Prepare an update body body = {'description': 'Tester', 'records': ['192.0.2.201', '192.0.2.202']} url = '/zones/%s/recordsets/%s' % (recordset['domain_id'], recordset['id']) response = self.client.put_json(url, 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 values returned are what we expect self.assertIn('records', response.json) self.assertEqual(2, len(response.json['records'])) self.assertEqual(set(['192.0.2.201', '192.0.2.202']), set(response.json['records'])) # Check the zone's status is as expected response = self.client.get('/zones/%s' % recordset['domain_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) self.assertEqual('UPDATE', response.json['action']) self.assertEqual('PENDING', response.json['status']) def test_update_recordset_with_record_clear(self): # Create a recordset with one record recordset = self.create_recordset(self.domain, 'A') self.create_record(self.domain, recordset) # Prepare an update body body = {'description': 'Tester', 'records': []} url = '/zones/%s/recordsets/%s' % (recordset['domain_id'], recordset['id']) response = self.client.put_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 values returned are what we expect self.assertIn('records', response.json) self.assertEqual(0, len(response.json['records'])) # Check the zone's status is as expected response = self.client.get('/zones/%s' % recordset['domain_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) self.assertEqual('UPDATE', response.json['action']) self.assertEqual('PENDING', response.json['status']) def test_update_recordset_invalid_id(self): self._assert_invalid_uuid( self.client.put_json, '/zones/%s/recordsets/%s') 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 = {'description': 'Tester', 'records': ['192.3.3.17'], 'junk': 'Junk Field'} # Ensure it fails with a 400 url = '/zones/%s/recordsets/%s' % (recordset['domain_id'], recordset['id']) self._assert_exception('invalid_object', 400, self.client.put_json, url, body) # Prepare an update body with junk in the body body = {'description': 'Tester', 'junk': 'Junk Field'} # Ensure it fails with a 400 self._assert_exception('invalid_object', 400, self.client.put_json, url, body) @patch.object(central_service.Service, 'get_recordset', side_effect=exceptions.DuplicateRecordSet()) def test_update_recordset_duplicate(self, _): # Prepare an update body body = {'description': 'Tester'} # Ensure it fails with a 409 url = ('/zones/%s/recordsets/ba751950-6193-11e3-949a-0800200c9a66' % (self.domain['id'])) self._assert_exception('duplicate_recordset', 409, self.client.put_json, url, body) @patch.object(central_service.Service, 'get_recordset', side_effect=messaging.MessagingTimeout()) def test_update_recordset_timeout(self, _): # Prepare an update body body = {'description': 'Tester'} # Ensure it fails with a 504 url = ('/zones/%s/recordsets/ba751950-6193-11e3-949a-0800200c9a66' % (self.domain['id'])) self._assert_exception('timeout', 504, self.client.put_json, url, body) @patch.object(central_service.Service, 'get_recordset', side_effect=exceptions.RecordSetNotFound()) def test_update_recordset_missing(self, _): # Prepare an update body body = {'description': 'Tester'} # Ensure it fails with a 404 url = ('/zones/%s/recordsets/ba751950-6193-11e3-949a-0800200c9a66' % (self.domain['id'])) self._assert_exception('recordset_not_found', 404, self.client.put_json, url, body) def test_update_recordset_invalid_ttl(self): recordset = self.create_recordset(self.domain) body = {'ttl': '>?!@'} url = '/zones/%s/recordsets/%s' % (recordset['domain_id'], recordset['id']) self._assert_exception('invalid_object', 400, self.client.put_json, url, body) def test_update_recordset_zero_ttl(self): recordset = self.create_recordset(self.domain) body = {'ttl': 0} url = '/zones/%s/recordsets/%s' % (recordset['domain_id'], recordset['id']) self._assert_exception('invalid_object', 400, self.client.put_json, url, body) def test_update_recordset_negative_ttl(self): recordset = self.create_recordset(self.domain) body = {'ttl': -1} url = '/zones/%s/recordsets/%s' % (recordset['domain_id'], recordset['id']) self._assert_exception('invalid_object', 400, self.client.put_json, url, body) def test_update_recordset_ttl_greater_than_max(self): recordset = self.create_recordset(self.domain) body = {'ttl': 2174483648} url = '/zones/%s/recordsets/%s' % (recordset['domain_id'], recordset['id']) self._assert_exception('invalid_object', 400, self.client.put_json, url, body) def test_update_recordset_description_too_long(self): recordset = self.create_recordset(self.domain) body = {'description': 'x' * 161} url = '/zones/%s/recordsets/%s' % (recordset['domain_id'], recordset['id']) self._assert_exception('invalid_object', 400, self.client.put_json, url, body) def test_delete_recordset(self): recordset = self.create_recordset(self.domain) url = '/zones/%s/recordsets/%s' % (recordset['domain_id'], recordset['id']) response = self.client.delete(url, status=202) self.assertEqual('application/json', response.content_type) # Currently recordset does not have a status field. As there are no # records, the recordset action/status show up as 'NONE', 'ACTIVE' self.assertEqual('NONE', response.json['action']) self.assertEqual('ACTIVE', response.json['status']) # Check the zone's status is as expected response = self.client.get('/zones/%s' % recordset['domain_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) self.assertEqual('UPDATE', response.json['action']) self.assertEqual('PENDING', response.json['status']) def test_delete_recordset_with_records(self): # Create a recordset with one record recordset = self.create_recordset(self.domain, 'A') self.create_record(self.domain, recordset) url = '/zones/%s/recordsets/%s' % (recordset['domain_id'], recordset['id']) response = self.client.delete(url, status=202) self.assertEqual('application/json', response.content_type) self.assertEqual('DELETE', response.json['action']) self.assertEqual('PENDING', response.json['status']) # Check the zone's status is as expected response = self.client.get('/zones/%s' % recordset['domain_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) self.assertEqual('UPDATE', response.json['action']) self.assertEqual('PENDING', response.json['status']) @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._assert_exception('recordset_not_found', 404, self.client.delete, url) def test_delete_recordset_invalid_id(self): self._assert_invalid_uuid( self.client.delete, '/zones/%s/recordsets/%s') def test_metadata_exists(self): url = '/zones/%s/recordsets' % self.domain['id'] response = self.client.get(url) # Make sure the fields exist self.assertIn('metadata', response.json) self.assertIn('total_count', response.json['metadata']) def test_total_count(self): url = '/zones/%s/recordsets' % self.domain['id'] response = self.client.get(url) # The NS and SOA records are there by default self.assertEqual(2, response.json['metadata']['total_count']) # Create a recordset fixture = self.get_recordset_fixture(self.domain['name'], fixture=0) response = self.client.post_json( '/zones/%s/recordsets' % self.domain['id'], fixture) response = self.client.get(url) # Make sure total_count picked up the change self.assertEqual(3, response.json['metadata']['total_count']) def test_total_count_filtered_by_data(self): # Closes bug 1447325 url = '/zones/%s/recordsets' % self.domain['id'] # Create a recordset fixture = self.get_recordset_fixture(self.domain['name'], fixture=0) response = self.client.post_json( '/zones/%s/recordsets' % self.domain['id'], fixture) response = self.client.get(url) # Make sure total_count picked up the change self.assertEqual(3, response.json['metadata']['total_count']) url = '/zones/%s/recordsets?data=nyan' % self.domain['id'] response = self.client.get(url) self.assertEqual(0, response.json['metadata']['total_count']) url = '/zones/%s/recordsets?data=ns1.example.org.' % self.domain['id'] response = self.client.get(url) self.assertEqual(1, response.json['metadata']['total_count']) # Test paging new_domain = self.create_domain(name='example.net.') recordset = self.create_recordset(new_domain, 'A') self.create_record(new_domain, recordset, data='nyan') recordset = self.create_recordset(new_domain, 'CNAME') self.create_record(new_domain, recordset, data='nyan') # Even with paging enabled, total_count is still the total number of # recordsets matching the "data" filter url = '/zones/%s/recordsets?limit=1&data=nyan' % new_domain.id response = self.client.get(url) self.assertEqual(2, response.json['metadata']['total_count']) def test_total_count_pagination(self): # Create two recordsets fixture = self.get_recordset_fixture(self.domain['name'], fixture=0) response = self.client.post_json( '/zones/%s/recordsets' % self.domain['id'], fixture) fixture = self.get_recordset_fixture(self.domain['name'], fixture=1) response = self.client.post_json( '/zones/%s/recordsets' % self.domain['id'], fixture) # Paginate the recordsets to two, there should be four now url = '/zones/%s/recordsets?limit=2' % self.domain['id'] response = self.client.get(url) # There are two recordsets returned self.assertEqual(2, len(response.json['recordsets'])) # But there should be four in total (NS/SOA + the created) self.assertEqual(4, response.json['metadata']['total_count']) # Secondary Zones specific tests def test_get_secondary_zone_recordset(self): fixture = self.get_domain_fixture('SECONDARY', 1) fixture['email'] = '*****@*****.**' secondary = self.create_domain(**fixture) # Create a recordset recordset = self.create_recordset(secondary) url = '/zones/%s/recordsets/%s' % (secondary['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) 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.assertIsNone(response.json['updated_at']) self.assertEqual(recordset['name'], response.json['name']) self.assertEqual(recordset['type'], response.json['type']) def test_get_secondary_zone_recordsets(self): fixture = self.get_domain_fixture('SECONDARY', 1) fixture['email'] = '*****@*****.**' secondary = self.create_domain(**fixture) url = '/zones/%s/recordsets' % secondary['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('recordsets', response.json) self.assertIn('links', response.json) self.assertIn('self', response.json['links']) # We should start with 2 recordsets for SOA & NS self.assertEqual(1, len(response.json['recordsets'])) soa = self.central_service.find_recordset( self.admin_context, criterion={'domain_id': secondary['id'], 'type': 'SOA'}) data = [self.create_recordset(secondary, name='x-%s.%s' % (i, secondary['name'])) for i in range(0, 10)] data.insert(0, soa) self._assert_paging(data, url, key='recordsets') self._assert_invalid_paging(data, url, key='recordsets') def test_create_secondary_zone_recordset(self): fixture = self.get_domain_fixture('SECONDARY', 1) fixture['email'] = '*****@*****.**' secondary = self.create_domain(**fixture) fixture = self.get_recordset_fixture(secondary['name'], fixture=0) url = '/zones/%s/recordsets' % secondary['id'] self._assert_exception('forbidden', 403, self.client.post_json, url, fixture) def test_update_secondary_zone_recordset(self): fixture = self.get_domain_fixture('SECONDARY', 1) fixture['email'] = '*****@*****.**' secondary = self.create_domain(**fixture) # Set the context so that we can create a RRSet recordset = self.create_recordset(secondary) url = '/zones/%s/recordsets/%s' % (recordset['domain_id'], recordset['id']) self._assert_exception('forbidden', 403, self.client.put_json, url, {'ttl': 100}) def test_delete_secondary_zone_recordset(self): fixture = self.get_domain_fixture('SECONDARY', 1) fixture['email'] = '*****@*****.**' secondary = self.create_domain(**fixture) # Set the context so that we can create a RRSet recordset = self.create_recordset(secondary) url = '/zones/%s/recordsets/%s' % (recordset['domain_id'], recordset['id']) self._assert_exception('forbidden', 403, self.client.delete, url) def test_no_create_rs_deleting_zone(self): # Prepare a create fixture = self.get_recordset_fixture(self.domain['name'], fixture=0) body = fixture self.client.delete('/zones/%s' % self.domain['id'], status=202) self._assert_exception('bad_request', 400, self.client.post_json, '/zones/%s/recordsets' % self.domain['id'], body) def test_no_update_rs_deleting_zone(self): # Create a recordset recordset = self.create_recordset(self.domain) # Prepare an update body body = {'description': 'Tester'} url = '/zones/%s/recordsets/%s' % (recordset['domain_id'], recordset['id']) self.client.delete('/zones/%s' % self.domain['id'], status=202) self._assert_exception('bad_request', 400, self.client.put_json, url, body) def test_no_delete_rs_deleting_zone(self): # Create a recordset recordset = self.create_recordset(self.domain) url = '/zones/%s/recordsets/%s' % (recordset['domain_id'], recordset['id']) self.client.delete('/zones/%s' % self.domain['id'], status=202) self._assert_exception('bad_request', 400, self.client.delete, url) def test_invalid_recordset_filter(self): invalid_url = '/zones/%s/recordsets?action=NONE' % self.domain['id'] self._assert_exception( 'bad_request', 400, self.client.get, invalid_url)
class ApiV1zonesTest(ApiV1Test): def test_get_zone_schema(self): response = self.get('schemas/domain') self.assertIn('description', response.json) self.assertIn('links', response.json) self.assertIn('title', response.json) self.assertIn('id', response.json) self.assertIn('additionalProperties', response.json) self.assertIn('properties', response.json) self.assertIn('description', response.json['properties']) self.assertIn('created_at', response.json['properties']) self.assertIn('updated_at', response.json['properties']) self.assertIn('name', response.json['properties']) self.assertIn('email', response.json['properties']) self.assertIn('ttl', response.json['properties']) self.assertIn('serial', response.json['properties']) def test_get_zones_schema(self): response = self.get('schemas/domains') self.assertIn('description', response.json) self.assertIn('additionalProperties', response.json) self.assertIn('properties', response.json) self.assertIn('title', response.json) self.assertIn('id', response.json) def test_create_zone(self): # Create a zone fixture = self.get_zone_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_zone_junk(self): # Create a zone fixture = self.get_zone_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_zone', side_effect=messaging.MessagingTimeout()) def test_create_zone_timeout(self, _): # Create a zone fixture = self.get_zone_fixture(0) # V1 doesn't have these del fixture['type'] self.post('domains', data=fixture, status_code=504) @patch.object(central_service.Service, 'create_zone', side_effect=exceptions.DuplicateZone()) def test_create_zone_duplicate(self, _): # Create a zone fixture = self.get_zone_fixture(0) # V1 doesn't have these del fixture['type'] self.post('domains', data=fixture, status_code=409) def test_create_zone_null_ttl(self): # Create a zone fixture = self.get_zone_fixture(0) fixture['ttl'] = None self.post('domains', data=fixture, status_code=400) def test_create_zone_negative_ttl(self): # Create a zone fixture = self.get_zone_fixture(0) fixture['ttl'] = -1 self.post('domains', data=fixture, status_code=400) def test_create_zone_zero_ttl(self): # Create a zone fixture = self.get_zone_fixture(0) fixture['ttl'] = 0 self.post('domains', data=fixture, status_code=400) def test_create_zone_invalid_ttl(self): # Create a zone fixture = self.get_zone_fixture(0) fixture['ttl'] = "$?>&" self.post('domains', data=fixture, status_code=400) def test_create_zone_ttl_greater_than_max(self): fixture = self.get_zone_fixture(0) fixture['ttl'] = 2147483648 self.post('domains', data=fixture, status_code=400) def test_create_zone_utf_description(self): # Create a zone fixture = self.get_zone_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 zone, ensuring it succeeds, thus UTF-8 is supported self.post('domains', data=fixture) def test_create_zone_description_too_long(self): # Create a zone fixture = self.get_zone_fixture(0) fixture['description'] = "x" * 161 # Create the zone, ensuring it fails with a 400 self.post('domains', data=fixture, status_code=400) def test_create_zone_with_unwanted_attributes(self): zone_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 zone fixture = self.get_zone_fixture(0) fixture['id'] = zone_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 zone fixture = self.get_zone_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_zone_name_too_long(self): fixture = self.get_zone_fixture(0) long_name = 'a' * 255 + ".org." fixture['name'] = long_name response = self.post('domains', data=fixture, status_code=400) self.assertNotIn('id', response.json) def test_create_zone_name_is_not_present(self): fixture = self.get_zone_fixture(0) del fixture['name'] self.post('domains', data=fixture, status_code=400) def test_create_invalid_email(self): # Prepare a zone fixture = self.get_zone_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_create_zone_email_too_long(self): fixture = self.get_zone_fixture(0) long_email = 'a' * 255 + "@org.com" fixture['email'] = long_email response = self.post('domains', data=fixture, status_code=400) self.assertNotIn('id', response.json) def test_create_zone_email_not_present(self): fixture = self.get_zone_fixture(0) del fixture['email'] self.post('domains', data=fixture, status_code=400) def test_create_zone_twice(self): self.create_zone() with testtools.ExpectedException(exceptions.DuplicateZone): self.create_zone() def test_create_zone_pending_deletion(self): zone = self.create_zone() self.delete('domains/%s' % zone['id']) with testtools.ExpectedException(exceptions.DuplicateZone): self.create_zone() def test_get_zones(self): response = self.get('domains') self.assertIn('domains', response.json) self.assertEqual(0, len(response.json['domains'])) # Create a zone self.create_zone() response = self.get('domains') self.assertIn('domains', response.json) self.assertEqual(1, len(response.json['domains'])) # Create a second zone self.create_zone(fixture=1) response = self.get('domains') self.assertIn('domains', response.json) self.assertEqual(2, len(response.json['domains'])) def test_get_zone_servers(self): # Create a zone zone = self.create_zone() response = self.get('domains/%s/servers' % zone['id']) # Verify length of zone servers self.assertEqual(1, len(response.json['servers'])) @patch.object(central_service.Service, 'find_zones', side_effect=messaging.MessagingTimeout()) def test_get_zones_timeout(self, _): self.get('domains', status_code=504) def test_get_zone(self): # Create a zone zone = self.create_zone() response = self.get('domains/%s' % zone['id']) self.assertIn('id', response.json) self.assertEqual(response.json['id'], zone['id']) @patch.object(central_service.Service, 'find_zone', side_effect=messaging.MessagingTimeout()) def test_get_zone_timeout(self, _): # Create a zone zone = self.create_zone() self.get('domains/%s' % zone['id'], status_code=504) def test_get_zone_missing(self): self.get('domains/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', status_code=404) def test_get_zone_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_zone(self): # Create a zone zone = self.create_zone() data = {'email': 'prefix-%s' % zone['email']} response = self.put('domains/%s' % zone['id'], data=data) self.assertIn('id', response.json) self.assertEqual(response.json['id'], zone['id']) self.assertIn('email', response.json) self.assertEqual('prefix-%s' % zone['email'], response.json['email']) def test_update_zone_junk(self): # Create a zone zone = self.create_zone() data = {'email': 'prefix-%s' % zone['email'], 'junk': 'Junk Field'} self.put('domains/%s' % zone['id'], data=data, status_code=400) def test_update_zone_name_fail(self): # Create a zone zone = self.create_zone() data = {'name': 'renamed.com.'} self.put('domains/%s' % zone['id'], data=data, status_code=400) def test_update_zone_null_ttl(self): # Create a zone zone = self.create_zone() data = {'ttl': None} self.put('domains/%s' % zone['id'], data=data, status_code=400) def test_update_zone_negative_ttl(self): # Create a zone zone = self.create_zone() data = {'ttl': -1} self.put('domains/%s' % zone['id'], data=data, status_code=400) def test_update_zone_zero_ttl(self): # Create a zone zone = self.create_zone() data = {'ttl': 0} self.put('domains/%s' % zone['id'], data=data, status_code=400) @patch.object(central_service.Service, 'update_zone', side_effect=messaging.MessagingTimeout()) def test_update_zone_timeout(self, _): # Create a zone zone = self.create_zone() data = {'email': 'prefix-%s' % zone['email']} self.put('domains/%s' % zone['id'], data=data, status_code=504) @patch.object(central_service.Service, 'update_zone', side_effect=exceptions.DuplicateZone()) def test_update_zone_duplicate(self, _): # Create a zone zone = self.create_zone() data = {'email': 'prefix-%s' % zone['email']} self.put('domains/%s' % zone['id'], data=data, status_code=409) def test_update_zone_missing(self): data = {'email': '*****@*****.**'} self.put('domains/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', data=data, status_code=404) def test_update_zone_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_update_zone_ttl_greter_than_max(self): # Create a zone zone = self.create_zone() data = {'ttl': 2147483648} self.put('domains/%s' % zone['id'], data=data, status_code=400) def test_update_zone_invalid_email(self): # Create a zone zone = self.create_zone() invalid_emails = [ 'org', 'example.org', 'bla.example.org', 'org.', 'example.org.', 'bla.example.org.', 'bla.example.org.', 'a' * 255 + "@com", '' ] for invalid_email in invalid_emails: data = {'email': invalid_email} self.put('domains/%s' % zone['id'], data=data, status_code=400) def test_update_zone_description_too_long(self): # Create a zone zone = self.create_zone() invalid_des = 'a' * 165 data = {'description': invalid_des} self.put('domains/%s' % zone['id'], data=data, status_code=400) def test_update_zone_in_pending_deletion(self): zone = self.create_zone() self.delete('domains/%s' % zone['id']) self.put('domains/%s' % zone['id'], data={}, status_code=404) def test_delete_zone(self): # Create a zone zone = self.create_zone() self.delete('domains/%s' % zone['id']) # Simulate the zone having been deleted on the backend zone_serial = self.central_service.get_zone( self.admin_context, zone['id']).serial self.central_service.update_status( self.admin_context, zone['id'], "SUCCESS", zone_serial) # Ensure we can no longer fetch the zone self.get('domains/%s' % zone['id'], status_code=404) def test_zone_in_pending_deletion(self): zone1 = self.create_zone() self.create_zone(fixture=1) response = self.get('domains') self.assertEqual(2, len(response.json['domains'])) # Delete zone1 self.delete('domains/%s' % zone1['id']) # Ensure we can no longer list nor fetch the deleted zone response = self.get('domains') self.assertEqual(1, len(response.json['domains'])) self.get('domains/%s' % zone1['id'], status_code=404) @patch.object(central_service.Service, 'delete_zone', side_effect=messaging.MessagingTimeout()) def test_delete_zone_timeout(self, _): # Create a zone zone = self.create_zone() self.delete('domains/%s' % zone['id'], status_code=504) def test_delete_zone_missing(self): self.delete('domains/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', status_code=404) def test_delete_zone_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_zone_fixture('SECONDARY', 0) fixture['email'] = cfg.CONF['service:central'].managed_resource_email zone = self.create_zone(**fixture) self.get('domains/%s' % zone.id, status_code=404) def test_update_secondary_missing(self): fixture = self.get_zone_fixture('SECONDARY', 0) fixture['email'] = cfg.CONF['service:central'].managed_resource_email zone = self.create_zone(**fixture) self.put('domains/%s' % zone.id, {}, status_code=404) def test_delete_secondary_missing(self): fixture = self.get_zone_fixture('SECONDARY', 0) fixture['email'] = cfg.CONF['service:central'].managed_resource_email zone = self.create_zone(**fixture) self.delete('domains/%s' % zone.id, status_code=404) def test_get_zone_servers_from_secondary(self): fixture = self.get_zone_fixture('SECONDARY', 0) fixture['email'] = cfg.CONF['service:central'].managed_resource_email zone = self.create_zone(**fixture) self.get('domains/%s/servers' % zone.id, status_code=404)