def _multi_send(method, context, topic, msg, timeout=None, envelope=False, _msg_id=None): """ Wraps the sending of messages, dispatches to the matchmaker and sends message to all relevant hosts. """ conf = CONF LOG.debug(_("%(msg)s") % {'msg': ' '.join(map(pformat, (topic, msg)))}) queues = _get_matchmaker().queues(topic) LOG.debug(_("Sending message(s) to: %s"), queues) # Don't stack if we have no matchmaker results if len(queues) == 0: LOG.warn(_("No matchmaker results. Not casting.")) # While not strictly a timeout, callers know how to handle # this exception and a timeout isn't too big a lie. raise rpc_common.Timeout(_("No match from matchmaker.")) # This supports brokerless fanout (addresses > 1) for queue in queues: (_topic, ip_addr) = queue _addr = "tcp://%s:%s" % (ip_addr, conf.rpc_zmq_port) if method.__name__ == '_cast': eventlet.spawn_n(method, _addr, context, _topic, msg, timeout, envelope, _msg_id) return return method(_addr, context, _topic, msg, timeout, envelope)
def _error_callback(exc): if isinstance(exc, qpid_exceptions.Empty): LOG.debug( _('Timed out waiting for RPC response: %s') % str(exc)) raise rpc_common.Timeout() else: LOG.exception( _('Failed to consume message from queue: %s') % str(exc))
def _error_callback(exc): if isinstance(exc, socket.timeout): LOG.debug(_('Timed out waiting for RPC response: %s') % str(exc)) raise rpc_common.Timeout() else: LOG.exception(_('Failed to consume message from queue: %s') % str(exc)) info['do_consume'] = True
def multicall(conf, context, topic, msg, timeout=None): """Make a call that returns multiple times.""" check_serialize(msg) method = msg.get('method') if not method: return args = msg.get('args', {}) version = msg.get('version', None) namespace = msg.get('namespace', None) try: consumer = CONSUMERS[topic][0] except (KeyError, IndexError): raise rpc_common.Timeout("No consumers available") else: return consumer.call(context, version, method, namespace, args, timeout)
def __iter__(self): """Return a result until we get a reply with an 'ending" flag""" if self._done: raise StopIteration while True: try: data = self._dataqueue.get(timeout=self._timeout) result = self._process_data(data) except queue.Empty: self.done() raise rpc_common.Timeout() except Exception: with excutils.save_and_reraise_exception(): self.done() if self._got_ending: self.done() raise StopIteration if isinstance(result, Exception): self.done() raise result yield result
def call(self, context, version, method, namespace, args, timeout): done = eventlet.event.Event() def _inner(): ctxt = RpcContext.from_dict(context.to_dict()) try: rval = self.proxy.dispatch(context, version, method, namespace, **args) res = [] # Caller might have called ctxt.reply() manually for (reply, failure) in ctxt._response: if failure: six.reraise(failure[0], failure[1], failure[2]) res.append(reply) # if ending not 'sent'...we might have more data to # return from the function itself if not ctxt._done: if inspect.isgenerator(rval): for val in rval: res.append(val) else: res.append(rval) done.send(res) except rpc_common.ClientException as e: done.send_exception(e._exc_info[1]) except Exception as e: done.send_exception(e) thread = eventlet.greenthread.spawn(_inner) if timeout: start_time = time.time() while not done.ready(): eventlet.greenthread.sleep(1) cur_time = time.time() if (cur_time - start_time) > timeout: thread.kill() raise rpc_common.Timeout() return done.wait()
class ApiV2ZonesTest(ApiV2TestCase): __test__ = True def setUp(self): super(ApiV2ZonesTest, self).setUp() # Create a server self.create_server() def test_missing_accept(self): self.client.get('/zones/123', status=400) def test_bad_accept(self): self.client.get('/zones/123', headers={'Accept': 'test/goat'}, status=406) def test_missing_content_type(self): self.client.post('/zones', status=415) def test_bad_content_type(self): self.client.post('/zones', headers={'Content-type': 'test/goat'}, status=415) def test_create_zone(self): # Create a zone fixture = self.get_domain_fixture(0) response = self.client.post_json('/zones/', {'zone': fixture}) # Check the headers are what we expect self.assertEqual(201, response.status_int) self.assertEqual('application/json', response.content_type) # Check the body structure is what we expect self.assertIn('zone', response.json) self.assertIn('links', response.json['zone']) self.assertIn('self', response.json['zone']['links']) # Check the values returned are what we expect self.assertIn('id', response.json['zone']) self.assertIn('created_at', response.json['zone']) self.assertEqual('ACTIVE', response.json['zone']['status']) self.assertIsNone(response.json['zone']['updated_at']) for k in fixture: self.assertEqual(fixture[k], response.json['zone'][k]) def test_create_zone_validation(self): # NOTE: The schemas should be tested separatly to the API. So we # don't need to test every variation via the API itself. # Fetch a fixture fixture = self.get_domain_fixture(0) # Add a junk field to the wrapper body = {'zone': fixture, 'junk': 'Junk Field'} # Ensure it fails with a 400 response = self.client.post_json('/zones/', body, status=400) self.assertEqual(400, response.status_int) # Add a junk field to the body fixture['junk'] = 'Junk Field' # Ensure it fails with a 400 body = {'zone': fixture} self.client.post_json('/zones/', body, status=400) @patch.object(central_service.Service, 'create_domain', side_effect=rpc_common.Timeout()) def test_create_zone_timeout(self, _): fixture = self.get_domain_fixture(0) body = {'zone': fixture} self.client.post_json('/zones/', body, status=504) @patch.object(central_service.Service, 'create_domain', side_effect=exceptions.DuplicateDomain()) def test_create_zone_duplicate(self, _): fixture = self.get_domain_fixture(0) body = {'zone': fixture} self.client.post_json('/zones/', body, status=409) def test_get_zones(self): response = self.client.get('/zones/') # Check the headers are what we expect self.assertEqual(200, response.status_int) self.assertEqual('application/json', response.content_type) # Check the body structure is what we expect self.assertIn('zones', response.json) self.assertIn('links', response.json) self.assertIn('self', response.json['links']) # We should start with 0 zones self.assertEqual(0, len(response.json['zones'])) # Test with 1 zone self.create_domain() response = self.client.get('/zones/') self.assertIn('zones', response.json) self.assertEqual(1, len(response.json['zones'])) # test with 2 zones self.create_domain(fixture=1) response = self.client.get('/zones/') self.assertIn('zones', response.json) self.assertEqual(2, len(response.json['zones'])) @patch.object(central_service.Service, 'find_domains', side_effect=rpc_common.Timeout()) def test_get_zones_timeout(self, _): self.client.get('/zones/', status=504) def test_get_zone(self): # Create a zone zone = self.create_domain() response = self.client.get('/zones/%s' % zone['id'], headers=[('Accept', 'application/json')]) # Check the headers are what we expect self.assertEqual(200, response.status_int) self.assertEqual('application/json', response.content_type) # Check the body structure is what we expect self.assertIn('zone', response.json) self.assertIn('links', response.json['zone']) self.assertIn('self', response.json['zone']['links']) # Check the values returned are what we expect self.assertIn('id', response.json['zone']) self.assertIn('created_at', response.json['zone']) self.assertEqual('ACTIVE', response.json['zone']['status']) self.assertIsNone(response.json['zone']['updated_at']) self.assertEqual(zone['name'], response.json['zone']['name']) self.assertEqual(zone['email'], response.json['zone']['email']) @patch.object(central_service.Service, 'get_domain', side_effect=rpc_common.Timeout()) def test_get_zone_timeout(self, _): self.client.get('/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', headers={'Accept': 'application/json'}, status=504) @patch.object(central_service.Service, 'get_domain', side_effect=exceptions.DomainNotFound()) def test_get_zone_missing(self, _): self.client.get('/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', headers={'Accept': 'application/json'}, status=404) def test_get_zone_invalid_id(self): self.skip('We don\'t guard against this in APIv2 yet') # The letter "G" is not valid in a UUID self.client.get('/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff9GG', headers={'Accept': 'application/json'}, status=404) # Badly formed UUID self.client.get('/zones/2fdadfb1cf964259ac6bbb7b6d2ff9GG', headers={'Accept': 'application/json'}, status=404) # Integer self.client.get('/zones/12345', headers={'Accept': 'application/json'}, status=404) def test_update_zone(self): # Create a zone zone = self.create_domain() # Prepare an update body body = {'zone': {'email': 'prefix-%s' % zone['email']}} response = self.client.patch_json('/zones/%s' % zone['id'], body, status=200) # Check the headers are what we expect self.assertEqual(200, response.status_int) self.assertEqual('application/json', response.content_type) # Check the body structure is what we expect self.assertIn('zone', response.json) self.assertIn('links', response.json['zone']) self.assertIn('self', response.json['zone']['links']) self.assertIn('status', response.json['zone']) # Check the values returned are what we expect self.assertIn('id', response.json['zone']) self.assertIsNotNone(response.json['zone']['updated_at']) self.assertEqual('prefix-%s' % zone['email'], response.json['zone']['email']) def test_update_zone_validation(self): # NOTE: The schemas should be tested separatly to the API. So we # don't need to test every variation via the API itself. # Create a zone zone = self.create_domain() # Prepare an update body with junk in the wrapper body = { 'zone': { 'email': 'prefix-%s' % zone['email'] }, 'junk': 'Junk Field' } # Ensure it fails with a 400 self.client.patch_json('/zones/%s' % zone['id'], body, status=400) # Prepare an update body with junk in the body body = { 'zone': { 'email': 'prefix-%s' % zone['email'], 'junk': 'Junk Field' } } # Ensure it fails with a 400 self.client.patch_json('/zones/%s' % zone['id'], body, status=400) @patch.object(central_service.Service, 'get_domain', side_effect=exceptions.DuplicateDomain()) def test_update_zone_duplicate(self, _): # Prepare an update body body = {'zone': {'email': '*****@*****.**'}} # Ensure it fails with a 409 self.client.patch_json('/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', body, status=409) @patch.object(central_service.Service, 'get_domain', side_effect=rpc_common.Timeout()) def test_update_zone_timeout(self, _): # Prepare an update body body = {'zone': {'email': '*****@*****.**'}} # Ensure it fails with a 504 self.client.patch_json('/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', body, status=504) @patch.object(central_service.Service, 'get_domain', side_effect=exceptions.DomainNotFound()) def test_update_zone_missing(self, _): # Prepare an update body body = {'zone': {'email': '*****@*****.**'}} # Ensure it fails with a 404 self.client.patch_json('/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', body, status=404) def test_update_zone_invalid_id(self): self.skip('We don\'t guard against this in APIv2 yet') # Prepare an update body body = {'zone': {'email': '*****@*****.**'}} # The letter "G" is not valid in a UUID self.client.patch_json('/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff9GG', body, status=404) # Badly formed UUID self.client.patch_json('/zones/2fdadfb1cf964259ac6bbb7b6d2ff980', body, status=404) # Integer self.client.patch_json('/zones/12345', body, status=404) def test_delete_zone(self): zone = self.create_domain() self.client.delete('/zones/%s' % zone['id'], status=204) @patch.object(central_service.Service, 'delete_domain', side_effect=rpc_common.Timeout()) def test_delete_zone_timeout(self, _): self.client.delete('/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', status=504) @patch.object(central_service.Service, 'delete_domain', side_effect=exceptions.DomainNotFound()) def test_delete_zone_missing(self, _): self.client.delete('/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', status=404) def test_delete_zone_invalid_id(self): self.skip('We don\'t guard against this in APIv2 yet') # The letter "G" is not valid in a UUID self.client.delete('/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff9GG', status=404) # Badly formed UUID self.client.delete('/zones/2fdadfb1cf964259ac6bbb7b6d2ff980', status=404) # Integer self.client.delete('/zones/12345', status=404) # Zone import/export def test_missing_origin(self): self.client.post('/zones', self.get_zonefile_fixture(variant='noorigin'), headers={'Content-type': 'text/dns'}, status=400) def test_missing_soa(self): self.client.post('/zones', self.get_zonefile_fixture(variant='nosoa'), headers={'Content-type': 'text/dns'}, status=400) def test_malformed_zonefile(self): self.client.post('/zones', self.get_zonefile_fixture(variant='malformed'), headers={'Content-type': 'text/dns'}, status=400) def test_import_export(self): # Since v2 doesn't support getting records, import and export the # fixture, making sure they're the same according to dnspython post_response = self.client.post('/zones', self.get_zonefile_fixture(), headers={'Content-type': 'text/dns'}) get_response = self.client.get('/zones/%s' % post_response.json['zone']['id'], headers={'Accept': 'text/dns'}) exported_zonefile = get_response.body imported = dnszone.from_text(self.get_zonefile_fixture()) exported = dnszone.from_text(exported_zonefile) # Compare SOA emails, since zone comparison takes care of origin imported_soa = imported.get_rdataset(imported.origin, 'SOA') imported_email = imported_soa[0].rname.to_text() exported_soa = exported.get_rdataset(exported.origin, 'SOA') exported_email = exported_soa[0].rname.to_text() self.assertEqual(imported_email, exported_email) # Delete SOAs since they have, at the very least, different serials, # and dnspython considers that to be not equal. imported.delete_rdataset(imported.origin, 'SOA') exported.delete_rdataset(exported.origin, 'SOA') # Delete non-delegation NS, since they won't be the same imported.delete_rdataset(imported.origin, 'NS') exported.delete_rdataset(exported.origin, 'NS') self.assertEqual(imported, exported)
class ApiV1RecordsTest(ApiV1Test): __test__ = True def setUp(self): super(ApiV1RecordsTest, self).setUp() self.domain = self.create_domain() def test_create_record(self): fixture = self.get_record_fixture(self.domain['name'], 0) # 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']) @patch.object(central_service.Service, 'create_record') def test_create_record_trailing_slash(self, mock): # Create a record with a trailing slash self.post('domains/%s/records/' % self.domain['id'], data=self.get_record_fixture(self.domain['name'], 0)) # verify that the central service is called self.assertTrue(mock.called) def test_create_record_junk(self): fixture = self.get_record_fixture(self.domain['name'], 0) # 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_record_utf_description(self): fixture = self.get_record_fixture(self.domain['name'], 0) #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.domain['name'], 0) #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): # Create a record fixture = self.get_record_fixture(self.domain['name'], 0) 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) @patch.object(central_service.Service, 'create_record', side_effect=rpc_common.Timeout()) def test_create_record_timeout(self, _): fixture = self.get_record_fixture(self.domain['name'], 0) # 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.domain['name'], 0) fixture['name'] = '*.%s' % fixture['name'] # 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): # Prepare a record fixture = self.get_record_fixture(self.domain['name'], 0) fixture['type'] = 'SRV' fixture['name'] = '_sip._udp.%s' % fixture['name'] fixture['priority'] = 10 fixture['data'] = '0 5060 sip.%s' % self.domain['name'] # 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): # Prepare a record fixture = self.get_record_fixture(self.domain['name'], 0) fixture['type'] = 'SRV' fixture['name'] = '_sip._udp.%s' % fixture['name'] fixture['priority'] = 10 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): # Prepare a record fixture = self.get_record_fixture(self.domain['name'], 0) fixture['type'] = 'SRV' fixture['priority'] = 10 fixture['data'] = '0 5060 sip.%s' % self.domain['name'] invalid_names = [ '%s' % fixture['name'], '_udp.%s' % fixture['name'], 'sip._udp.%s' % fixture['name'], '_sip.udp.%s' % fixture['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.domain['name'], 0) 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']) self.assertIn('records', response.json) self.assertEqual(0, len(response.json['records'])) # Create a record self.create_record(self.domain) response = self.get('domains/%s/records' % self.domain['id']) self.assertIn('records', response.json) self.assertEqual(1, len(response.json['records'])) # Create a second record self.create_record(self.domain, fixture=1) response = self.get('domains/%s/records' % self.domain['id']) self.assertIn('records', response.json) self.assertEqual(2, len(response.json['records'])) @patch.object(central_service.Service, 'find_records') def test_get_records_trailing_slash(self, mock): self.get('domains/%s/records/' % self.domain['id']) # verify that the central service is called self.assertTrue(mock.called) @patch.object(central_service.Service, 'find_records', side_effect=rpc_common.Timeout()) 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(self): # Create a record record = self.create_record(self.domain) response = self.get('domains/%s/records/%s' % (self.domain['id'], record['id'])) self.assertIn('id', response.json) self.assertEqual(response.json['id'], record['id']) @patch.object(central_service.Service, 'get_record') def test_get_record_trailing_slash(self, mock): # Create a record record = self.create_record(self.domain) self.get('domains/%s/records/%s/' % (self.domain['id'], record['id'])) # verify that the central service is called self.assertTrue(mock.called) def test_update_record(self): # Create a record record = self.create_record(self.domain) data = {'name': 'prefix-%s' % record['name']} 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.assertIn('name', response.json) self.assertEqual(response.json['name'], 'prefix-%s' % record['name']) @patch.object(central_service.Service, 'update_record') def test_update_record_trailing_slash(self, mock): # Create a record record = self.create_record(self.domain) data = {'name': 'prefix-%s' % record['name']} self.put('domains/%s/records/%s/' % (self.domain['id'], record['id']), data=data) # verify that the central service is called self.assertTrue(mock.called) def test_update_record_junk(self): # Create a record record = self.create_record(self.domain) data = {'name': 'prefix-%s' % record['name'], 'junk': 'Junk Field'} 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) 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, 'update_record', side_effect=rpc_common.Timeout()) def test_update_record_timeout(self, _): # Create a record record = self.create_record(self.domain) 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.delete('domains/%s/records/%s' % (self.domain['id'], record['id'])) # Esnure 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, 'delete_record') def test_delete_record_trailing_slash(self, mock): # Create a record record = self.create_record(self.domain) self.delete('domains/%s/records/%s/' % (self.domain['id'], record['id'])) # verify that the central service is called self.assertTrue(mock.called) @patch.object(central_service.Service, 'delete_record', side_effect=rpc_common.Timeout()) def test_delete_record_timeout(self, _): # Create a record record = self.create_record(self.domain) 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)
class ApiV1ServersTest(ApiV1Test): __test__ = True 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']) @patch.object(central_service.Service, 'create_server') def test_create_server_trailing_slash(self, mock): # Create a server with a trailing slash self.post('servers/', data=self.get_server_fixture(0)) # verify that the central service is called self.assertTrue(mock.called) 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) @patch.object(central_service.Service, 'create_server', side_effect=rpc_common.Timeout()) 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, 'create_server', 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): response = self.get('servers') self.assertIn('servers', response.json) self.assertEqual(0, len(response.json['servers'])) # Create a server self.create_server() response = self.get('servers') self.assertIn('servers', response.json) self.assertEqual(1, len(response.json['servers'])) # Create a second server self.create_server(fixture=1) response = self.get('servers') self.assertIn('servers', response.json) self.assertEqual(2, len(response.json['servers'])) @patch.object(central_service.Service, 'find_servers') def test_get_servers_trailing_slash(self, mock): self.get('servers/') # verify that the central service is called self.assertTrue(mock.called) @patch.object(central_service.Service, 'find_servers', side_effect=rpc_common.Timeout()) def test_get_servers_timeout(self, _): self.get('servers', status_code=504) def test_get_server(self): # Create a server server = self.create_server() response = self.get('servers/%s' % server['id']) self.assertIn('id', response.json) self.assertEqual(response.json['id'], server['id']) @patch.object(central_service.Service, 'get_server') def test_get_server_trailing_slash(self, mock): # Create a server server = self.create_server() self.get('servers/%s/' % server['id']) # verify that the central service is called self.assertTrue(mock.called) @patch.object(central_service.Service, 'get_server', side_effect=rpc_common.Timeout()) def test_get_server_timeout(self, _): # Create a server server = self.create_server() self.get('servers/%s' % server['id'], status_code=504) def test_get_server_missing(self): self.get('servers/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', status_code=404) def test_update_server(self): # Create a server server = self.create_server() data = {'name': 'test.example.org.'} response = self.put('servers/%s' % server['id'], data=data) self.assertIn('id', response.json) self.assertEqual(response.json['id'], server['id']) self.assertIn('name', response.json) self.assertEqual(response.json['name'], 'test.example.org.') @patch.object(central_service.Service, 'update_server') def test_update_server_trailing_slash(self, mock): # Create a server server = self.create_server() data = {'name': 'test.example.org.'} self.put('servers/%s/' % server['id'], data=data) # verify that the central service is called self.assertTrue(mock.called) def test_update_server_junk(self): # Create a server server = self.create_server() data = {'name': 'test.example.org.', 'junk': 'Junk Field'} self.put('servers/%s' % server['id'], data=data, status_code=400) @patch.object(central_service.Service, 'update_server', side_effect=rpc_common.Timeout()) def test_update_server_timeout(self, _): # Create a server server = self.create_server() data = {'name': 'test.example.org.'} self.put('servers/%s' % server['id'], data=data, status_code=504) @patch.object(central_service.Service, 'update_server', side_effect=exceptions.DuplicateServer()) def test_update_server_duplicate(self, _): server = self.create_server() data = {'name': 'test.example.org.'} self.put('servers/%s' % server['id'], data=data, status_code=409) def test_update_server_missing(self): data = {'name': 'test.example.org.'} self.get('servers/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', data=data, status_code=404) def test_delete_server(self): # Create a server server = self.create_server() # Create a second server so that we can delete the first # because the last remaining server is not allowed to be deleted server2 = self.create_server(fixture=1) # Now delete the server self.delete('servers/%s' % server['id']) # Ensure we can no longer fetch the deleted server self.get('servers/%s' % server['id'], status_code=404) # Also, verify we cannot delete last remaining server self.delete('servers/%s' % server2['id'], status_code=400) @patch.object(central_service.Service, 'delete_server') def test_delete_server_trailing_slash(self, mock): # Create a server server = self.create_server() self.delete('servers/%s/' % server['id']) # verify that the central service is called self.assertTrue(mock.called) @patch.object(central_service.Service, 'delete_server', side_effect=rpc_common.Timeout()) def test_delete_server_timeout(self, _): # Create a server server = self.create_server() self.delete('servers/%s' % server['id'], status_code=504) def test_delete_server_missing(self): self.delete('servers/9fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', status_code=404)
class ApiV1DomainsTest(ApiV1Test): __test__ = True def test_create_domain(self): # Create a server self.create_server() # Create a domain fixture = self.get_domain_fixture(0) response = self.post('domains', data=fixture) self.assertIn('id', response.json) self.assertIn('name', response.json) self.assertEqual(response.json['name'], fixture['name']) @patch.object(central_service.Service, 'create_domain') def test_create_domain_trailing_slash(self, mock): # Create a server self.create_server() self.post('domains/', data=self.get_domain_fixture(0)) # verify that the central service is called self.assertTrue(mock.called) def test_create_domain_junk(self): # Create a server self.create_server() # Create a domain fixture = self.get_domain_fixture(0) # Add a junk property fixture['junk'] = 'Junk Field' # Ensure it fails with a 400 self.post('domains', data=fixture, status_code=400) def test_create_domain_no_servers(self): # Create a domain fixture = self.get_domain_fixture(0) self.post('domains', data=fixture, status_code=500) @patch.object(central_service.Service, 'create_domain', side_effect=rpc_common.Timeout()) def test_create_domain_timeout(self, _): # Create a domain fixture = self.get_domain_fixture(0) self.post('domains', data=fixture, status_code=504) @patch.object(central_service.Service, 'create_domain', side_effect=exceptions.DuplicateDomain()) def test_create_domain_duplicate(self, _): # Create a domain fixture = self.get_domain_fixture(0) self.post('domains', data=fixture, status_code=409) def test_create_domain_null_ttl(self): # Create a domain fixture = self.get_domain_fixture(0) fixture['ttl'] = None self.post('domains', data=fixture, status_code=400) def test_create_domain_negative_ttl(self): # Create a domain fixture = self.get_domain_fixture(0) fixture['ttl'] = -1 self.post('domains', data=fixture, status_code=400) def test_create_domain_utf_description(self): # Create a server self.create_server() # Create a domain fixture = self.get_domain_fixture(0) #Give it a UTF-8 filled description fixture['description'] = "utf-8:2H₂+O₂⇌2H₂O,R=4.7kΩ,⌀200mm∮E⋅da=Q,n" \ ",∑f(i)=∏g(i),∀x∈ℝ:⌈x⌉" #Create the domain, ensuring it suceeds, thus UTF-8 is supported self.post('domains', data=fixture) def test_create_domain_description_too_long(self): # Create a server self.create_server() # Create a domain fixture = self.get_domain_fixture(0) fixture['description'] = "x" * 161 #Create the domain, ensuring it fails with a 400 self.post('domains', data=fixture, status_code=400) def test_create_invalid_name(self): # Prepare a domain fixture = self.get_domain_fixture(0) invalid_names = [ 'org', 'example.org', 'example.321', ] for invalid_name in invalid_names: fixture['name'] = invalid_name # Create a record response = self.post('domains', data=fixture, status_code=400) self.assertNotIn('id', response.json) def test_create_invalid_email(self): # Prepare a domain fixture = self.get_domain_fixture(0) invalid_emails = [ 'org', 'example.org', 'bla.example.org', 'org.', 'example.org.', 'bla.example.org.', 'bla.example.org.', ] for invalid_email in invalid_emails: fixture['email'] = invalid_email # Create a record response = self.post('domains', data=fixture, status_code=400) self.assertNotIn('id', response.json) def test_get_domains(self): response = self.get('domains') self.assertIn('domains', response.json) self.assertEqual(0, len(response.json['domains'])) # Create a domain self.create_domain() response = self.get('domains') self.assertIn('domains', response.json) self.assertEqual(1, len(response.json['domains'])) # Create a second domain self.create_domain(fixture=1) response = self.get('domains') self.assertIn('domains', response.json) self.assertEqual(2, len(response.json['domains'])) @patch.object(central_service.Service, 'find_domains') def test_get_domains_trailing_slash(self, mock): self.get('domains/') # verify that the central service is called self.assertTrue(mock.called) @patch.object(central_service.Service, 'find_domains', side_effect=rpc_common.Timeout()) def test_get_domains_timeout(self, _): self.get('domains', status_code=504) def test_get_domain(self): # Create a domain domain = self.create_domain() response = self.get('domains/%s' % domain['id']) self.assertIn('id', response.json) self.assertEqual(response.json['id'], domain['id']) @patch.object(central_service.Service, 'get_domain') def test_get_domain_trailing_slash(self, mock): # Create a domain domain = self.create_domain() self.get('domains/%s/' % domain['id']) # verify that the central service is called self.assertTrue(mock.called) @patch.object(central_service.Service, 'get_domain', side_effect=rpc_common.Timeout()) def test_get_domain_timeout(self, _): # Create a domain domain = self.create_domain() self.get('domains/%s' % domain['id'], status_code=504) def test_get_domain_missing(self): self.get('domains/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', status_code=404) def test_get_domain_invalid_id(self): # The letter "G" is not valid in a UUID self.get('domains/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff9GG', status_code=404) self.get('domains/2fdadfb1cf964259ac6bbb7b6d2ff980', status_code=404) def test_update_domain(self): # Create a domain domain = self.create_domain() data = {'email': 'prefix-%s' % domain['email']} response = self.put('domains/%s' % domain['id'], data=data) self.assertIn('id', response.json) self.assertEqual(response.json['id'], domain['id']) self.assertIn('email', response.json) self.assertEqual(response.json['email'], 'prefix-%s' % domain['email']) @patch.object(central_service.Service, 'update_domain') def test_update_domain_trailing_slash(self, mock): # Create a domain domain = self.create_domain() data = {'email': 'prefix-%s' % domain['email']} self.put('domains/%s/' % domain['id'], data=data) # verify that the central service is called self.assertTrue(mock.called) def test_update_domain_junk(self): # Create a domain domain = self.create_domain() data = {'email': 'prefix-%s' % domain['email'], 'junk': 'Junk Field'} self.put('domains/%s' % domain['id'], data=data, status_code=400) def test_update_domain_name_fail(self): # Create a domain domain = self.create_domain() data = {'name': 'renamed.com.'} self.put('domains/%s' % domain['id'], data=data, status_code=400) def test_update_domain_null_ttl(self): # Create a domain domain = self.create_domain() data = {'ttl': None} self.put('domains/%s' % domain['id'], data=data, status_code=400) @patch.object(central_service.Service, 'update_domain', side_effect=rpc_common.Timeout()) def test_update_domain_timeout(self, _): # Create a domain domain = self.create_domain() data = {'email': 'prefix-%s' % domain['email']} self.put('domains/%s' % domain['id'], data=data, status_code=504) @patch.object(central_service.Service, 'update_domain', side_effect=exceptions.DuplicateDomain()) def test_update_domain_duplicate(self, _): # Create a domain domain = self.create_domain() data = {'email': 'prefix-%s' % domain['email']} self.put('domains/%s' % domain['id'], data=data, status_code=409) def test_update_domain_missing(self): data = {'email': '*****@*****.**'} self.put('domains/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', data=data, status_code=404) def test_update_domain_invalid_id(self): data = {'email': '*****@*****.**'} # The letter "G" is not valid in a UUID self.put('domains/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff9GG', data=data, status_code=404) self.put('domains/2fdadfb1cf964259ac6bbb7b6d2ff980', data=data, status_code=404) def test_delete_domain(self): # Create a domain domain = self.create_domain() self.delete('domains/%s' % domain['id']) # Esnure we can no longer fetch the domain self.get('domains/%s' % domain['id'], status_code=404) @patch.object(central_service.Service, 'delete_domain') def test_delete_domain_trailing_slash(self, mock): # Create a domain domain = self.create_domain() self.delete('domains/%s/' % domain['id']) # verify that the central service is called self.assertTrue(mock.called) @patch.object(central_service.Service, 'delete_domain', side_effect=rpc_common.Timeout()) def test_delete_domain_timeout(self, _): # Create a domain domain = self.create_domain() self.delete('domains/%s' % domain['id'], status_code=504) def test_delete_domain_missing(self): self.delete('domains/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', status_code=404) def test_delete_domain_invalid_id(self): # The letter "G" is not valid in a UUID self.delete('domains/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff9GG', status_code=404) self.delete('domains/2fdadfb1cf964259ac6bbb7b6d2ff980', status_code=404)
class ApiV2RecordSetsTest(ApiV2TestCase): def setUp(self): super(ApiV2RecordSetsTest, self).setUp() # Create a domain self.domain = self.create_domain() def test_create_recordset(self): # Create a zone fixture = self.get_recordset_fixture(self.domain['name'], fixture=0) response = self.client.post_json( '/zones/%s/recordsets' % self.domain['id'], {'recordset': fixture}) # Check the headers are what we expect self.assertEqual(201, response.status_int) self.assertEqual('application/json', response.content_type) # Check the body structure is what we expect self.assertIn('recordset', response.json) self.assertIn('links', response.json['recordset']) self.assertIn('self', response.json['recordset']['links']) # Check the values returned are what we expect self.assertIn('id', response.json['recordset']) self.assertIn('created_at', response.json['recordset']) self.assertIsNone(response.json['recordset']['updated_at']) for k in fixture: self.assertEqual(fixture[k], response.json['recordset'][k]) def test_create_recordset_validation(self): # NOTE: The schemas should be tested separatly to the API. So we # don't need to test every variation via the API itself. # Fetch a fixture fixture = self.get_recordset_fixture(self.domain['name'], fixture=0) # Add a junk field to the wrapper body = {'recordset': fixture, 'junk': 'Junk Field'} # Ensure it fails with a 400 response = self.client.post_json('/zones/%s/recordsets' % self.domain['id'], body, status=400) self.assertEqual(400, response.status_int) # Add a junk field to the body fixture['junk'] = 'Junk Field' body = {'recordset': fixture} # Ensure it fails with a 400 response = self.client.post_json('/zones/%s/recordsets' % self.domain['id'], body, status=400) @patch.object(central_service.Service, 'create_recordset', side_effect=rpc_common.Timeout()) def test_create_recordset_timeout(self, _): fixture = self.get_recordset_fixture(self.domain['name'], fixture=0) body = {'recordset': fixture} self.client.post_json('/zones/%s/recordsets' % self.domain['id'], body, status=504) @patch.object(central_service.Service, 'create_recordset', side_effect=exceptions.DuplicateDomain()) def test_create_recordset_duplicate(self, _): fixture = self.get_recordset_fixture(self.domain['name'], fixture=0) body = {'recordset': fixture} self.client.post_json('/zones/%s/recordsets' % self.domain['id'], body, status=409) def test_create_recordset_invalid_domain(self): fixture = self.get_recordset_fixture(self.domain['name'], fixture=0) body = {'recordset': fixture} self.client.post_json( '/zones/ba751950-6193-11e3-949a-0800200c9a66/recordsets', body, status=404) def test_get_recordsets(self): response = self.client.get('/zones/%s/recordsets' % self.domain['id']) # Check the headers are what we expect self.assertEqual(200, response.status_int) self.assertEqual('application/json', response.content_type) # Check the body structure is what we expect self.assertIn('recordsets', response.json) self.assertIn('links', response.json) self.assertIn('self', response.json['links']) # We should start with 0 recordsets self.assertEqual(0, len(response.json['recordsets'])) data = [ self.create_recordset(self.domain, name='x-%s.%s' % (i, self.domain['name'])) for i in xrange(0, 10) ] url = '/zones/%s/recordsets' % self.domain['id'] self._assert_paging(data, url, key='recordsets') @patch.object(central_service.Service, 'find_recordsets', side_effect=rpc_common.Timeout()) def test_get_recordsets_timeout(self, _): self.client.get( '/zones/ba751950-6193-11e3-949a-0800200c9a66/recordsets', status=504) def test_get_recordset(self): # Create a recordset recordset = self.create_recordset(self.domain) url = '/zones/%s/recordsets/%s' % (self.domain['id'], recordset['id']) response = self.client.get(url) # Check the headers are what we expect self.assertEqual(200, response.status_int) self.assertEqual('application/json', response.content_type) # Check the body structure is what we expect self.assertIn('recordset', response.json) self.assertIn('links', response.json['recordset']) self.assertIn('self', response.json['recordset']['links']) # Check the values returned are what we expect self.assertIn('id', response.json['recordset']) self.assertIn('created_at', response.json['recordset']) self.assertIsNone(response.json['recordset']['updated_at']) self.assertEqual(recordset['name'], response.json['recordset']['name']) self.assertEqual(recordset['type'], response.json['recordset']['type']) @patch.object(central_service.Service, 'get_recordset', side_effect=rpc_common.Timeout()) def test_get_recordset_timeout(self, _): self.client.get('/zones/%s/recordsets/ba751950-6193-11e3-949a-0800200c' '9a66' % self.domain['id'], headers={'Accept': 'application/json'}, status=504) @patch.object(central_service.Service, 'get_recordset', side_effect=exceptions.RecordSetNotFound()) def test_get_recordset_missing(self, _): self.client.get('/zones/%s/recordsets/ba751950-6193-11e3-949a-0800200c' '9a66' % self.domain['id'], headers={'Accept': 'application/json'}, status=404) def test_get_recordset_invalid_id(self): self.skip('We don\'t guard against this in APIv2 yet') def test_update_recordset(self): # Create a recordset recordset = self.create_recordset(self.domain) # Prepare an update body body = {'recordset': {'description': 'Tester'}} url = '/zones/%s/recordsets/%s' % (recordset['domain_id'], recordset['id']) response = self.client.patch_json(url, body, status=200) # Check the headers are what we expect self.assertEqual(200, response.status_int) self.assertEqual('application/json', response.content_type) # Check the body structure is what we expect self.assertIn('recordset', response.json) self.assertIn('links', response.json['recordset']) self.assertIn('self', response.json['recordset']['links']) # Check the values returned are what we expect self.assertIn('id', response.json['recordset']) self.assertIsNotNone(response.json['recordset']['updated_at']) self.assertEqual('Tester', response.json['recordset']['description']) def test_update_recordset_validation(self): # NOTE: The schemas should be tested separatly to the API. So we # don't need to test every variation via the API itself. # Create a zone recordset = self.create_recordset(self.domain) # Prepare an update body with junk in the wrapper body = {'recordset': {'description': 'Tester'}, 'junk': 'Junk Field'} # Ensure it fails with a 400 url = '/zones/%s/recordsets/%s' % (recordset['domain_id'], recordset['id']) self.client.patch_json(url, body, status=400) # Prepare an update body with junk in the body body = {'recordset': {'description': 'Tester', 'junk': 'Junk Field'}} # Ensure it fails with a 400 url = '/zones/%s/recordsets/%s' % (recordset['domain_id'], recordset['id']) self.client.patch_json(url, body, status=400) @patch.object(central_service.Service, 'get_recordset', side_effect=exceptions.DuplicateRecordSet()) def test_update_recordset_duplicate(self, _): # Prepare an update body body = {'recordset': {'description': 'Tester'}} # Ensure it fails with a 409 url = ('/zones/%s/recordsets/ba751950-6193-11e3-949a-0800200c9a66' % (self.domain['id'])) self.client.patch_json(url, body, status=409) @patch.object(central_service.Service, 'get_recordset', side_effect=rpc_common.Timeout()) def test_update_recordset_timeout(self, _): # Prepare an update body body = {'recordset': {'description': 'Tester'}} # Ensure it fails with a 504 url = ('/zones/%s/recordsets/ba751950-6193-11e3-949a-0800200c9a66' % (self.domain['id'])) self.client.patch_json(url, body, status=504) @patch.object(central_service.Service, 'get_recordset', side_effect=exceptions.RecordSetNotFound()) def test_update_recordset_missing(self, _): # Prepare an update body body = {'recordset': {'description': 'Tester'}} # Ensure it fails with a 404 url = ('/zones/%s/recordsets/ba751950-6193-11e3-949a-0800200c9a66' % (self.domain['id'])) self.client.patch_json(url, body, status=404) def test_update_recordset_invalid_id(self): self.skip('We don\'t guard against this in APIv2 yet') def test_delete_recordset(self): recordset = self.create_recordset(self.domain) url = '/zones/%s/recordsets/%s' % (recordset['domain_id'], recordset['id']) self.client.delete(url, status=204) @patch.object(central_service.Service, 'delete_recordset', side_effect=rpc_common.Timeout()) def test_delete_recordset_timeout(self, _): url = ('/zones/%s/recordsets/ba751950-6193-11e3-949a-0800200c9a66' % (self.domain['id'])) self.client.delete(url, status=504) @patch.object(central_service.Service, 'delete_recordset', side_effect=exceptions.RecordSetNotFound()) def test_delete_recordset_missing(self, _): url = ('/zones/%s/recordsets/ba751950-6193-11e3-949a-0800200c9a66' % (self.domain['id'])) self.client.delete(url, status=404) def test_delete_recordset_invalid_id(self): self.skip('We don\'t guard against this in APIv2 yet')