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')
Beispiel #2
0
    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 messaging.MessagingTimeout('No reply on topic %s' %
                                                 target.topic)

        return None
Beispiel #3
0
 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 messaging.MessagingTimeout('Timed out waiting for a reply')
Beispiel #4
0
 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')
Beispiel #5
0
class ApiV2NameServersTest(ApiV2TestCase):
    def setUp(self):
        super(ApiV2NameServersTest, self).setUp()

        # Create a domain
        self.domain = self.create_domain()

    def test_get_nameservers(self):
        url = '/zones/%s/nameservers' % 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('nameservers', response.json)
        self.assertIn('links', response.json)
        self.assertIn('self', response.json['links'])

        # We should start with 0 nameservers
        self.assertEqual(1, len(response.json['nameservers']))

        servers = self.central_service.get_domain_servers(
            self.admin_context, self.domain['id'])

        self.assertEqual(servers[0]['id'],
                         response.json['nameservers'][0]['id'])
        self.assertEqual(servers[0]['name'],
                         response.json['nameservers'][0]['name'])

        self.create_server(name='nsx.mydomain.com.')

        response = self.client.get(url)

        self.assertEqual(2, len(response.json['nameservers']))

    def test_get_nameservers_invalid_id(self):
        self._assert_invalid_uuid(self.client.get, '/zones/%s/nameservers')

    @patch.object(central_service.Service,
                  'get_domain_servers',
                  side_effect=messaging.MessagingTimeout())
    def test_get_nameservers_timeout(self, _):
        url = '/zones/ba751950-6193-11e3-949a-0800200c9a66/nameservers'

        self._assert_exception('timeout', 504, self.client.get, url)
Beispiel #6
0
 def test_get_dvr_mac_address_retried_max(self):
     raise_timeout = 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)
Beispiel #7
0
 def test_get_dvr_mac_address_retried(self):
     valid_entry = {'host': 'cn1', 'mac_address': 'aa:22:33:44:55:66'}
     raise_timeout = 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 _poll_connection(self, msg_id, timeout):
        while True:
            while self.incoming:
                message_data = self.incoming.pop(0)

                incoming_msg_id = message_data.pop('_msg_id', None)
                if incoming_msg_id == msg_id:
                    return self._process_reply(message_data)

                self.waiters.put(incoming_msg_id, message_data)

            try:
                self.conn.consume(limit=1, timeout=timeout)
            except rpc_common.Timeout:
                raise messaging.MessagingTimeout('Timed out waiting for a '
                                                 'reply to message ID %s'
                                                 % msg_id)
Beispiel #9
0
 def get(self, msg_id, timeout):
     try:
         return self._queues[msg_id].get(block=True, timeout=timeout)
     except moves.queue.Empty:
         raise messaging.MessagingTimeout('Timed out waiting for a reply '
                                          'to message ID %s' % msg_id)
Beispiel #10
0
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)
Beispiel #11
0
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'])

    @patch.object(central_service.Service, 'create_record')
    def test_create_record_trailing_slash(self, mock):
        fixture = self.get_record_fixture(self.recordset['type'])
        fixture.update({
            'name': self.recordset['name'],
            'type': self.recordset['type'],
        })

        # Create a record with a trailing slash
        self.post('domains/%s/records/' % self.domain['id'],
                  data=fixture)

        # verify that the central service is called
        self.assertTrue(mock.called)

    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_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)

    @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'])
        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.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'])

        self.assertIn('records', response.json)
        self.assertEqual(0, len(response.json['records']))

        # Create a record
        self.create_record(self.domain, self.recordset)

        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, self.recordset, 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=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(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'])

    @patch.object(central_service.Service, 'get_recordset')
    def test_get_record_trailing_slash(self, mock):
        # Create a record
        record = self.create_record(self.domain, self.recordset)

        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, 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)

    @patch.object(central_service.Service, 'update_record')
    def test_update_record_trailing_slash(self, mock):
        # Create a record
        record = self.create_record(self.domain, self.recordset)

        data = {'ttl': 100}

        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, 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_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, 'get_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']))

        # 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, 'get_domain')
    def test_delete_record_trailing_slash(self, mock):
        # Create a record
        record = self.create_record(self.domain, self.recordset)

        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, 'get_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)
