Merge "Migrate the recordset validation functional test"
diff --git a/README.rst b/README.rst
index 87f4736..09d8191 100644
--- a/README.rst
+++ b/README.rst
@@ -1,3 +1,12 @@
+========================
+Team and repository tags
+========================
+
+.. image:: http://governance.openstack.org/badges/designate-tempest-plugin.svg
+ :target: http://governance.openstack.org/reference/tags/index.html
+
+.. Change things from this point on
+
================================
Tempest Integration of Designate
================================
diff --git a/designate_tempest_plugin/clients.py b/designate_tempest_plugin/clients.py
index d85d343..87b43c4 100644
--- a/designate_tempest_plugin/clients.py
+++ b/designate_tempest_plugin/clients.py
@@ -13,9 +13,7 @@
# under the License.
from tempest import clients
from tempest import config
-from tempest.lib.auth import KeystoneAuthProvider
-from tempest.lib.auth import KeystoneV2AuthProvider
-from tempest.lib.auth import KeystoneV3AuthProvider
+from tempest.lib import auth
from designate_tempest_plugin.services.dns.v1.json.domains_client import \
DomainsClient
@@ -55,8 +53,8 @@
class ManagerV1(clients.Manager):
- def __init__(self, credentials=None, service=None):
- super(ManagerV1, self).__init__(credentials, service)
+ def __init__(self, credentials=None):
+ super(ManagerV1, self).__init__(credentials)
self._init_clients(self._get_params())
def _init_clients(self, params):
@@ -79,8 +77,8 @@
class ManagerV2(clients.Manager):
- def __init__(self, credentials=None, service=None):
- super(ManagerV2, self).__init__(credentials, service)
+ def __init__(self, credentials=None):
+ super(ManagerV2, self).__init__(credentials)
self._init_clients(self._get_params())
def _init_clients(self, params):
@@ -118,8 +116,8 @@
class ManagerAdmin(clients.Manager):
- def __init__(self, credentials=None, service=None):
- super(ManagerAdmin, self).__init__(credentials, service)
+ def __init__(self, credentials=None):
+ super(ManagerAdmin, self).__init__(credentials)
self._init_clients(self._get_params())
def _init_clients(self, params):
@@ -140,8 +138,8 @@
class ManagerV2Unauthed(ManagerV2):
- def __init__(self, credentials=None, service=None):
- super(ManagerV2Unauthed, self).__init__(credentials, service)
+ def __init__(self, credentials=None):
+ super(ManagerV2Unauthed, self).__init__(credentials)
self.auth_provider = self._auth_provider_class()(
credentials=self.auth_provider.credentials,
auth_url=self.auth_provider.auth_client.auth_url,
@@ -158,7 +156,7 @@
return KeystoneV2UnauthedProvider
-class BaseUnauthedProvider(KeystoneAuthProvider):
+class BaseUnauthedProvider(auth.KeystoneAuthProvider):
def _decorate_request(self, filters, method, url, headers=None, body=None,
auth_data=None):
@@ -173,13 +171,15 @@
return url, headers, body
-class KeystoneV2UnauthedProvider(KeystoneV2AuthProvider, BaseUnauthedProvider):
+class KeystoneV2UnauthedProvider(auth.KeystoneV2AuthProvider,
+ BaseUnauthedProvider):
def _decorate_request(self, *args, **kwargs):
return BaseUnauthedProvider._decorate_request(self, *args, **kwargs)
-class KeystoneV3UnauthedProvider(KeystoneV3AuthProvider, BaseUnauthedProvider):
+class KeystoneV3UnauthedProvider(auth.KeystoneV3AuthProvider,
+ BaseUnauthedProvider):
def _decorate_request(self, *args, **kwargs):
return BaseUnauthedProvider._decorate_request(self, *args, **kwargs)
diff --git a/designate_tempest_plugin/common/models.py b/designate_tempest_plugin/common/models.py
index e69bd09..b2a1687 100644
--- a/designate_tempest_plugin/common/models.py
+++ b/designate_tempest_plugin/common/models.py
@@ -31,6 +31,9 @@
def __eq__(self, other):
return self.__dict__ == other.__dict__
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
@classmethod
def from_text(cls, text):
"""Return a ZoneFile from a string containing the zone file contents"""
@@ -64,6 +67,9 @@
def __eq__(self, other):
return self.__dict__ == other.__dict__
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
def __hash__(self):
return hash(tuple(sorted(self.__dict__.items())))
diff --git a/designate_tempest_plugin/hacking/__init__.py b/designate_tempest_plugin/hacking/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/designate_tempest_plugin/hacking/__init__.py
diff --git a/designate_tempest_plugin/hacking/checks.py b/designate_tempest_plugin/hacking/checks.py
new file mode 100644
index 0000000..366aca3
--- /dev/null
+++ b/designate_tempest_plugin/hacking/checks.py
@@ -0,0 +1,31 @@
+# Copyright 2016 Hewlett Packard Enterprise Development Company, L.P.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.hacking import checks
+
+
+def factory(register):
+ # Imported from Tempest
+ register(checks.import_no_clients_in_api_and_scenario_tests)
+ register(checks.scenario_tests_need_service_tags)
+ register(checks.no_setup_teardown_class_for_tests)
+ register(checks.no_vi_headers)
+ register(checks.service_tags_not_in_module_path)
+ register(checks.no_hyphen_at_end_of_rand_name)
+ register(checks.no_mutable_default_args)
+ register(checks.no_testtools_skip_decorator)
+ register(checks.get_resources_on_service_clients)
+ register(checks.delete_resources_on_service_clients)
+ register(checks.dont_use_config_in_tempest_lib)
+ register(checks.use_rand_uuid_instead_of_uuid4)
diff --git a/designate_tempest_plugin/services/dns/admin/json/quotas_client.py b/designate_tempest_plugin/services/dns/admin/json/quotas_client.py
index 08b1790..fb233d2 100644
--- a/designate_tempest_plugin/services/dns/admin/json/quotas_client.py
+++ b/designate_tempest_plugin/services/dns/admin/json/quotas_client.py
@@ -11,13 +11,10 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
-from oslo_log import log as logging
from designate_tempest_plugin import data_utils as dns_data_utils
from designate_tempest_plugin.services.dns.admin.json import base
-LOG = logging.getLogger(__name__)
-
class QuotasClient(base.DnsClientAdminBase):
diff --git a/designate_tempest_plugin/services/dns/json/base.py b/designate_tempest_plugin/services/dns/json/base.py
index 19dbe45..6c5f1d2 100644
--- a/designate_tempest_plugin/services/dns/json/base.py
+++ b/designate_tempest_plugin/services/dns/json/base.py
@@ -20,7 +20,7 @@
from six.moves.urllib import parse as urllib
import six
-from designate_tempest_plugin.common.models import ZoneFile
+from designate_tempest_plugin.common import models
LOG = logging.getLogger(__name__)
@@ -66,7 +66,7 @@
if 'application/json' in resp['content-type']:
return json.loads(object_str)
elif 'text/dns' in resp['content-type']:
- return ZoneFile.from_text(object_str)
+ return models.ZoneFile.from_text(object_str)
else:
raise lib_exc.InvalidContentType()
diff --git a/designate_tempest_plugin/services/dns/v2/json/quotas_client.py b/designate_tempest_plugin/services/dns/v2/json/quotas_client.py
index 3522a1d..df2cdee 100644
--- a/designate_tempest_plugin/services/dns/v2/json/quotas_client.py
+++ b/designate_tempest_plugin/services/dns/v2/json/quotas_client.py
@@ -11,13 +11,10 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
-from oslo_log import log as logging
from designate_tempest_plugin import data_utils as dns_data_utils
from designate_tempest_plugin.services.dns.v2.json import base
-LOG = logging.getLogger(__name__)
-
class QuotasClient(base.DnsClientV2Base):
diff --git a/designate_tempest_plugin/services/dns/v2/json/recordset_client.py b/designate_tempest_plugin/services/dns/v2/json/recordset_client.py
index 3363e0c..578ccf3 100644
--- a/designate_tempest_plugin/services/dns/v2/json/recordset_client.py
+++ b/designate_tempest_plugin/services/dns/v2/json/recordset_client.py
@@ -26,7 +26,7 @@
:param zone_uuid: Unique identifier of the zone in UUID format..
:param recordset_data: A dictionary that represents the recordset
- data.
+ data.
:param params: A Python dict that represents the query paramaters to
include in the request URI.
:return: A tuple with the server response and the created zone.
@@ -44,6 +44,29 @@
return resp, body
@base.handle_errors
+ def update_recordset(self, zone_uuid, recordset_uuid,
+ recordet_data, params=None):
+ """Update the recordset related to the specified zone.
+ :param zone_uuid: Unique identifier of the zone in UUID format.
+ :param recordset_uuid: Unique identifier of the recordset in UUID
+ format.
+ :param recordset_data: A dictionary that represents the recordset
+ data.
+ :param params: A Python dict that represents the query paramaters to
+ include in the request URI.
+ :return: A tuple with the server response and the created zone.
+ """
+ resp, body = self._put_request(
+ 'zones/{0}/recordsets'.format(zone_uuid), recordset_uuid,
+ data=recordet_data, params=params)
+
+ # Update Recordset should Return a HTTP 202, or a 200 if the recordset
+ # is already active
+ self.expected_success([200, 202], resp.status)
+
+ return resp, body
+
+ @base.handle_errors
def show_recordset(self, zone_uuid, recordset_uuid, params=None):
"""Gets a specific recordset related to a specific zone.
:param zone_uuid: Unique identifier of the zone in UUID format.
@@ -87,6 +110,24 @@
'zones/{0}/recordsets'.format(uuid), params=params)
@base.handle_errors
+ def show_zones_recordset(self, recordset_uuid, params=None):
+ """Gets a single recordset, using the cross_zone endpoint
+ :param recordset_uuid: Unique identifier of the recordset in UUID
+ format.
+ :param params: A Python dict that represents the query paramaters to
+ include in the request URI.
+ :return: A tuple with the server response and the response body.
+ """
+ resp, body = self._show_request(
+ 'recordsets', recordset_uuid,
+ params=params)
+
+ # Show recordsets/id should return a HTTP 301
+ self.expected_success(301, resp.status)
+
+ return resp, body
+
+ @base.handle_errors
def list_zones_recordsets(self, params=None):
"""List recordsets across all zones.
:param params: A Python dict that represents the query paramaters to
@@ -95,23 +136,3 @@
"""
return self._list_request(
'recordsets', params=params)
-
- @base.handle_errors
- def update_recordset(self, zone_uuid, recordset_uuid,
- recordset_model, params=None):
- """Update the recordset related to the specified zone.
- :param zone_uuid: Unique identifier of the zone in UUID format..
- :param recordset_uuid: Unique identifier of the records in UUID format.
- :param recordset_model: .
- :param params: A Python dict that represents the query paramaters to
- include in the request URI.
- :return: A tuple with the server response and the created zone.
- """
- resp, body = self._put_request(
- 'zones/{0}/recordsets'.format(zone_uuid), recordset_uuid,
- data=recordset_model, params=params)
-
- # Update Recordset should Return a HTTP 202
- self.expected_success(202, resp.status)
-
- return resp, body
diff --git a/designate_tempest_plugin/services/dns/v2/json/transfer_request_client.py b/designate_tempest_plugin/services/dns/v2/json/transfer_request_client.py
index 513a8ad..f494cde 100644
--- a/designate_tempest_plugin/services/dns/v2/json/transfer_request_client.py
+++ b/designate_tempest_plugin/services/dns/v2/json/transfer_request_client.py
@@ -42,6 +42,24 @@
return resp, body
@base.handle_errors
+ def create_transfer_request_empty_body(self, uuid, params=None):
+ """Create a zone transfer_requests.
+ :param uuid: Unique identifier of the zone in UUID format.
+ :param params: A Python dict that represents the query paramaters to
+ include in the request URI.
+ :return: Serialized zone trasfer request as a dictionary.
+ """
+
+ transfer_request_uri = 'zones/{0}/tasks/transfer_requests'.format(uuid)
+ resp, body = self._create_request(
+ transfer_request_uri, None, params=params)
+
+ # Create Transfer request should Return a HTTP 201
+ self.expected_success(201, resp.status)
+
+ return resp, body
+
+ @base.handle_errors
def show_transfer_request(self, uuid, params=None):
"""Gets a specific transfer_requestsed zone.
:param uuid: Unique identifier of the transfer_requestsed zone in
diff --git a/designate_tempest_plugin/tests/api/v1/test_domains.py b/designate_tempest_plugin/tests/api/v1/test_domains.py
index 84e77e5..9c6d1b6 100644
--- a/designate_tempest_plugin/tests/api/v1/test_domains.py
+++ b/designate_tempest_plugin/tests/api/v1/test_domains.py
@@ -31,8 +31,8 @@
cls.client = cls.os.domains_client
@classmethod
- def setUpClass(cls):
- super(DnsDomainsTest, cls).setUpClass()
+ def resource_setup(cls):
+ super(DnsDomainsTest, cls).resource_setup()
cls.setup_domains = list()
for i in range(2):
name = data_utils.rand_name('domain') + '.com.'
@@ -41,10 +41,10 @@
cls.setup_domains.append(domain)
@classmethod
- def tearDownClass(cls):
+ def resource_cleanup(cls):
for domain in cls.setup_domains:
cls.client.delete_domain(domain['id'])
- super(DnsDomainsTest, cls).tearDownClass()
+ super(DnsDomainsTest, cls).resource_cleanup()
def _delete_domain(self, domain_id):
self.client.delete_domain(domain_id)
diff --git a/designate_tempest_plugin/tests/api/v1/test_records.py b/designate_tempest_plugin/tests/api/v1/test_records.py
index 1e395d6..ec15771 100644
--- a/designate_tempest_plugin/tests/api/v1/test_records.py
+++ b/designate_tempest_plugin/tests/api/v1/test_records.py
@@ -30,8 +30,8 @@
cls.client = cls.os.records_client
@classmethod
- def setUpClass(cls):
- super(RecordsTest, cls).setUpClass()
+ def resource_setup(cls):
+ super(RecordsTest, cls).resource_setup()
# Creates domains and Records for testcase
cls.setup_records = list()
@@ -53,11 +53,11 @@
cls.setup_records.append(record)
@classmethod
- def tearDownClass(cls):
+ def resource_cleanup(cls):
for record in cls.setup_records:
cls.client.delete_record(cls.domain['id'], record['id'])
cls.os.domains_client.delete_domain(cls.domain['id'])
- super(RecordsTest, cls).tearDownClass()
+ super(RecordsTest, cls).resource_cleanup()
def _delete_record(self, domain_id, record_id):
self.client.delete_record(domain_id, record_id)
diff --git a/designate_tempest_plugin/tests/api/v1/test_servers.py b/designate_tempest_plugin/tests/api/v1/test_servers.py
index 74639ba..c92c604 100644
--- a/designate_tempest_plugin/tests/api/v1/test_servers.py
+++ b/designate_tempest_plugin/tests/api/v1/test_servers.py
@@ -48,8 +48,8 @@
raise cls.skipException(skip_msg)
@classmethod
- def setUpClass(cls):
- super(ServersAdminTest, cls).setUpClass()
+ def resource_setup(cls):
+ super(ServersAdminTest, cls).resource_setup()
cls.setup_servers = list()
for i in range(2):
@@ -58,10 +58,10 @@
cls.setup_servers.append(server)
@classmethod
- def tearDownClass(cls):
+ def resource_cleanup(cls):
for server in cls.setup_servers:
cls.client.delete_server(server['id'])
- super(ServersAdminTest, cls).tearDownClass()
+ super(ServersAdminTest, cls).resource_cleanup()
def _delete_server(self, server_id):
self.client.delete_server(server_id)
diff --git a/designate_tempest_plugin/tests/api/v2/recordset_wildcard_data.json b/designate_tempest_plugin/tests/api/v2/recordset_wildcard_data.json
new file mode 100644
index 0000000..dedf414
--- /dev/null
+++ b/designate_tempest_plugin/tests/api/v2/recordset_wildcard_data.json
@@ -0,0 +1,53 @@
+{
+ "A at APEX": {
+ "name": "*",
+ "type": "A",
+ "records": ["192.0.2.1", "192.0.2.2", "192.0.2.3"]
+ },
+ "A under APEX": {
+ "name": "*.sub",
+ "type": "A",
+ "records": ["192.0.2.1", "192.0.2.2", "192.0.2.3"]
+ },
+ "AAAA at APEX": {
+ "name": "*",
+ "type": "AAAA",
+ "records": ["2001:db8::1", "2001:db8::1", "2001:db8::"]
+ },
+ "AAAA under APEX": {
+ "name": "*.sub",
+ "type": "AAAA",
+ "records": ["2001:db8::1", "2001:db8::1", "2001:db8::"]
+ },
+ "MX at APEX": {
+ "name": "*",
+ "type": "MX",
+ "records": ["10 mail1.example.org.",
+ "20 mail2.example.org."]
+ },
+ "MX under APEX": {
+ "name": "*.sub",
+ "type": "MX",
+ "records": ["10 mail.example.org."]
+ },
+ "SPF at APEX": {
+ "name": "*",
+ "type": "SPF",
+ "records": ["v=spf1; a -all"]
+ },
+ "SPF under APEX": {
+ "name": "*.sub",
+ "type": "SPF",
+ "records": ["v=spf1; a -all"]
+ },
+ "TXT at APEX": {
+ "name": "*",
+ "type": "TXT",
+ "records": ["Can you read me?"]
+ },
+ "TXT under APEX": {
+ "name": "*.sub",
+ "type": "TXT",
+ "records": ["Can you read me?"]
+ }
+}
diff --git a/designate_tempest_plugin/tests/api/v2/test_quotas.py b/designate_tempest_plugin/tests/api/v2/test_quotas.py
index 9411270..bd865bb 100644
--- a/designate_tempest_plugin/tests/api/v2/test_quotas.py
+++ b/designate_tempest_plugin/tests/api/v2/test_quotas.py
@@ -75,7 +75,7 @@
LOG.info("Ensuring the response has all quota types")
self.assertExpected(quotas, body, [])
- @decorators.idempotent_id('76d24c87-1b39-4e19-947c-c08e1380dc61')
+ @decorators.idempotent_id('9b09b3e2-7e88-4569-bce3-9be2f7ac70c3')
def test_update_quotas_other_project(self):
project_id = self.quotas_client.tenant_id
diff --git a/designate_tempest_plugin/tests/api/v2/test_recordset.py b/designate_tempest_plugin/tests/api/v2/test_recordset.py
index 9096f76..d686d94 100644
--- a/designate_tempest_plugin/tests/api/v2/test_recordset.py
+++ b/designate_tempest_plugin/tests/api/v2/test_recordset.py
@@ -91,6 +91,28 @@
LOG.info('Ensure we respond with PENDING')
self.assertEqual('PENDING', body['status'])
+ @decorators.idempotent_id('69f002e5-6511-43d3-abae-7abdd45ae03e')
+ @ddt.file_data("recordset_wildcard_data.json")
+ def test_create_wildcard_recordset(self, name, type, records):
+ if name is not None:
+ recordset_name = name + "." + self.zone['name']
+
+ else:
+ recordset_name = "*." + self.zone['name']
+
+ recordset_data = {
+ 'name': recordset_name,
+ 'type': type,
+ 'records': records,
+ }
+
+ LOG.info('Create a Recordset')
+ resp, body = self.client.create_recordset(
+ self.zone['id'], recordset_data)
+
+ LOG.info('Ensure we respond with PENDING')
+ self.assertEqual('PENDING', body['status'])
+
@decorators.idempotent_id('5964f730-5546-46e6-9105-5030e9c492b2')
def test_list_recordsets(self):
recordset_data = data_utils.rand_recordset_data(
@@ -187,7 +209,7 @@
cls.client = cls.os.recordset_client
cls.zone_client = cls.os.zones_client
- @decorators.idempotent_id('631d74fd-6909-4684-a61b-5c4d2f92c3e7')
+ @decorators.idempotent_id('98c94f8c-217a-4056-b996-b1f856d0753e')
@ddt.file_data("recordset_data_invalid.json")
def test_create_recordset_invalid(self, name, type, records):
if name is not None:
@@ -303,17 +325,22 @@
self.assertGreater(len(body['recordsets']), 0)
+ @decorators.skip_because(bug="1616892")
+ @decorators.idempotent_id('65ec0495-81d9-4cfb-8007-9d93b32ae883')
+ def test_get_single_zones_recordsets(self):
+ recordset_data = data_utils.rand_recordset_data(
+ record_type='A', zone_name=self.zone['name'], records=['10.1.0.2'])
+
+ LOG.info('Create a Recordset')
+ resp, zone_recordset = self.client.create_recordset(
+ self.zone['id'], recordset_data)
+
+ self.client.show_zones_recordset(zone_recordset['id'])
+
@decorators.idempotent_id('a8e41020-65be-453b-a8c1-2497d539c345')
def test_list_filter_zones_recordsets(self):
- recordset_data = {
- "name": self.zone['name'],
- "description": "This is an example record set.",
- "type": "A",
- "ttl": 3600,
- "records": [
- "10.1.0.2"
- ]
- }
+ recordset_data = data_utils.rand_recordset_data(
+ record_type='A', zone_name=self.zone['name'], records=['10.0.1.2'])
LOG.info('Create a Recordset')
resp, zone_recordset = self.client.create_recordset(
@@ -323,12 +350,44 @@
_, zone2 = self.zone_client.create_zone()
self.addCleanup(self.zone_client.delete_zone, zone2['id'])
+ LOG.info('Create another Recordset')
+ recordset_data = data_utils.rand_recordset_data(
+ record_type='A', zone_name=zone2['name'],
+ records=['10.0.1.3'])
+ resp, zone_recordset2 = self.client.create_recordset(
+ zone2['id'], recordset_data)
+
LOG.info('List recordsets')
- _, body = self.client.list_zones_recordsets(params={"data": "10.1.*"})
+ _, body = self.client.list_zones_recordsets(params={"data": "10.0.*"})
recordsets = body['recordsets']
- self.assertEqual(zone_recordset['id'], recordsets[0]['id'])
+ ids = [r['id'] for r in recordsets]
+ self.assertIn(zone_recordset['id'], ids)
+ self.assertIn(zone_recordset2['id'], ids)
+ # Ensure that every rrset has a record with the filtered data
+ for r in recordsets:
+ one_record_has_data = False
+ for record in r['records']:
+ if record.startswith('10.0.'):
+ one_record_has_data = True
+ self.assertTrue(one_record_has_data)
+
+ @decorators.idempotent_id('7f4970bf-9aeb-4a3c-9afd-02f5a7178d35')
+ def test_list_zones_recordsets_zone_names(self):
+ LOG.info('Create another zone')
+ _, zone2 = self.zone_client.create_zone()
+ self.addCleanup(self.zone_client.delete_zone, zone2['id'])
+
+ LOG.info('List recordsets')
+ _, body = self.client.list_zones_recordsets()
+
+ recordsets = body['recordsets']
+ zone_names = set()
+ for r in recordsets:
+ zone_names.add(r['zone_name'])
+
+ self.assertGreaterEqual(len(zone_names), 2)
class RecordsetOwnershipTest(BaseRecordsetsTest):
diff --git a/designate_tempest_plugin/tests/api/v2/test_transfer_accepts.py b/designate_tempest_plugin/tests/api/v2/test_transfer_accepts.py
index a043137..0972a24 100644
--- a/designate_tempest_plugin/tests/api/v2/test_transfer_accepts.py
+++ b/designate_tempest_plugin/tests/api/v2/test_transfer_accepts.py
@@ -68,8 +68,8 @@
transfer_request['id'])
data = {
- "key": transfer_request['key'],
- "zone_transfer_request_id": transfer_request['id']
+ "key": transfer_request['key'],
+ "zone_transfer_request_id": transfer_request['id']
}
LOG.info('Create a zone transfer_accept')
diff --git a/designate_tempest_plugin/tests/api/v2/test_transfer_request.py b/designate_tempest_plugin/tests/api/v2/test_transfer_request.py
index 9bc3897..af81cfc 100644
--- a/designate_tempest_plugin/tests/api/v2/test_transfer_request.py
+++ b/designate_tempest_plugin/tests/api/v2/test_transfer_request.py
@@ -17,22 +17,25 @@
from tempest.lib import exceptions as lib_exc
from designate_tempest_plugin.tests import base
+from designate_tempest_plugin import data_utils as dns_data_utils
LOG = logging.getLogger(__name__)
class BaseTransferRequestTest(base.BaseDnsV2Test):
- excluded_keys = ['created_at', 'updated_at', 'key', 'links',
- 'zone_name']
+ excluded_keys = ['created_at', 'updated_at', 'key', 'links']
class TransferRequestTest(BaseTransferRequestTest):
+ credentials = ['primary', 'alt']
+
@classmethod
def setup_clients(cls):
super(TransferRequestTest, cls).setup_clients()
cls.zone_client = cls.os.zones_client
cls.client = cls.os.transfer_request_client
+ cls.alt_client = cls.os_alt.transfer_request_client
@decorators.idempotent_id('2381d489-ad84-403d-b0a2-8b77e4e966bf')
def test_create_transfer_request(self):
@@ -48,6 +51,38 @@
LOG.info('Ensure we respond with ACTIVE status')
self.assertEqual('ACTIVE', transfer_request['status'])
+ @decorators.idempotent_id('5deae1ac-7c14-42dc-b14e-4e4b2725beb7')
+ def test_create_transfer_request_scoped(self):
+ LOG.info('Create a zone')
+ _, zone = self.zone_client.create_zone()
+ self.addCleanup(self.zone_client.delete_zone, zone['id'])
+
+ transfer_request_data = dns_data_utils.rand_transfer_request_data(
+ target_project_id=self.os_alt.credentials.project_id)
+
+ LOG.info('Create a scoped zone transfer_request')
+ _, transfer_request = self.client.create_transfer_request(
+ zone['id'], transfer_request_data)
+ self.addCleanup(self.client.delete_transfer_request,
+ transfer_request['id'])
+
+ LOG.info('Ensure we respond with ACTIVE status')
+ self.assertEqual('ACTIVE', transfer_request['status'])
+
+ @decorators.idempotent_id('4505152f-0a9c-4f02-b385-2216c914a0be')
+ def test_create_transfer_request_empty_body(self):
+ LOG.info('Create a zone')
+ _, zone = self.zone_client.create_zone()
+ self.addCleanup(self.zone_client.delete_zone, zone['id'])
+ LOG.info('Create a zone transfer_request')
+ _, transfer_request = self.client.create_transfer_request_empty_body(
+ zone['id'])
+ self.addCleanup(self.client.delete_transfer_request,
+ transfer_request['id'])
+
+ LOG.info('Ensure we respond with ACTIVE status')
+ self.assertEqual('ACTIVE', transfer_request['status'])
+
@decorators.idempotent_id('64a7be9f-8371-4ce1-a242-c1190de7c985')
def test_show_transfer_request(self):
LOG.info('Create a zone')
@@ -66,6 +101,32 @@
'created transfer_request')
self.assertExpected(transfer_request, body, self.excluded_keys)
+ @decorators.idempotent_id('235ded87-0c47-430b-8cad-4f3194b927a6')
+ def test_show_transfer_request_as_target(self):
+ # Checks the target of a scoped transfer request can see
+ # the request.
+ LOG.info('Create a zone')
+ _, zone = self.zone_client.create_zone()
+ self.addCleanup(self.zone_client.delete_zone, zone['id'])
+
+ transfer_request_data = dns_data_utils.rand_transfer_request_data(
+ target_project_id=self.os_alt.credentials.project_id)
+
+ LOG.info('Create a scoped zone transfer_request')
+ _, transfer_request = self.client.create_transfer_request(
+ zone['id'], transfer_request_data)
+ self.addCleanup(self.client.delete_transfer_request,
+ transfer_request['id'])
+
+ LOG.info('Fetch the transfer_request as the target')
+ _, body = self.alt_client.show_transfer_request(transfer_request['id'])
+
+ LOG.info('Ensure the fetched response matches the '
+ 'created transfer_request')
+ excluded_keys = self.excluded_keys + ["target_project_id",
+ "project_id"]
+ self.assertExpected(transfer_request, body, excluded_keys)
+
@decorators.idempotent_id('7d81c487-aa15-44c4-b3e5-424ab9e6a3e5')
def test_delete_transfer_request(self):
LOG.info('Create a zone')
diff --git a/designate_tempest_plugin/tests/api/v2/test_unauthed.py b/designate_tempest_plugin/tests/api/v2/test_unauthed.py
index e788a3b..b48cfd7 100644
--- a/designate_tempest_plugin/tests/api/v2/test_unauthed.py
+++ b/designate_tempest_plugin/tests/api/v2/test_unauthed.py
@@ -17,7 +17,7 @@
import ddt
from designate_tempest_plugin.tests import base
-from designate_tempest_plugin.clients import ManagerV2Unauthed
+from designate_tempest_plugin import clients
LOG = logging.getLogger(__name__)
@@ -25,7 +25,7 @@
@ddt.ddt
class TestDnsUnauthed(base.BaseDnsV2Test):
- client_manager = ManagerV2Unauthed
+ client_manager = clients.ManagerV2Unauthed
credentials = ["primary"]
@classmethod
diff --git a/designate_tempest_plugin/tests/scenario/v2/test_zones.py b/designate_tempest_plugin/tests/scenario/v2/test_zones.py
index c98a551..ccbfc6c 100644
--- a/designate_tempest_plugin/tests/scenario/v2/test_zones.py
+++ b/designate_tempest_plugin/tests/scenario/v2/test_zones.py
@@ -87,6 +87,7 @@
waiters.wait_for_zone_404(self.client, zone['id'])
@test.attr(type='slow')
+ @decorators.skip_because(bug='1623576')
@decorators.idempotent_id('ad8d1f5b-da66-46a0-bbee-14dc84a5d791')
@config.skip_unless_config('dns', 'nameservers')
def test_zone_create_propagates_to_nameservers(self):
@@ -98,6 +99,7 @@
waiters.wait_for_query(self.query_client, zone['name'], "SOA")
@test.attr(type='slow')
+ @decorators.skip_because(bug='1623576')
@decorators.idempotent_id('d13d3095-c78f-4aae-8fe3-a74ccc335c84')
@config.skip_unless_config('dns', 'nameservers')
def test_zone_delete_propagates_to_nameservers(self):
diff --git a/designate_tempest_plugin/tests/scenario/v2/test_zones_transfer.py b/designate_tempest_plugin/tests/scenario/v2/test_zones_transfer.py
new file mode 100644
index 0000000..4870307
--- /dev/null
+++ b/designate_tempest_plugin/tests/scenario/v2/test_zones_transfer.py
@@ -0,0 +1,62 @@
+# Copyright 2016 Rackspace
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+from oslo_log import log as logging
+from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
+
+from designate_tempest_plugin.tests import base
+
+LOG = logging.getLogger(__name__)
+
+
+class ZonesTransferTest(base.BaseDnsV2Test):
+ credentials = ['primary', 'alt']
+
+ @classmethod
+ def setup_clients(cls):
+ super(ZonesTransferTest, cls).setup_clients()
+ cls.zones_client = cls.os.zones_client
+ cls.alt_zones_client = cls.os_alt.zones_client
+ cls.request_client = cls.os.transfer_request_client
+ cls.alt_request_client = cls.os_alt.transfer_request_client
+ cls.accept_client = cls.os.transfer_accept_client
+ cls.alt_accept_client = cls.os_alt.transfer_accept_client
+
+ @decorators.idempotent_id('60bd80ac-c979-4686-9a03-f2f775f272ab')
+ def test_zone_transfer(self):
+ LOG.info('Create a zone as primary tenant')
+ _, zone = self.zones_client.create_zone()
+ self.addCleanup(self.zones_client.delete_zone, zone['id'],
+ ignore_errors=lib_exc.NotFound)
+ self.addCleanup(self.alt_zones_client.delete_zone, zone['id'],
+ ignore_errors=lib_exc.NotFound)
+
+ LOG.info('Create a zone transfer_request for zone as primary tenant')
+ _, transfer_request = \
+ self.request_client.create_transfer_request_empty_body(zone['id'])
+
+ accept_data = {
+ "key": transfer_request['key'],
+ "zone_transfer_request_id": transfer_request['id']
+ }
+
+ LOG.info('Accept the request as alt tenant')
+ self.alt_accept_client.create_transfer_accept(accept_data)
+
+ LOG.info('Fetch the zone as alt tenant')
+ self.alt_zones_client.show_zone(zone['id'])
+
+ LOG.info('Ensure 404 when fetching the zone as primary tenant')
+ self.assertRaises(lib_exc.NotFound,
+ lambda: self.zones_client.show_zone(zone['id']))
diff --git a/requirements.txt b/requirements.txt
index d7c3d83..13d92fc 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -2,7 +2,7 @@
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
-dnspython>=1.14.0 # http://www.dnspython.org/LICENSE
-dnspython3>=1.12.0;python_version>='3.0' # http://www.dnspython.org/LICENSE
+dnspython>=1.14.0;python_version=='2.7' # http://www.dnspython.org/LICENSE
+dnspython3!=1.13.0,!=1.14.0,>=1.12.0;python_version>='3.0' # http://www.dnspython.org/LICENSE
ddt>=1.0.1 # MIT
tempest>=12.1.0 # Apache-2.0
diff --git a/tools/tox_install.sh b/tools/tox_install.sh
new file mode 100755
index 0000000..e61b63a
--- /dev/null
+++ b/tools/tox_install.sh
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+
+# Client constraint file contains this client version pin that is in conflict
+# with installing the client from source. We should remove the version pin in
+# the constraints file before applying it for from-source installation.
+
+CONSTRAINTS_FILE="$1"
+shift 1
+
+set -e
+
+# NOTE(tonyb): Place this in the tox enviroment's log dir so it will get
+# published to logs.openstack.org for easy debugging.
+localfile="$VIRTUAL_ENV/log/upper-constraints.txt"
+
+if [[ "$CONSTRAINTS_FILE" != http* ]]; then
+ CONSTRAINTS_FILE="file://$CONSTRAINTS_FILE"
+fi
+# NOTE(tonyb): need to add curl to bindep.txt if the project supports bindep
+curl "$CONSTRAINTS_FILE" --insecure --progress-bar --output "$localfile"
+
+pip install -c"$localfile" openstack-requirements
+
+# This is the main purpose of the script: Allow local installation of
+# the current repo. It is listed in constraints file and thus any
+# install will be constrained and we need to unconstrain it.
+edit-constraints "$localfile" -- "$CLIENT_NAME"
+
+pip install -c"$localfile" -U "$@"
+exit $?
diff --git a/tox.ini b/tox.ini
index cdbccbb..9c21dac 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,14 +1,17 @@
[tox]
-minversion = 1.6
+minversion = 2.0
envlist = py34,py27,flake8
skipsdist = True
[testenv]
usedevelop = True
-install_command = pip install {opts} {packages}
+install_command = {toxinidir}/tools/tox_install.sh {env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages}
deps = -r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
setenv =
+ VIRTUAL_ENV={envdir}
+ BRANCH_NAME=master
+ CLIENT_NAME=designate-tempest-plugin
PYTHONDONTWRITEBYTECODE=1
whitelist_externals = sh
find
@@ -73,3 +76,8 @@
ignore = H302,H306,H402,H404,H405,H904,E126,E128
exclude = .venv,.git,.tox,dist,doc,*openstack/common*,*openstack/deprecated*,*lib/python*,*egg,build,tools,.ropeproject
+
+
+[hacking]
+local-check-factory = designate_tempest_plugin.hacking.checks.factory
+