Stabilizing “PTR record” tests suite and adding new test cases
Stabilizing
1) The same TLD is used by default for all tests
2) Adding waiters for set/unset PTR records
New test cases
1) test_show_floatingip_ptr_impersonate_another_project
2) test_list_floatingip_ptr_all_projects
3) test_set_floatingip_ptr_not_existing_fip_id
4) test_set_floatingip_ptr_huge_size_description
5) test_set_floatingip_ptr_invalid_name
Note:
This tests also includes refactoring of the existing tests.
Negative logic is now removed from positive test cases and
implemented separatly in DesignatePtrRecordNegative class.
Change-Id: I64483c3d8e1ae44db7712b3e463ae4ea239a613a
diff --git a/designate_tempest_plugin/common/constants.py b/designate_tempest_plugin/common/constants.py
index 84ee5ae..4f6c72b 100644
--- a/designate_tempest_plugin/common/constants.py
+++ b/designate_tempest_plugin/common/constants.py
@@ -19,6 +19,7 @@
DELETED = 'DELETED'
ACTIVE = 'ACTIVE'
UP = 'UP'
+CREATE = 'CREATE'
# Zone types
PRIMARY_ZONE_TYPE = 'PRIMARY'
diff --git a/designate_tempest_plugin/common/waiters.py b/designate_tempest_plugin/common/waiters.py
index 2b7a3b6..2422f37 100644
--- a/designate_tempest_plugin/common/waiters.py
+++ b/designate_tempest_plugin/common/waiters.py
@@ -226,3 +226,35 @@
message = "(%s) %s" % (caller, message)
raise lib_exc.TimeoutException(message)
+
+
+def wait_for_ptr_status(client, fip_id, status):
+ """Waits for a PTR associated with FIP to reach given status."""
+ LOG.info('Waiting for PTR %s to reach %s', fip_id, status)
+
+ ptr = client.show_ptr_record(fip_id)
+ start = int(time.time())
+
+ while ptr['status'] != status:
+ time.sleep(client.build_interval)
+ ptr = client.show_ptr_record(fip_id)
+ status_curr = ptr['status']
+ if status_curr == status:
+ LOG.info('PTR %s reached %s', fip_id, status)
+ return
+
+ if int(time.time()) - start >= client.build_timeout:
+ message = ('PTR for FIP: %(fip_id)s failed to reach '
+ 'status=%(status)s within the required time '
+ '(%(timeout)s s). Current status: %(status_curr)s' %
+ {'fip_id': fip_id,
+ 'status': status,
+ 'status_curr': status_curr,
+ 'timeout': client.build_timeout})
+
+ caller = test_utils.find_test_caller()
+
+ if caller:
+ message = '(%s) %s' % (caller, message)
+
+ raise lib_exc.TimeoutException(message)
diff --git a/designate_tempest_plugin/data_utils.py b/designate_tempest_plugin/data_utils.py
index 2f61d97..98db929 100644
--- a/designate_tempest_plugin/data_utils.py
+++ b/designate_tempest_plugin/data_utils.py
@@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import random
+from string import ascii_lowercase
import netaddr
from oslo_log import log as logging
@@ -34,7 +35,7 @@
return an.format(netaddr.ipv6_compact)
-def rand_zone_name(name='', prefix=None, suffix='.com.'):
+def rand_zone_name(name='', prefix='rand', suffix='.com.'):
"""Generate a random zone name
:param str name: The name that you want to include
:param prefix: the exact text to start the string. Defaults to "rand"
@@ -259,3 +260,22 @@
func = globals()["rand_{}_recordset".format(record_type.lower())]
return func(zone_name)
+
+
+def rand_string(size):
+ """Create random string of ASCII chars by size
+
+ :param int size - length os the string to be create
+ :return - random creates string of ASCII lover characters
+ """
+ return ''.join(random.choice(ascii_lowercase) for _ in range(size))
+
+
+def rand_domain_name(tld=None):
+ """Create random valid domain name
+
+ :param tld (optional) - TLD that will be used to random domain name
+ :return - valid domain name, for example: paka.zbabun.iuh
+ """
+ domain_tld = tld or rand_string(3)
+ return rand_string(4) + '.' + rand_string(6) + '.' + domain_tld + '.'
diff --git a/designate_tempest_plugin/services/dns/v2/json/ptr_client.py b/designate_tempest_plugin/services/dns/v2/json/ptr_client.py
index 1bd59b3..eed221b 100644
--- a/designate_tempest_plugin/services/dns/v2/json/ptr_client.py
+++ b/designate_tempest_plugin/services/dns/v2/json/ptr_client.py
@@ -24,7 +24,8 @@
@base.handle_errors
def set_ptr_record(self, floatingip_id, ptr_name=None,
- ttl=None, description=None, headers=None):
+ ttl=None, description=None, headers=None,
+ tld=None):
"""Set a PTR record for the given FloatingIP
:param floatingip_id: valid UUID of floating IP to be used.
@@ -32,13 +33,13 @@
:param ttl TTL or random valid value if not provided.
:param description Description or random if not provided.
:param headers (dict): The headers to use for the request.
+ :param tld, the TLD to be used in ptrdname generated value.
:return: created PTR dictionary.
"""
ptr = {
- 'ptrdname': ptr_name or dns_data_utils.rand_zone_name(),
+ 'ptrdname': ptr_name or dns_data_utils.rand_domain_name(tld),
'ttl': ttl or dns_data_utils.rand_ttl(),
- 'description': description or data_utils.rand_name(
- 'test-ptr')}
+ 'description': description or data_utils.rand_name('test-ptr')}
return self._update_request(
resource='reverse/floatingips/{}'.format(CONF.identity.region),
diff --git a/designate_tempest_plugin/tests/api/v2/test_ptrs.py b/designate_tempest_plugin/tests/api/v2/test_ptrs.py
index e2ad98a..4303cce 100644
--- a/designate_tempest_plugin/tests/api/v2/test_ptrs.py
+++ b/designate_tempest_plugin/tests/api/v2/test_ptrs.py
@@ -13,15 +13,22 @@
# under the License.
from oslo_log import log as logging
from tempest import config
+from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
from designate_tempest_plugin.tests import base
+from designate_tempest_plugin.common import constants as const
+from designate_tempest_plugin.common import waiters
+from designate_tempest_plugin import data_utils as dns_data_utils
+
import tempest.test
CONF = config.CONF
LOG = logging.getLogger(__name__)
+TLD = dns_data_utils.rand_string(3)
+
class BasePtrTest(base.BaseDnsV2Test):
excluded_keys = ['created_at', 'updated_at', 'version', 'links',
@@ -29,7 +36,8 @@
class DesignatePtrRecord(BasePtrTest, tempest.test.BaseTestCase):
- credentials = ["primary"]
+
+ credentials = ['primary', 'admin']
@classmethod
def setup_credentials(cls):
@@ -41,20 +49,33 @@
def setup_clients(cls):
super(DesignatePtrRecord, cls).setup_clients()
cls.primary_ptr_client = cls.os_primary.dns_v2.PtrClient()
+ cls.admin_ptr_client = cls.os_admin.dns_v2.PtrClient()
cls.primary_floating_ip_client = cls.os_primary.floating_ips_client
- def _set_ptr(self):
- fip = self.primary_floating_ip_client.create_floatingip(
- floating_network_id=CONF.network.public_network_id)['floatingip']
- fip_id = fip['id']
- self.addCleanup(self.primary_floating_ip_client.delete_floatingip,
- fip_id)
- ptr = self.primary_ptr_client.set_ptr_record(fip_id)
+ def _set_ptr(self, ptr_name=None, ttl=None, description=None,
+ headers=None, tld=TLD, fip_id=None):
+ if not fip_id:
+ fip = self.primary_floating_ip_client.create_floatingip(
+ floating_network_id=CONF.network.public_network_id)[
+ 'floatingip']
+ fip_id = fip['id']
+ self.addCleanup(
+ self.primary_floating_ip_client.delete_floatingip, fip_id)
+ ptr = self.primary_ptr_client.set_ptr_record(
+ fip_id, ptr_name=ptr_name, ttl=ttl, description=description,
+ headers=headers, tld=tld)
self.addCleanup(self.primary_ptr_client.unset_ptr_record, fip_id)
self.assertEqual('CREATE', ptr['action'])
self.assertEqual('PENDING', ptr['status'])
+ waiters.wait_for_ptr_status(
+ self.primary_ptr_client, fip_id=fip_id, status=const.ACTIVE)
return fip_id, ptr
+ def _unset_ptr(self, fip_id):
+ self.primary_ptr_client.unset_ptr_record(fip_id)
+ waiters.wait_for_ptr_status(
+ self.primary_ptr_client, fip_id=fip_id, status=const.DELETED)
+
@decorators.idempotent_id('2fb9d6ea-871d-11eb-9f9a-74e5f9e2a801')
def test_set_floatingip_ptr(self):
self._set_ptr()
@@ -66,6 +87,19 @@
floatingip_id=fip_id)
self.assertExpected(ptr, show_ptr, self.excluded_keys)
+ @decorators.idempotent_id('d3128a92-e3bd-11eb-a097-74e5f9e2a801')
+ def test_show_floatingip_ptr_impersonate_another_project(self):
+ fip_id, ptr = self._set_ptr()
+
+ LOG.info('As Admin user, show PTR record created by Primary'
+ ' user by including "x-auth-sudo-project-id" HTTP header'
+ ' in HTTP request.')
+ show_ptr = self.admin_ptr_client.show_ptr_record(
+ floatingip_id=fip_id,
+ headers={
+ 'x-auth-sudo-project-id': self.primary_ptr_client.project_id})
+ self.assertExpected(ptr, show_ptr, self.excluded_keys)
+
@decorators.idempotent_id('9187a9c6-87d4-11eb-9f9a-74e5f9e2a801')
def test_list_floatingip_ptr_records(self):
number_of_ptr_records = 3
@@ -81,14 +115,34 @@
'Failed - received PTR IDs: {} are not as'
' expected: {}'.format(created_ptr_ids, received_ptr_ids))
+ @decorators.idempotent_id('a108d6f2-e3c0-11eb-a097-74e5f9e2a801')
+ @decorators.skip_because(bug="1935977")
+ def test_list_floatingip_ptr_all_projects(self):
+ ptr = self._set_ptr()[1]
+ LOG.info('Created PTR is:{}'.format(ptr))
+
+ LOG.info('As Admin user, try to list PTR record for all projects '
+ 'by including "x-auth-all-projects" HTTP header.')
+ received_ptr_ids = [
+ item['id'] for item in self.admin_ptr_client.list_ptr_records(
+ headers={'x-auth-all-projects': True})]
+ self.assertGreater(
+ len(received_ptr_ids), 0,
+ 'Failed, "received_ptr_ids" should not be empty')
+ self.assertIn(
+ ptr['id'], received_ptr_ids,
+ 'Failed, expected ID was not found in "received_ptr_ids" list.')
+
@decorators.idempotent_id('499b5a7e-87e1-11eb-b412-74e5f9e2a801')
+ @decorators.skip_because(bug="1932026")
def test_unset_floatingip_ptr(self):
fip_id, ptr = self._set_ptr()
- self.primary_ptr_client.unset_ptr_record(fip_id)
+ self._unset_ptr(fip_id)
class DesignatePtrRecordNegative(BasePtrTest, tempest.test.BaseTestCase):
- credentials = ["primary"]
+
+ credentials = ['primary', 'admin']
@classmethod
def setup_credentials(cls):
@@ -101,24 +155,79 @@
super(DesignatePtrRecordNegative, cls).setup_clients()
cls.primary_ptr_client = cls.os_primary.dns_v2.PtrClient()
cls.primary_floating_ip_client = cls.os_primary.floating_ips_client
+ cls.admin_ptr_client = cls.os_admin.dns_v2.PtrClient()
def _set_ptr(self, ptr_name=None, ttl=None, description=None,
- headers=None):
- fip = self.primary_floating_ip_client.create_floatingip(
- floating_network_id=CONF.network.public_network_id)[
- 'floatingip']
- fip_id = fip['id']
- self.addCleanup(self.primary_floating_ip_client.delete_floatingip,
- fip_id)
+ headers=None, tld=TLD, fip_id=None):
+ if not fip_id:
+ fip = self.primary_floating_ip_client.create_floatingip(
+ floating_network_id=CONF.network.public_network_id)[
+ 'floatingip']
+ fip_id = fip['id']
+ self.addCleanup(
+ self.primary_floating_ip_client.delete_floatingip, fip_id)
ptr = self.primary_ptr_client.set_ptr_record(
fip_id, ptr_name=ptr_name, ttl=ttl, description=description,
- headers=headers)
+ headers=headers, tld=tld)
self.addCleanup(self.primary_ptr_client.unset_ptr_record, fip_id)
self.assertEqual('CREATE', ptr['action'])
self.assertEqual('PENDING', ptr['status'])
+ waiters.wait_for_ptr_status(
+ self.primary_ptr_client, fip_id=fip_id, status=const.ACTIVE)
return fip_id, ptr
+ @decorators.attr(type='negative')
+ @decorators.idempotent_id('8392db50-cdd0-11eb-a00f-74e5f9e2a801')
def test_set_floatingip_ptr_invalid_ttl(self):
LOG.info('Try to set PTR record using invalid TTL value')
with self.assertRaisesDns(lib_exc.BadRequest, 'invalid_object', 400):
self._set_ptr(ttl=-10)
+
+ @decorators.attr(type='negative')
+ @decorators.idempotent_id('0c9349ae-e2e8-11eb-a097-74e5f9e2a801')
+ def test_set_floatingip_ptr_not_existing_fip_id(self):
+ LOG.info('Try to set PTR record using not existing Floating IP')
+ with self.assertRaisesDns(lib_exc.NotFound, 'not_found', 404):
+ self._set_ptr(fip_id=data_utils.rand_uuid())
+
+ @decorators.attr(type='negative')
+ @decorators.idempotent_id('df217902-e3b2-11eb-a097-74e5f9e2a801')
+ def test_set_floatingip_ptr_huge_size_description(self):
+ LOG.info('Try to set PTR record using huge size description string')
+ with self.assertRaisesDns(lib_exc.BadRequest, 'invalid_object', 400):
+ self._set_ptr(description=dns_data_utils.rand_string(5000))
+
+ @decorators.attr(type='negative')
+ @decorators.idempotent_id('cb2264e2-e3b3-11eb-a097-74e5f9e2a801')
+ def test_set_floatingip_ptr_invalid_name(self):
+ invalid_names = ['', '@!(*&', 4564, dns_data_utils.rand_string(5000)]
+ for name in invalid_names:
+ LOG.info('Set PTR record using invalid name:{}'.format(name))
+ with self.assertRaisesDns(
+ lib_exc.BadRequest, 'invalid_object', 400):
+ self._set_ptr(description=dns_data_utils.rand_string(5000))
+
+ @decorators.attr(type='negative')
+ @decorators.idempotent_id('f616d216-51ac-11ec-8edf-201e8823901f')
+ def test_show_floatingip_ptr_impersonate_another_project_no_header(self):
+ fip_id, ptr = self._set_ptr()
+
+ LOG.info('As Admin user, show PTR record created by Primary'
+ ' user, without including "x-auth-sudo-project-id" '
+ 'HTTP header in request.')
+ with self.assertRaisesDns(lib_exc.NotFound, 'not_found', 404):
+ self.admin_ptr_client.show_ptr_record(floatingip_id=fip_id)
+
+ @decorators.attr(type='negative')
+ @decorators.idempotent_id('0d132ff0-51ad-11ec-8edf-201e8823901f')
+ @decorators.skip_because(bug="1935977")
+ def test_list_floatingip_ptr_all_projects_no_header(self):
+ ptr = self._set_ptr()[1]
+ LOG.info('Created PTR is:{}'.format(ptr))
+
+ LOG.info('As Admin user, try to list PTR record for all projects '
+ 'without including "x-auth-all-projects" HTTP header.')
+ received_ptr_ids = [
+ item['id'] for item in self.admin_ptr_client.list_ptr_records()]
+ self.assertEqual([], received_ptr_ids,
+ 'Failed, "received_ptr_ids" list should be empty')