Beispiel #12
0
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_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)

        # Add a junk field to the wrapper
        body = {'recordset': fixture, 'junk': 'Junk Field'}

        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)

        # Add a junk field to the body
        fixture['junk'] = 'Junk Field'
        body = {'recordset': 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 = {'recordset': 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 = {'recordset': 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 = {'recordset': 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 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)]

        self._assert_paging(data, url, key='recordsets')

        self._assert_invalid_paging(data, url, key='recordsets')

    def test_get_recordsets_invalid_id(self):
        self._assert_invalid_uuid(self.client.get, '/zones/%s/recordsets')

    @patch.object(central_service.Service, 'find_recordsets',
                  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_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'])

    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 = {'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_invalid_id(self):
        self._assert_invalid_uuid(
            self.client.patch_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 = {'recordset': {'description': 'Tester'}, '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.patch_json,
                               url, body)

        # Prepare an update body with junk in the body
        body = {'recordset': {'description': 'Tester', 'junk': 'Junk Field'}}

        # Ensure it fails with a 400
        self._assert_exception('invalid_object', 400, self.client.patch_json,
                               url, body)

    @patch.object(central_service.Service, 'get_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._assert_exception('duplicate_recordset', 409,
                               self.client.patch_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 = {'recordset': {'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.patch_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 = {'recordset': {'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.patch_json, url, body)

    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=messaging.MessagingTimeout())
    def test_delete_recordset_timeout(self, _):
        url = ('/zones/%s/recordsets/ba751950-6193-11e3-949a-0800200c9a66'
               % (self.domain['id']))

        self._assert_exception('timeout', 504, self.client.delete, url)

    @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')
Beispiel #13
0
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/', {'tsigkey': 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('tsigkey', response.json)
        self.assertIn('links', response.json['tsigkey'])
        self.assertIn('self', response.json['tsigkey']['links'])

        # Check the generated values returned are what we expect
        self.assertIn('id', response.json['tsigkey'])
        self.assertIn('created_at', response.json['tsigkey'])
        self.assertIsNone(response.json['tsigkey']['updated_at'])

        # Check the supplied values returned are what we expect
        self.assertDictContainsSubset(fixture, response.json['tsigkey'])

    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 wrapper
        body = {'tsigkey': fixture, 'junk': 'Junk Field'}

        # Ensure it fails with a 400
        self._assert_exception('invalid_object', 400, self.client.post_json,
                               '/tsigkeys', body)

        # Add a junk field to the body
        fixture['junk'] = 'Junk Field'

        # Ensure it fails with a 400
        body = {'tsigkey': 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 = {'tsigkey': 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('tsigkey', response.json)
        self.assertIn('links', response.json['tsigkey'])
        self.assertIn('self', response.json['tsigkey']['links'])

        # Check the generated values returned are what we expect
        self.assertIn('id', response.json['tsigkey'])
        self.assertIn('created_at', response.json['tsigkey'])
        self.assertIsNone(response.json['tsigkey']['updated_at'])

        # Check the supplied values returned are what we expect
        self.assertEqual(tsigkey.name, response.json['tsigkey']['name'])
        self.assertEqual(
            tsigkey.algorithm, response.json['tsigkey']['algorithm'])
        self.assertEqual(tsigkey.secret, response.json['tsigkey']['secret'])
        self.assertEqual(tsigkey.scope, response.json['tsigkey']['scope'])
        self.assertEqual(
            tsigkey.resource_id, response.json['tsigkey']['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 = {'tsigkey': {'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('tsigkey', response.json)
        self.assertIn('links', response.json['tsigkey'])
        self.assertIn('self', response.json['tsigkey']['links'])

        # Check the values returned are what we expect
        self.assertIn('id', response.json['tsigkey'])
        self.assertIsNotNone(response.json['tsigkey']['updated_at'])
        self.assertEqual('prefix-%s' % tsigkey['secret'],
                         response.json['tsigkey']['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 = {'tsigkey': {'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 = {'tsigkey': {'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 = {'tsigkey': {'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)
Beispiel #14
0
class ApiV2ZonesTest(ApiV2TestCase):
    def setUp(self):
        super(ApiV2ZonesTest, self).setUp()

        # Create a server
        self.create_server()

        # Create the default TLDs
        self.create_default_tlds()

    def test_create_zone(self):
        # Create a zone
        fixture = self.get_domain_fixture(0)
        response = self.client.post_json('/zones/', {'zone': fixture})

        # Check the headers are what we expect
        self.assertEqual(201, response.status_int)
        self.assertEqual('application/json', response.content_type)

        # Check the body structure is what we expect
        self.assertIn('zone', response.json)
        self.assertIn('links', response.json['zone'])
        self.assertIn('self', response.json['zone']['links'])

        # Check the values returned are what we expect
        self.assertIn('id', response.json['zone'])
        self.assertIn('created_at', response.json['zone'])
        self.assertEqual('ACTIVE', response.json['zone']['status'])
        self.assertIsNone(response.json['zone']['updated_at'])

        for k in fixture:
            self.assertEqual(fixture[k], response.json['zone'][k])

    def test_create_zone_validation(self):
        # NOTE: The schemas should be tested separately to the API. So we
        #       don't need to test every variation via the API itself.
        # Fetch a fixture
        fixture = self.get_domain_fixture(0)

        # Add a junk field to the wrapper
        body = {'zone': fixture, 'junk': 'Junk Field'}

        # Ensure it fails with a 400
        self._assert_exception('invalid_object', 400, self.client.post_json,
                               '/zones', body)

        # Add a junk field to the body
        fixture['junk'] = 'Junk Field'

        # Ensure it fails with a 400
        body = {'zone': fixture}

        self._assert_exception('invalid_object', 400, self.client.post_json,
                               '/zones', body)

    def test_create_zone_body_validation(self):
        fixture = self.get_domain_fixture(0)
        # Add id to the body
        fixture['id'] = '2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980'
        # Ensure it fails with a 400
        body = {'zone': fixture}
        self._assert_exception('invalid_object', 400, self.client.post_json,
                               '/zones', body)

        fixture = self.get_domain_fixture(0)
        # Add created_at to the body
        fixture['created_at'] = '2014-03-12T19:07:53.000000'
        # Ensure it fails with a 400
        body = {'zone': fixture}
        self._assert_exception('invalid_object', 400, self.client.post_json,
                               '/zones', body)

    def test_create_zone_invalid_name(self):
        # Try to create a zone with an invalid name
        fixture = self.get_domain_fixture(-1)

        # Ensure it fails with a 400
        self._assert_exception('invalid_object', 400, self.client.post_json,
                               '/zones', {'zone': fixture})

    @patch.object(central_service.Service,
                  'create_domain',
                  side_effect=messaging.MessagingTimeout())
    def test_create_zone_timeout(self, _):
        fixture = self.get_domain_fixture(0)

        body = {'zone': fixture}

        self._assert_exception('timeout', 504, self.client.post_json,
                               '/zones/', body)

    @patch.object(central_service.Service,
                  'create_domain',
                  side_effect=exceptions.DuplicateDomain())
    def test_create_zone_duplicate(self, _):
        fixture = self.get_domain_fixture(0)

        body = {'zone': fixture}

        self._assert_exception('duplicate_domain', 409, self.client.post_json,
                               '/zones/', body)

    def test_create_zone_missing_content_type(self):
        self._assert_exception('unsupported_content_type', 415,
                               self.client.post, '/zones')

    def test_create_zone_bad_content_type(self):
        self._assert_exception('unsupported_content_type',
                               415,
                               self.client.post,
                               '/zones',
                               headers={'Content-type': 'test/goat'})

    def test_zone_invalid_url(self):
        url = '/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980/invalid'
        self._assert_exception('not_found',
                               404,
                               self.client.get,
                               url,
                               headers={'Accept': 'application/json'})
        self._assert_exception('not_found', 404, self.client.patch_json, url)
        self._assert_exception('not_found', 404, self.client.delete, url)

        # Pecan returns a 405 for post
        response = self.client.post(url, status=405)
        self.assertEqual(405, response.status_int)

    def test_get_zones(self):
        response = self.client.get('/zones/')

        # Check the headers are what we expect
        self.assertEqual(200, response.status_int)
        self.assertEqual('application/json', response.content_type)

        # Check the body structure is what we expect
        self.assertIn('zones', response.json)
        self.assertIn('links', response.json)
        self.assertIn('self', response.json['links'])

        # We should start with 0 zones
        self.assertEqual(0, len(response.json['zones']))

        # We should start with 0 zones
        self.assertEqual(0, len(response.json['zones']))

        data = [self.create_domain(name='x-%s.com.' % i) for i in 'abcdefghij']
        self._assert_paging(data, '/zones', key='zones')

        self._assert_invalid_paging(data, '/zones', key='zones')

    @patch.object(central_service.Service,
                  'find_domains',
                  side_effect=messaging.MessagingTimeout())
    def test_get_zones_timeout(self, _):
        self._assert_exception('timeout', 504, self.client.get, '/zones/')

    def test_get_zone(self):
        # Create a zone
        zone = self.create_domain()

        response = self.client.get('/zones/%s' % zone['id'],
                                   headers=[('Accept', 'application/json')])

        # Check the headers are what we expect
        self.assertEqual(200, response.status_int)
        self.assertEqual('application/json', response.content_type)

        # Check the body structure is what we expect
        self.assertIn('zone', response.json)
        self.assertIn('links', response.json['zone'])
        self.assertIn('self', response.json['zone']['links'])

        # Check the values returned are what we expect
        self.assertIn('id', response.json['zone'])
        self.assertIn('created_at', response.json['zone'])
        self.assertEqual('ACTIVE', response.json['zone']['status'])
        self.assertIsNone(response.json['zone']['updated_at'])
        self.assertEqual(zone['name'], response.json['zone']['name'])
        self.assertEqual(zone['email'], response.json['zone']['email'])

    def test_get_zone_invalid_id(self):
        self._assert_invalid_uuid(self.client.get, '/zones/%s')

    @patch.object(central_service.Service,
                  'get_domain',
                  side_effect=messaging.MessagingTimeout())
    def test_get_zone_timeout(self, _):
        url = '/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980'
        self._assert_exception('timeout',
                               504,
                               self.client.get,
                               url,
                               headers={'Accept': 'application/json'})

    @patch.object(central_service.Service,
                  'get_domain',
                  side_effect=exceptions.DomainNotFound())
    def test_get_zone_missing(self, _):
        url = '/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980'
        self._assert_exception('domain_not_found',
                               404,
                               self.client.get,
                               url,
                               headers={'Accept': 'application/json'})

    def test_get_zone_missing_accept(self):
        url = '/zones/6e2146f3-87bc-4f47-adc5-4df0a5c78218'

        self._assert_exception('bad_request', 400, self.client.get, url)

    def test_get_zone_bad_accept(self):
        url = '/zones/6e2146f3-87bc-4f47-adc5-4df0a5c78218'

        self.client.get(url, headers={'Accept': 'test/goat'}, status=406)

    def test_update_zone(self):
        # Create a zone
        zone = self.create_domain()

        # Prepare an update body
        body = {'zone': {'email': 'prefix-%s' % zone['email']}}

        response = self.client.patch_json('/zones/%s' % zone['id'],
                                          body,
                                          status=200)

        # Check the headers are what we expect
        self.assertEqual(200, response.status_int)
        self.assertEqual('application/json', response.content_type)

        # Check the body structure is what we expect
        self.assertIn('zone', response.json)
        self.assertIn('links', response.json['zone'])
        self.assertIn('self', response.json['zone']['links'])
        self.assertIn('status', response.json['zone'])

        # Check the values returned are what we expect
        self.assertIn('id', response.json['zone'])
        self.assertIsNotNone(response.json['zone']['updated_at'])
        self.assertEqual('prefix-%s' % zone['email'],
                         response.json['zone']['email'])

    def test_update_zone_invalid_id(self):
        self._assert_invalid_uuid(self.client.patch_json, '/zones/%s')

    def test_update_zone_validation(self):
        # NOTE: The schemas should be tested separatly to the API. So we
        #       don't need to test every variation via the API itself.
        # Create a zone
        zone = self.create_domain()

        # Prepare an update body with junk in the wrapper
        body = {
            'zone': {
                'email': 'prefix-%s' % zone['email']
            },
            'junk': 'Junk Field'
        }

        url = '/zones/%s' % zone['id']

        # Ensure it fails with a 400
        self._assert_exception('invalid_object', 400, self.client.patch_json,
                               url, body)

        # Prepare an update body with junk in the body
        body = {
            'zone': {
                'email': 'prefix-%s' % zone['email'],
                'junk': 'Junk Field'
            }
        }

        # Ensure it fails with a 400
        self._assert_exception('invalid_object', 400, self.client.patch_json,
                               url, body)

    @patch.object(central_service.Service,
                  'get_domain',
                  side_effect=exceptions.DuplicateDomain())
    def test_update_zone_duplicate(self, _):
        # Prepare an update body
        body = {'zone': {'email': '*****@*****.**'}}

        url = '/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980'

        # Ensure it fails with a 409
        self._assert_exception('duplicate_domain', 409, self.client.patch_json,
                               url, body)

    @patch.object(central_service.Service,
                  'get_domain',
                  side_effect=messaging.MessagingTimeout())
    def test_update_zone_timeout(self, _):
        # Prepare an update body
        body = {'zone': {'email': '*****@*****.**'}}

        url = '/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980'

        # Ensure it fails with a 504
        self._assert_exception('timeout', 504, self.client.patch_json, url,
                               body)

    @patch.object(central_service.Service,
                  'get_domain',
                  side_effect=exceptions.DomainNotFound())
    def test_update_zone_missing(self, _):
        # Prepare an update body
        body = {'zone': {'email': '*****@*****.**'}}

        url = '/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980'

        # Ensure it fails with a 404
        self._assert_exception('domain_not_found', 404, self.client.patch_json,
                               url, body)

    def test_delete_zone(self):
        zone = self.create_domain()

        self.client.delete('/zones/%s' % zone['id'], status=204)

    def test_delete_zone_invalid_id(self):
        self._assert_invalid_uuid(self.client.delete, '/zones/%s')

    @patch.object(central_service.Service,
                  'delete_domain',
                  side_effect=messaging.MessagingTimeout())
    def test_delete_zone_timeout(self, _):
        url = '/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980'

        self._assert_exception('timeout', 504, self.client.delete, url)

    @patch.object(central_service.Service,
                  'delete_domain',
                  side_effect=exceptions.DomainNotFound())
    def test_delete_zone_missing(self, _):
        url = '/zones/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980'

        self._assert_exception('domain_not_found', 404, self.client.delete,
                               url)

    # Zone import/export
    def test_missing_origin(self):
        fixture = self.get_zonefile_fixture(variant='noorigin')

        self._assert_exception('bad_request',
                               400,
                               self.client.post,
                               '/zones',
                               fixture,
                               headers={'Content-type': 'text/dns'})

    def test_missing_soa(self):
        fixture = self.get_zonefile_fixture(variant='nosoa')

        self._assert_exception('bad_request',
                               400,
                               self.client.post,
                               '/zones',
                               fixture,
                               headers={'Content-type': 'text/dns'})

    def test_malformed_zonefile(self):
        fixture = self.get_zonefile_fixture(variant='malformed')

        self._assert_exception('bad_request',
                               400,
                               self.client.post,
                               '/zones',
                               fixture,
                               headers={'Content-type': 'text/dns'})

    def test_import_export(self):
        # Since v2 doesn't support getting records, import and export the
        # fixture, making sure they're the same according to dnspython
        post_response = self.client.post('/zones',
                                         self.get_zonefile_fixture(),
                                         headers={'Content-type': 'text/dns'})
        get_response = self.client.get('/zones/%s' %
                                       post_response.json['zone']['id'],
                                       headers={'Accept': 'text/dns'})
        exported_zonefile = get_response.body
        imported = dnszone.from_text(self.get_zonefile_fixture())
        exported = dnszone.from_text(exported_zonefile)
        # Compare SOA emails, since zone comparison takes care of origin
        imported_soa = imported.get_rdataset(imported.origin, 'SOA')
        imported_email = imported_soa[0].rname.to_text()
        exported_soa = exported.get_rdataset(exported.origin, 'SOA')
        exported_email = exported_soa[0].rname.to_text()
        self.assertEqual(imported_email, exported_email)
        # Delete SOAs since they have, at the very least, different serials,
        # and dnspython considers that to be not equal.
        imported.delete_rdataset(imported.origin, 'SOA')
        exported.delete_rdataset(exported.origin, 'SOA')
        # Delete non-delegation NS, since they won't be the same
        imported.delete_rdataset(imported.origin, 'NS')
        exported.delete_rdataset(exported.origin, 'NS')
        self.assertEqual(imported, exported)
Beispiel #15
0
class ApiV1DomainsTest(ApiV1Test):
    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=messaging.MessagingTimeout())
    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 succeeds, 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=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, '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=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'])

    @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=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'])

        # 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=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)
Beispiel #16
0
 def _raise_timeout_exception(msg_id):
     raise messaging.MessagingTimeout(
         _('Timed out waiting for a reply to message ID %s.') % msg_id)
Beispiel #17
0
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_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])
Beispiel #18
0
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_invalid_type(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_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 xrange(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',
                ]}),
            self.get_recordset_fixture(
                self.domain['name'],
                'A',
                fixture=1,
                values={'records': ['192.0.2.1', '192.0.2.3']}),
        ]

        for fixture in fixtures:
            response = self.client.post_json(
                '/zones/%s/recordsets' % self.domain['id'], fixture)

        get_urls = [
            '/zones/%s/recordsets?data=192.0.2.1' % self.domain['id'],
            '/zones/%s/recordsets?data=192.0.2.2' % self.domain['id'],
            '/zones/%s/recordsets?data=192.0.2.1&name=%s' %
            (self.domain['id'], fixtures[0]['name'])
        ]

        correct_results = [2, 1, 1]

        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 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_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_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 xrange(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)
Beispiel #19
0
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'])

    @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=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,
                  '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=messaging.MessagingTimeout())
    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=messaging.MessagingTimeout())
    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=messaging.MessagingTimeout())
    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=messaging.MessagingTimeout())
    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)