Merge "Unroll DDT API tests used for refstack/interop"
diff --git a/designate_tempest_plugin/common/waiters.py b/designate_tempest_plugin/common/waiters.py
index ee59702..2b7a3b6 100644
--- a/designate_tempest_plugin/common/waiters.py
+++ b/designate_tempest_plugin/common/waiters.py
@@ -51,16 +51,16 @@
             raise lib_exc.TimeoutException(message)
 
 
-def wait_for_zone_status(client, zone_id, status):
+def wait_for_zone_status(client, zone_id, status, headers=None):
     """Waits for a zone to reach given status."""
     LOG.info('Waiting for zone %s to reach %s', zone_id, status)
 
-    _, zone = client.show_zone(zone_id)
+    _, zone = client.show_zone(zone_id, headers=headers)
     start = int(time.time())
 
     while zone['status'] != status:
         time.sleep(client.build_interval)
-        _, zone = client.show_zone(zone_id)
+        _, zone = client.show_zone(zone_id, headers=headers)
         status_curr = zone['status']
         if status_curr == status:
             LOG.info('Zone %s reached %s', zone_id, status)
diff --git a/designate_tempest_plugin/config.py b/designate_tempest_plugin/config.py
index 3aadb96..99c9a04 100644
--- a/designate_tempest_plugin/config.py
+++ b/designate_tempest_plugin/config.py
@@ -79,4 +79,24 @@
                 default=True,
                 help="Is https://bugs.launchpad.net/designate/+bug/1573141 "
                 "fixed"),
+    # Note: Also see the enforce_scope section (from tempest) for Designate API
+    #       scope checking setting.
+    cfg.BoolOpt('enforce_new_defaults',
+                default=False,
+                help='Does the dns service API policies enforce '
+                     'the new keystone default roles? This configuration '
+                     'value should be same as designate.conf: '
+                     '[oslo_policy].enforce_new_defaults option.'),
+]
+
+# Extending this enforce_scope group defined in tempest
+enforce_scope_group = cfg.OptGroup(name="enforce_scope",
+                                   title="OpenStack Services with "
+                                         "enforce scope")
+EnforceScopeGroup = [
+    cfg.BoolOpt('designate',
+                default=False,
+                help='Does the dns service API policies enforce '
+                     'scope? This configuration value should be same as '
+                     'designate.conf: [oslo_policy].enforce_scope option.'),
 ]
diff --git a/designate_tempest_plugin/data_utils.py b/designate_tempest_plugin/data_utils.py
index 2f61d97..c9d3f6d 100644
--- a/designate_tempest_plugin/data_utils.py
+++ b/designate_tempest_plugin/data_utils.py
@@ -141,10 +141,12 @@
         'ttl': ttl}
 
 
-def rand_a_recordset(zone_name, ip=None, **kwargs):
-    if ip is None:
-        ip = rand_ip()
-    return rand_recordset_data('A', zone_name, records=[ip], **kwargs)
+def rand_a_recordset(zone_name, ips=None, **kwargs):
+    if ips is None:
+        return rand_recordset_data(
+            'A', zone_name, records=[rand_ip()], **kwargs)
+    else:
+        return rand_recordset_data('A', zone_name, records=ips, **kwargs)
 
 
 def rand_aaaa_recordset(zone_name, ip=None, **kwargs):
diff --git a/designate_tempest_plugin/plugin.py b/designate_tempest_plugin/plugin.py
index 7e33261..15e7cc5 100644
--- a/designate_tempest_plugin/plugin.py
+++ b/designate_tempest_plugin/plugin.py
@@ -58,6 +58,8 @@
                                   project_config.DnsGroup)
         config.register_opt_group(conf, project_config.dns_feature_group,
                                   project_config.DnsFeatureGroup)
+        config.register_opt_group(conf, project_config.enforce_scope_group,
+                                  project_config.EnforceScopeGroup)
 
     def get_opt_lists(self):
         """
diff --git a/designate_tempest_plugin/services/dns/v2/__init__.py b/designate_tempest_plugin/services/dns/v2/__init__.py
index 2f738df..44cc403 100644
--- a/designate_tempest_plugin/services/dns/v2/__init__.py
+++ b/designate_tempest_plugin/services/dns/v2/__init__.py
@@ -39,9 +39,11 @@
     ZoneExportsClient
 from designate_tempest_plugin.services.dns.v2.json.zone_imports_client import \
     ZoneImportsClient
+from designate_tempest_plugin.services.dns.v2.json.api_version_client import \
+    ApiVersionClient
 
 __all__ = ['BlacklistsClient', 'DesignateLimitClient', 'PoolClient',
            'PtrClient', 'QuotasClient', 'RecordsetClient', 'ServiceClient',
            'TldClient', 'TransferAcceptClient', 'TransferRequestClient',
            'TsigkeyClient', 'ZonesClient', 'ZoneExportsClient',
-           'ZoneImportsClient']
+           'ZoneImportsClient', 'ApiVersionClient']
diff --git a/designate_tempest_plugin/services/dns/v2/json/api_version_client.py b/designate_tempest_plugin/services/dns/v2/json/api_version_client.py
new file mode 100644
index 0000000..5a78540
--- /dev/null
+++ b/designate_tempest_plugin/services/dns/v2/json/api_version_client.py
@@ -0,0 +1,27 @@
+# Copyright 2021 Red Hat.
+#
+# 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 designate_tempest_plugin.services.dns.v2.json import base
+
+
+class ApiVersionClient(base.DnsClientV2Base):
+
+    @base.handle_errors
+    def list_enabled_api_versions(self):
+        """Show all enabled API versions
+
+        :return: Dictionary containing version details
+        """
+        resp, body = self.get('/')
+        self.expected_success(self.LIST_STATUS_CODES, resp.status)
+        return resp, self.deserialize(resp, body)
diff --git a/designate_tempest_plugin/services/dns/v2/json/blacklists_client.py b/designate_tempest_plugin/services/dns/v2/json/blacklists_client.py
index c3f6de1..bfe65c7 100644
--- a/designate_tempest_plugin/services/dns/v2/json/blacklists_client.py
+++ b/designate_tempest_plugin/services/dns/v2/json/blacklists_client.py
@@ -36,6 +36,9 @@
             'description': description or data_utils.rand_name(),
         }
 
+        if pattern == '':
+            blacklist['pattern'] = ''
+
         resp, body = self._create_request('blacklists', blacklist,
                                           params=params)
 
diff --git a/designate_tempest_plugin/services/dns/v2/json/pool_client.py b/designate_tempest_plugin/services/dns/v2/json/pool_client.py
index 67e8de8..4a703d4 100644
--- a/designate_tempest_plugin/services/dns/v2/json/pool_client.py
+++ b/designate_tempest_plugin/services/dns/v2/json/pool_client.py
@@ -22,7 +22,8 @@
     """API V2 Tempest REST client for Pool API"""
 
     @base.handle_errors
-    def create_pool(self, pool_name=None, ns_records=None, params=None):
+    def create_pool(self, pool_name=None, ns_records=None, params=None,
+                    project_id=None):
         """Create a pool with the specified parameters.
         :param pool_name: name of the pool.
             Default: Random Value.
@@ -30,12 +31,15 @@
                            with priority.
         :param params: A Python dict that represents the query paramaters to
                        include in the request URI.
+        :param project_id: The project ID to associate the pool with.
         :return: A tuple with the server response and the created pool.
         """
         pool = {
                  "name": pool_name or data_utils.rand_name(name="Demo pool"),
                  "ns_records": ns_records or dns_data_utils.rand_ns_records()
         }
+        if project_id:
+            pool["project_id"] = project_id
 
         resp, body = self._create_request('pools', data=pool, params=params)
 
@@ -45,33 +49,38 @@
         return resp, body
 
     @base.handle_errors
-    def show_pool(self, uuid, params=None):
+    def show_pool(self, uuid, params=None, headers=None):
         """Gets a specific pool.
         :param uuid: Unique identifier of the pool in UUID format.
         :param params: A Python dict that represents the query paramaters to
                        include in the request URI.
+        :param headers: The optional headers to include in the show request.
         :return: Serialized pool as a dictionary.
         """
-        return self._show_request('pools', uuid, params=params)
+        return self._show_request('pools', uuid, params=params,
+                                  headers=headers)
 
     @base.handle_errors
-    def list_pools(self, params=None):
+    def list_pools(self, params=None, headers=None):
         """Gets a list of pools.
         :param params: A Python dict that represents the query paramaters to
                        include in the request URI.
+        :param headers: The optional headers to include in the list request.
         :return: Serialized pools as a list.
         """
-        return self._list_request('pools', params=params)
+        return self._list_request('pools', params=params, headers=headers)
 
     @base.handle_errors
-    def delete_pool(self, uuid, params=None):
+    def delete_pool(self, uuid, params=None, headers=None):
         """Deletes a pool having the specified UUID.
         :param uuid: The unique identifier of the pool.
         :param params: A Python dict that represents the query paramaters to
                        include in the request URI.
+        :param headers: The optional headers to include in the delete request.
         :return: A tuple with the server response and the response body.
         """
-        resp, body = self._delete_request('pools', uuid, params=params)
+        resp, body = self._delete_request('pools', uuid, params=params,
+                                          headers=headers)
 
         # Delete Pool should Return a HTTP 204
         self.expected_success(204, resp.status)
@@ -80,7 +89,7 @@
 
     @base.handle_errors
     def update_pool(self, uuid, pool_name=None, ns_records=None,
-                    params=None):
+                    params=None, headers=None, extra_headers=False):
         """Update a pool with the specified parameters.
         :param uuid: The unique identifier of the pool.
         :param pool_name: name of the pool.
@@ -90,6 +99,9 @@
             Default: Random Value.
         :param params: A Python dict that represents the query paramaters to
                        include in the request URI.
+        :param headers: The optional headers to include in the update request.
+        :param extra_headers: A boolean indicating that the headers replace
+                              default headers or are in addition.
         :return: A tuple with the server response and the updated pool.
         """
 
@@ -99,7 +111,8 @@
         }
 
         resp, body = self._update_request('pools', uuid, pool,
-                                          params=params)
+                                          params=params, headers=headers,
+                                          extra_headers=extra_headers)
 
         # Update Pool should Return a HTTP 202
         self.expected_success(202, resp.status)
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 df2cdee..97398c0 100644
--- a/designate_tempest_plugin/services/dns/v2/json/quotas_client.py
+++ b/designate_tempest_plugin/services/dns/v2/json/quotas_client.py
@@ -19,12 +19,13 @@
 class QuotasClient(base.DnsClientV2Base):
 
     @base.handle_errors
-    def update_quotas(self, zones=None, zone_records=None,
+    def update_quotas(self, project_id, zones=None, zone_records=None,
                       zone_recordsets=None, recordset_records=None,
-                      api_export_size=None, project_id=None, params=None,
+                      api_export_size=None, params=None,
                       headers=None):
         """Update the quotas for the project id
 
+        :param project_id: Apply the quotas to this project id
         :param zones: The limit on zones per tenant
             Default: Random Value
         :param zone_records: The limit on records per zone
@@ -35,15 +36,11 @@
             Default: Random Value
         :param api_export_size: The limit on size of on exported zone
             Default: Random Value
-        :param project_id: Apply the quotas to this project id
-            Default: The project id of this client
         :param params: A Python dict that represents the query paramaters to
                        include in the request URI.
         :param headers (dict): The headers to use for the request.
         :return: A tuple with the server response and the created quota.
         """
-        project_id = project_id or self.tenant_id
-
         quotas = dns_data_utils.rand_quotas(
             zones=zones,
             zone_records=zone_records,
@@ -61,33 +58,28 @@
         return resp, body
 
     @base.handle_errors
-    def show_quotas(self, project_id=None, params=None, headers=None):
+    def show_quotas(self, project_id, params=None, headers=None):
         """Gets a specific quota.
 
         :param project_id: Show the quotas of this project id
-            Default: The project id of this client
         :param params: A Python dict that represents the query paramaters to
                        include in the request URI.
         :param headers (dict): The headers to use for the request.
         :return: Serialized quota as a dictionary.
         """
-        project_id = project_id or self.tenant_id
         return self._show_request('quotas', project_id, params=params,
                                   headers=headers, extra_headers=True)
 
     @base.handle_errors
-    def delete_quotas(self, project_id=None, params=None, headers=None):
+    def delete_quotas(self, project_id, params=None, headers=None):
         """Resets the quotas for the specified project id
 
         :param project_id: Reset the quotas of this project id
-            Default: The project id of this client
         :param params: A Python dict that represents the query paramaters to
                        include in the request URI.
         :param headers (dict): The headers to use for the request.
         :return: A tuple with the server response and the response body.
         """
-        project_id = project_id or self.tenant_id
-
         resp, body = self._delete_request(
             'quotas', project_id,
             params=params, headers=headers,
@@ -96,3 +88,25 @@
         self.expected_success(204, resp.status)
 
         return resp, body
+
+    @base.handle_errors
+    def set_quotas(self, project_id, quotas, params=None, headers=None):
+        """Set a specific quota to given project ID
+
+        :param project_id: Set the quotas of this project id.
+        :param quotas: Dictionary of quotas to set (POST payload)
+        :param params: A Python dict that represents the query paramaters to
+                       include in the request URI.
+        :param headers (dict): The headers to use for the request.
+        :return: Serialized quota as a dictionary.
+        """
+        if headers is None:
+            headers = {'content-type': 'application/json'}
+        if 'content-type' not in [header.lower() for header in headers]:
+            headers['content-type'] = 'application/json'
+
+        resp, body = self._update_request(
+            "quotas", project_id,
+            data=quotas, params=params, headers=headers)
+        self.expected_success(200, resp.status)
+        return resp, body
diff --git a/designate_tempest_plugin/services/dns/v2/json/zones_client.py b/designate_tempest_plugin/services/dns/v2/json/zones_client.py
index 4becb58..c30d24e 100644
--- a/designate_tempest_plugin/services/dns/v2/json/zones_client.py
+++ b/designate_tempest_plugin/services/dns/v2/json/zones_client.py
@@ -27,7 +27,7 @@
     def create_zone(self, name=None, email=None, ttl=None, description=None,
                     attributes=None, wait_until=False,
                     zone_type=const.PRIMARY_ZONE_TYPE,
-                    primaries=None, params=None):
+                    primaries=None, params=None, project_id=None):
 
         """Create a zone with the specified parameters.
 
@@ -50,6 +50,8 @@
             Default: None
         :param params: A Python dict that represents the query paramaters to
                        include in the request URI.
+        :param project_id: When specified, overrides the project ID the zone
+                           will be associated with.
         :return: A tuple with the server response and the created zone.
         """
 
@@ -76,13 +78,23 @@
                     ' for a SECONDARY zone type')
 
             zone['masters'] = primaries
-        resp, body = self._create_request('zones', zone, params=params)
+
+        headers = None
+        extra_headers = False
+        if project_id:
+            headers = {'x-auth-sudo-project-id': project_id}
+            extra_headers = True
+
+        resp, body = self._create_request('zones', zone, params=params,
+                                          headers=headers,
+                                          extra_headers=extra_headers)
 
         # Create Zone should Return a HTTP 202
         self.expected_success(202, resp.status)
 
         if wait_until:
-            waiters.wait_for_zone_status(self, body['id'], wait_until)
+            waiters.wait_for_zone_status(self, body['id'], wait_until,
+                                         headers=headers)
 
         return resp, body
 
diff --git a/designate_tempest_plugin/tests/api/admin/test_quotas.py b/designate_tempest_plugin/tests/api/admin/test_quotas.py
index 0195ee3..dd4bed2 100644
--- a/designate_tempest_plugin/tests/api/admin/test_quotas.py
+++ b/designate_tempest_plugin/tests/api/admin/test_quotas.py
@@ -18,8 +18,8 @@
 from designate_tempest_plugin.tests import base
 from designate_tempest_plugin import data_utils as dns_data_utils
 
-LOG = logging.getLogger(__name__)
 CONF = config.CONF
+LOG = logging.getLogger(__name__)
 
 
 class BaseQuotasTest(base.BaseDnsAdminTest):
@@ -34,12 +34,14 @@
 
 class QuotasAdminTest(BaseQuotasTest):
 
-    credentials = ["admin"]
+    credentials = ["admin", "primary", "system_admin"]
 
     def setUp(self):
         super(QuotasAdminTest, self).setUp()
-        _, original_quotas = self.admin_client.show_quotas()
+        _, original_quotas = self.admin_client.show_quotas(
+            project_id=self.quotas_client.project_id)
         self.addCleanup(self.admin_client.update_quotas,
+                        project_id=self.quotas_client.project_id,
                         **original_quotas['quota'])
 
     @classmethod
@@ -51,18 +53,24 @@
     @classmethod
     def setup_clients(cls):
         super(QuotasAdminTest, cls).setup_clients()
-
-        cls.admin_client = cls.os_admin.dns_admin.QuotasClient()
+        if CONF.enforce_scope.designate:
+            cls.admin_client = cls.os_system_admin.dns_admin.QuotasClient()
+        else:
+            cls.admin_client = cls.os_admin.dns_admin.QuotasClient()
+        cls.quotas_client = cls.os_primary.dns_v2.QuotasClient()
 
     @decorators.idempotent_id('ed42f367-e5ba-40d7-a08d-366ad787d21c')
     def test_show_quotas(self):
         LOG.info("Updating quotas")
         quotas = dns_data_utils.rand_quotas()
-        _, body = self.admin_client.update_quotas(**quotas)
-        self.addCleanup(self.admin_client.delete_quotas)
+        _, body = self.admin_client.update_quotas(
+            project_id=self.quotas_client.project_id, **quotas)
+        self.addCleanup(self.admin_client.delete_quotas,
+                        project_id=self.quotas_client.project_id)
 
         LOG.info("Fetching quotas")
-        _, body = self.admin_client.show_quotas()
+        _, body = self.admin_client.show_quotas(
+            project_id=self.quotas_client.project_id)
 
         LOG.info("Ensuring the response has all quota types")
         self.assertExpected(quotas, body['quota'], self.excluded_keys)
@@ -70,7 +78,8 @@
     @decorators.idempotent_id('33e0affb-5d66-4216-881c-f101a779851a')
     def test_delete_quotas(self):
         LOG.info("Deleting quotas")
-        _, body = self.admin_client.delete_quotas()
+        _, body = self.admin_client.delete_quotas(
+            project_id=self.quotas_client.project_id)
 
         LOG.info("Ensuring an empty response body")
         self.assertEqual(body.strip(), b"")
@@ -79,8 +88,11 @@
     def test_update_quotas(self):
         LOG.info("Updating quotas")
         quotas = dns_data_utils.rand_quotas()
-        _, body = self.admin_client.update_quotas(**quotas)
-        self.addCleanup(self.admin_client.delete_quotas)
+        _, body = self.admin_client.update_quotas(
+            project_id=self.quotas_client.project_id,
+            **quotas)
+        self.addCleanup(self.admin_client.delete_quotas,
+                        project_id=self.quotas_client.project_id)
 
         LOG.info("Ensuring the response has all quota types")
         self.assertExpected(quotas, body['quota'], self.excluded_keys)
diff --git a/designate_tempest_plugin/tests/api/v2/test_blacklists.py b/designate_tempest_plugin/tests/api/v2/test_blacklists.py
index 0e22bf6..95688b3 100644
--- a/designate_tempest_plugin/tests/api/v2/test_blacklists.py
+++ b/designate_tempest_plugin/tests/api/v2/test_blacklists.py
@@ -12,6 +12,7 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 from oslo_log import log as logging
+from tempest import config
 from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest.lib.common.utils import data_utils
@@ -19,6 +20,7 @@
 from designate_tempest_plugin import data_utils as dns_data_utils
 from designate_tempest_plugin.tests import base
 
+CONF = config.CONF
 LOG = logging.getLogger(__name__)
 
 
@@ -28,8 +30,7 @@
 
 class BlacklistsAdminTest(BaseBlacklistsTest):
 
-    credentials = ["admin"]
-
+    credentials = ["admin", "system_admin", "primary"]
     @classmethod
     def setup_credentials(cls):
         # Do not create network resources for these test.
@@ -39,7 +40,12 @@
     @classmethod
     def setup_clients(cls):
         super(BlacklistsAdminTest, cls).setup_clients()
-        cls.admin_client = cls.os_admin.dns_v2.BlacklistsClient()
+
+        if CONF.enforce_scope.designate:
+            cls.admin_client = cls.os_system_admin.dns_v2.BlacklistsClient()
+        else:
+            cls.admin_client = cls.os_admin.dns_v2.BlacklistsClient()
+        cls.primary_client = cls.os_primary.dns_v2.BlacklistsClient()
 
     @decorators.idempotent_id('3a7f7564-6bdd-446e-addc-a3475b4c3f71')
     def test_create_blacklist(self):
@@ -53,6 +59,30 @@
 
         self.assertExpected(blacklist, body, self.excluded_keys)
 
+    @decorators.idempotent_id('ea608152-da3c-11eb-b8b8-74e5f9e2a801')
+    @decorators.skip_because(bug="1934252")
+    def test_create_blacklist_invalid_pattern(self):
+        patterns = ['', '#(*&^%$%$#@$', 'a' * 1000]
+        for pattern in patterns:
+            LOG.info(
+                'Try to create a blacklist using pattern:{}'.format(pattern))
+            self.assertRaises(
+                lib_exc.BadRequest, self.admin_client.create_blacklist,
+                pattern=pattern)
+
+    @decorators.idempotent_id('664bdaa0-da47-11eb-b8b8-74e5f9e2a801')
+    def test_create_blacklist_huge_size_description(self):
+        LOG.info('Try to create a blacklist using huge size description')
+        self.assertRaises(
+            lib_exc.BadRequest, self.admin_client.create_blacklist,
+            description='a' * 1000)
+
+    @decorators.idempotent_id('fe9de464-d8d1-11eb-bcdc-74e5f9e2a801')
+    def test_create_blacklist_as_primary_fails(self):
+        LOG.info('As Primary user, try to create a blacklist')
+        self.assertRaises(
+            lib_exc.Forbidden, self.primary_client.create_blacklist)
+
     @decorators.idempotent_id('5bc02942-6225-4619-8f49-2105581a8dd6')
     def test_show_blacklist(self):
         LOG.info('Create a blacklist')
@@ -112,7 +142,7 @@
 
 class TestBlacklistNotFoundAdmin(BaseBlacklistsTest):
 
-    credentials = ["admin"]
+    credentials = ["admin", "system_admin"]
 
     @classmethod
     def setup_credentials(cls):
@@ -123,7 +153,10 @@
     @classmethod
     def setup_clients(cls):
         super(TestBlacklistNotFoundAdmin, cls).setup_clients()
-        cls.admin_client = cls.os_admin.dns_v2.BlacklistsClient()
+        if CONF.enforce_scope.designate:
+            cls.admin_client = cls.os_system_admin.dns_v2.BlacklistsClient()
+        else:
+            cls.admin_client = cls.os_admin.dns_v2.BlacklistsClient()
 
     @decorators.idempotent_id('9d65b638-fe98-47a8-853f-fa9244d144cc')
     def test_show_blacklist_404(self):
@@ -155,7 +188,7 @@
 
 class TestBlacklistInvalidIdAdmin(BaseBlacklistsTest):
 
-    credentials = ["admin"]
+    credentials = ["admin", "system_admin"]
 
     @classmethod
     def setup_credentials(cls):
@@ -166,7 +199,10 @@
     @classmethod
     def setup_clients(cls):
         super(TestBlacklistInvalidIdAdmin, cls).setup_clients()
-        cls.admin_client = cls.os_admin.dns_v2.BlacklistsClient()
+        if CONF.enforce_scope.designate:
+            cls.admin_client = cls.os_system_admin.dns_v2.BlacklistsClient()
+        else:
+            cls.admin_client = cls.os_admin.dns_v2.BlacklistsClient()
 
     @decorators.idempotent_id('c7bae53f-2edc-45d8-b254-8a81482728c1')
     def test_show_blacklist_invalid_uuid(self):
diff --git a/designate_tempest_plugin/tests/api/v2/test_designate_limits.py b/designate_tempest_plugin/tests/api/v2/test_designate_limits.py
index 5db07c1..2cb9d9e 100644
--- a/designate_tempest_plugin/tests/api/v2/test_designate_limits.py
+++ b/designate_tempest_plugin/tests/api/v2/test_designate_limits.py
@@ -12,15 +12,19 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 from oslo_log import log as logging
+from tempest import config
 from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
+
 
 from designate_tempest_plugin.tests import base
 
+CONF = config.CONF
 LOG = logging.getLogger(__name__)
 
 
 class DesignateLimit(base.BaseDnsV2Test):
-    credentials = ['admin']
+    credentials = ["admin", "system_admin", "primary", "alt"]
 
     @classmethod
     def setup_credentials(cls):
@@ -31,16 +35,22 @@
     @classmethod
     def setup_clients(cls):
         super(DesignateLimit, cls).setup_clients()
-        cls.admin_client = cls.os_admin.dns_v2.DesignateLimitClient()
+        if CONF.enforce_scope.designate:
+            cls.admin_client = (cls.os_system_admin.dns_v2.
+                                DesignateLimitClient())
+        else:
+            cls.admin_client = cls.os_admin.dns_v2.DesignateLimitClient()
+        cls.primary_client = cls.os_primary.dns_v2.DesignateLimitClient()
+        cls.alt_client = cls.os_alt.dns_v2.DesignateLimitClient()
 
     @decorators.idempotent_id('828572be-8662-11eb-8ff2-74e5f9e2a801')
-    def test_list_designate_limits(self):
+    def test_list_designate_limits_as_primary_user(self):
         expected_default_limits_fields = [
             "max_page_limit", "max_recordset_name_length",
             "max_recordset_records", "max_zone_name_length",
             "max_zone_records", "max_zone_recordsets",
             "max_zones", "min_ttl"].sort()
-        project_limits = self.admin_client.list_designate_limits()
+        project_limits = self.primary_client.list_designate_limits()
         LOG.info(
             'Retrieved designate limits are: {} '.format(project_limits))
         self.assertEqual(
@@ -49,3 +59,46 @@
             'Retrieved fields: {} are not as expected: {} '.format(
                 list(project_limits.keys()).sort(),
                 expected_default_limits_fields))
+
+    @decorators.idempotent_id('828572be-8662-11eb-8ff2-74e5f9e2a801')
+    def test_list_designate_impersonate_another_user_as_admin(self):
+        primary_project_limits = self.primary_client.list_designate_limits()
+        LOG.info(
+            'Retrieved designate limits for Primary user are: {} '.format(
+                primary_project_limits))
+        admin_sudo_project_limits = self.admin_client.list_designate_limits(
+            headers={'x-auth-sudo-project-id': self.primary_client.project_id})
+        LOG.info(
+            'Retrieved designate limits for Admin user impersonates '
+            'Primary user are: {} '.format(admin_sudo_project_limits))
+        self.assertEqual(
+            primary_project_limits, admin_sudo_project_limits,
+            'Failed, Admin user should receive the same values for '
+            'Designate limits as a Primary tenant did.')
+
+    @decorators.idempotent_id('5975fee0-d430-11eb-aa4d-74e5f9e2a801')
+    def test_list_designate_impersonate_another_user_as_alt(self):
+        self.assertRaises(
+            lib_exc.Forbidden, self.alt_client.list_designate_limits,
+            headers={'x-auth-sudo-project-id': self.primary_client.project_id})
+
+    @decorators.idempotent_id('828572be-8662-11eb-8ff2-74e5f9e2a801')
+    @decorators.skip_because(bug="1933444")
+    def test_list_designate_limits_all_projects(self):
+        existing_project_ids = [
+            self.primary_client.project_id, self.alt_client.project_id]
+        LOG.info('Project IDs we would expect to receive with Admin user '
+                 'uses: "x-auth-all-projects" HTTP header '
+                 'are {}: '.format(existing_project_ids))
+        all_project_limits = self.admin_client.list_designate_limits(
+            headers={'x-auth-all-projects': True})
+        LOG.info(
+            'Retrieved designate limits by Admin user for all projects '
+            'are: '.format(all_project_limits))
+        received_project_ids = [
+            item['project_id'] for item in all_project_limits]
+        for project_id in existing_project_ids:
+            self.assertIn(
+                project_id, received_project_ids,
+                'Failed, expected project_id:{} is missing in:{} '.format(
+                    project_id, received_project_ids))
diff --git a/designate_tempest_plugin/tests/api/v2/test_enabled_api_version.py b/designate_tempest_plugin/tests/api/v2/test_enabled_api_version.py
new file mode 100644
index 0000000..db98a9d
--- /dev/null
+++ b/designate_tempest_plugin/tests/api/v2/test_enabled_api_version.py
@@ -0,0 +1,71 @@
+# Copyright 2021 Red Hat.
+#
+# 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.
+import requests
+
+from oslo_log import log as logging
+from tempest.lib import decorators
+
+from designate_tempest_plugin.tests import base
+from designate_tempest_plugin.services.dns.v2.json import base as service_base
+
+from tempest import config
+
+CONF = config.CONF
+LOG = logging.getLogger(__name__)
+
+
+class DesignateApiVersion(base.BaseDnsV2Test, service_base.DnsClientV2Base):
+    credentials = ['admin', 'primary']
+
+    @classmethod
+    def setup_credentials(cls):
+        # Do not create network resources for these test.
+        cls.set_network_resources()
+        super(DesignateApiVersion, cls).setup_credentials()
+
+    @classmethod
+    def setup_clients(cls):
+        super(DesignateApiVersion, cls).setup_clients()
+
+        cls.admin_client = cls.os_admin.dns_v2.ApiVersionClient()
+        cls.primary_client = cls.os_primary.dns_v2.ApiVersionClient()
+
+    @decorators.idempotent_id('aa84986e-f2ad-11eb-b58d-74e5f9e2a801')
+    def test_list_enabled_api_versions(self):
+        for user in ['admin', 'primary', 'not_auth_user']:
+            if user == 'admin':
+                versions = self.admin_client.list_enabled_api_versions()[1][
+                    'versions']['values']
+            if user == 'primary':
+                versions = self.primary_client.list_enabled_api_versions()[1][
+                    'versions']['values']
+            if user == 'not_auth_user':
+                uri = CONF.identity.uri.split('identity')[0] + 'dns'
+                response = requests.get(uri, verify=False)
+                headers = {
+                    k.lower(): v.lower() for k, v in response.headers.items()}
+                versions = self.deserialize(
+                    headers, str(response.text))['versions']['values']
+
+            LOG.info('Received enabled API versions for {} '
+                     'user are:{}'.format(user, versions))
+            for item in versions:
+                enabled_ids = [
+                    item['id'] for key in item.keys() if key == 'id']
+            LOG.info('Enabled versions IDs are:{}'.format(enabled_ids))
+            possible_options = [['v1'], ['v2'], ['v1', 'v2']]
+            self.assertIn(
+                enabled_ids, possible_options,
+                'Failed, received version: {} is not in possible options'
+                ' list:{}'.format(enabled_ids, possible_options))
diff --git a/designate_tempest_plugin/tests/api/v2/test_pool.py b/designate_tempest_plugin/tests/api/v2/test_pool.py
index 21782ce..60af204 100644
--- a/designate_tempest_plugin/tests/api/v2/test_pool.py
+++ b/designate_tempest_plugin/tests/api/v2/test_pool.py
@@ -15,12 +15,14 @@
 from operator import itemgetter
 
 from oslo_log import log as logging
+from tempest import config
 from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest.lib.common.utils import data_utils
 
 from designate_tempest_plugin.tests import base
 
+CONF = config.CONF
 LOG = logging.getLogger(__name__)
 
 
@@ -34,7 +36,7 @@
 
 
 class PoolAdminTest(BasePoolTest):
-    credentials = ['admin']
+    credentials = ["admin", "system_admin"]
 
     @classmethod
     def setup_credentials(cls):
@@ -45,12 +47,16 @@
     @classmethod
     def setup_clients(cls):
         super(PoolAdminTest, cls).setup_clients()
-        cls.admin_client = cls.os_admin.dns_v2.PoolClient()
+        if CONF.enforce_scope.designate:
+            cls.admin_client = cls.os_system_admin.dns_v2.PoolClient()
+        else:
+            cls.admin_client = cls.os_admin.dns_v2.PoolClient()
 
     @decorators.idempotent_id('69257f7c-b3d5-4e1b-998e-0677ad12f125')
     def test_create_pool(self):
         pool_data = {
                       "name": "Example Pool",
+                      "project_id": "1",
                       "ns_records": [{
                           "hostname": "ns1.example.org.",
                           "priority": 1}
@@ -58,8 +64,10 @@
                     }
         LOG.info('Create a pool')
         _, pool = self.admin_client.create_pool(pool_name=pool_data["name"],
-                      ns_records=pool_data["ns_records"])
-        self.addCleanup(self.admin_client.delete_pool, pool['id'])
+            ns_records=pool_data["ns_records"],
+            project_id=pool_data["project_id"])
+        self.addCleanup(self.admin_client.delete_pool, pool['id'],
+                        headers=self.all_projects_header)
 
         self.assertEqual(pool_data["name"], pool['name'])
         self.assertExpected(pool_data, pool, self.excluded_keys)
@@ -67,11 +75,13 @@
     @decorators.idempotent_id('e80eb70a-8ee5-40eb-b06e-599597a8ab7e')
     def test_show_pool(self):
         LOG.info('Create a pool')
-        _, pool = self.admin_client.create_pool()
-        self.addCleanup(self.admin_client.delete_pool, pool['id'])
+        _, pool = self.admin_client.create_pool(project_id="1")
+        self.addCleanup(self.admin_client.delete_pool, pool['id'],
+                        headers=self.all_projects_header)
 
         LOG.info('Fetch the pool')
-        _, body = self.admin_client.show_pool(pool['id'])
+        _, body = self.admin_client.show_pool(
+            pool['id'], headers=self.all_projects_header)
 
         LOG.info('Ensure the fetched response matches the created pool')
         self.assertExpected(pool, body, self.excluded_keys)
@@ -81,36 +91,43 @@
     @decorators.idempotent_id('d8c4c377-5d88-452d-a4d2-c004d72e1abe')
     def test_delete_pool(self):
         LOG.info('Create a pool')
-        _, pool = self.admin_client.create_pool()
+        _, pool = self.admin_client.create_pool(project_id="1")
         self.addCleanup(self.admin_client.delete_pool, pool['id'],
-                        ignore_errors=lib_exc.NotFound)
+                        ignore_errors=lib_exc.NotFound,
+                        headers=self.all_projects_header)
 
         LOG.info('Delete the pool')
-        _, body = self.admin_client.delete_pool(pool['id'])
+        _, body = self.admin_client.delete_pool(
+            pool['id'], headers=self.all_projects_header)
 
         self.assertRaises(lib_exc.NotFound,
-           lambda: self.admin_client.show_pool(pool['id']))
+           lambda: self.admin_client.show_pool(
+               pool['id'], headers=self.all_projects_header))
 
     @decorators.idempotent_id('77c85b40-83b2-4c17-9fbf-e6d516cfce90')
     def test_list_pools(self):
         LOG.info('Create a pool')
-        _, pool = self.admin_client.create_pool()
-        self.addCleanup(self.admin_client.delete_pool, pool['id'])
+        _, pool = self.admin_client.create_pool(project_id="1")
+        self.addCleanup(self.admin_client.delete_pool, pool['id'],
+                        headers=self.all_projects_header)
 
         LOG.info('List pools')
-        _, body = self.admin_client.list_pools()
+        _, body = self.admin_client.list_pools(
+            headers=self.all_projects_header)
 
         self.assertGreater(len(body['pools']), 0)
 
     @decorators.idempotent_id('fdcc84ce-af65-4af6-a5fc-6c50acbea0f0')
     def test_update_pool(self):
         LOG.info('Create a pool')
-        _, pool = self.admin_client.create_pool()
-        self.addCleanup(self.admin_client.delete_pool, pool['id'])
+        _, pool = self.admin_client.create_pool(project_id="1")
+        self.addCleanup(self.admin_client.delete_pool, pool['id'],
+                        headers=self.all_projects_header)
 
         LOG.info('Update the pool')
         _, patch_pool = self.admin_client.update_pool(
-            pool['id'], pool_name="foo")
+            pool['id'], pool_name="foo", headers=self.all_projects_header,
+            extra_headers=True)
 
         self.assertEqual("foo", patch_pool["name"])
 
@@ -124,7 +141,7 @@
 
 class TestPoolNotFoundAdmin(BasePoolTest):
 
-    credentials = ["admin"]
+    credentials = ["admin", "system_admin"]
 
     @classmethod
     def setup_credentials(cls):
@@ -135,7 +152,10 @@
     @classmethod
     def setup_clients(cls):
         super(TestPoolNotFoundAdmin, cls).setup_clients()
-        cls.admin_client = cls.os_admin.dns_v2.PoolClient()
+        if CONF.enforce_scope.designate:
+            cls.admin_client = cls.os_system_admin.dns_v2.PoolClient()
+        else:
+            cls.admin_client = cls.os_admin.dns_v2.PoolClient()
 
     @decorators.idempotent_id('56281b2f-dd5a-4376-8c32-aba771062fa5')
     def test_show_pool_404(self):
@@ -167,7 +187,7 @@
 
 class TestPoolInvalidIdAdmin(BasePoolTest):
 
-    credentials = ["admin"]
+    credentials = ["admin", "system_admin"]
 
     @classmethod
     def setup_credentials(cls):
@@ -178,7 +198,10 @@
     @classmethod
     def setup_clients(cls):
         super(TestPoolInvalidIdAdmin, cls).setup_clients()
-        cls.admin_client = cls.os_admin.dns_v2.PoolClient()
+        if CONF.enforce_scope.designate:
+            cls.admin_client = cls.os_system_admin.dns_v2.PoolClient()
+        else:
+            cls.admin_client = cls.os_admin.dns_v2.PoolClient()
 
     @decorators.idempotent_id('081d0188-42a7-4953-af0e-b022960715e2')
     def test_show_pool_invalid_uuid(self):
@@ -211,7 +234,7 @@
 
 class TestPoolAdminNegative(BasePoolTest):
 
-    credentials = ["admin"]
+    credentials = ["admin", "system_admin"]
 
     @classmethod
     def setup_credentials(cls):
@@ -222,7 +245,10 @@
     @classmethod
     def setup_clients(cls):
         super(TestPoolAdminNegative, cls).setup_clients()
-        cls.admin_client = cls.os_admin.dns_v2.PoolClient()
+        if CONF.enforce_scope.designate:
+            cls.admin_client = cls.os_system_admin.dns_v2.PoolClient()
+        else:
+            cls.admin_client = cls.os_admin.dns_v2.PoolClient()
 
     @decorators.idempotent_id('0a8cdc1e-ac02-11eb-ae06-74e5f9e2a801')
     def test_create_pool_invalid_name(self):
@@ -249,37 +275,43 @@
     # Note: Update pool API is deprecated for removal.
     def test_update_pool_with_invalid_name(self):
         LOG.info('Create a pool')
-        pool = self.admin_client.create_pool()[1]
-        self.addCleanup(self.admin_client.delete_pool, pool['id'])
+        pool = self.admin_client.create_pool(project_id="1")[1]
+        self.addCleanup(self.admin_client.delete_pool, pool['id'],
+                        headers=self.all_projects_header)
 
         LOG.info('Update the pool using a name that is too long')
         with self.assertRaisesDns(lib_exc.BadRequest, 'invalid_object', 400):
             self.admin_client.update_pool(
                 pool['id'],
-                pool_name=data_utils.rand_name(name="Huge_size_name") * 10000)
+                pool_name=data_utils.rand_name(name="Huge_size_name") * 10000,
+                headers=self.all_projects_header, extra_headers=True)
 
     @decorators.idempotent_id('2e496596-ac07-11eb-ae06-74e5f9e2a801')
     def test_update_pool_with_invalid_hostname_in_ns_records(self):
         # Note: Update pool API is deprecated for removal.
         LOG.info('Create a pool')
-        pool = self.admin_client.create_pool()[1]
-        self.addCleanup(self.admin_client.delete_pool, pool['id'])
+        pool = self.admin_client.create_pool(project_id="1")[1]
+        self.addCleanup(self.admin_client.delete_pool, pool['id'],
+                        headers=self.all_projects_header)
 
         LOG.info('Update the pool using invalid hostname in ns_records')
         with self.assertRaisesDns(lib_exc.BadRequest, 'invalid_object', 400):
             self.admin_client.update_pool(
                 pool['id'],
-                ns_records=[{"hostname": "ns1_example_org_", "priority": 1}])
+                ns_records=[{"hostname": "ns1_example_org_", "priority": 1}],
+                headers=self.all_projects_header, extra_headers=True)
 
     @decorators.idempotent_id('3e934624-ac07-11eb-ae06-74e5f9e2a801')
     def test_update_pool_with_invalid_priority_in_ns_records(self):
         # Note: Update pool API is deprecated for removal.
         LOG.info('Create a pool')
-        pool = self.admin_client.create_pool()[1]
-        self.addCleanup(self.admin_client.delete_pool, pool['id'])
+        pool = self.admin_client.create_pool(project_id="1")[1]
+        self.addCleanup(self.admin_client.delete_pool, pool['id'],
+                        headers=self.all_projects_header)
 
         LOG.info('Update the pool using invalid priority in ns_records')
         with self.assertRaisesDns(lib_exc.BadRequest, 'invalid_object', 400):
             self.admin_client.update_pool(
                 pool['id'],
-                ns_records=[{"hostname": "ns1.example.org.", "priority": -1}])
+                ns_records=[{"hostname": "ns1.example.org.", "priority": -1}],
+                headers=self.all_projects_header, extra_headers=True)
diff --git a/designate_tempest_plugin/tests/api/v2/test_ptrs.py b/designate_tempest_plugin/tests/api/v2/test_ptrs.py
index ef8f083..e2ad98a 100644
--- a/designate_tempest_plugin/tests/api/v2/test_ptrs.py
+++ b/designate_tempest_plugin/tests/api/v2/test_ptrs.py
@@ -19,9 +19,8 @@
 from designate_tempest_plugin.tests import base
 import tempest.test
 
-LOG = logging.getLogger(__name__)
-
 CONF = config.CONF
+LOG = logging.getLogger(__name__)
 
 
 class BasePtrTest(base.BaseDnsV2Test):
@@ -30,7 +29,7 @@
 
 
 class DesignatePtrRecord(BasePtrTest, tempest.test.BaseTestCase):
-    credentials = ['primary']
+    credentials = ["primary"]
 
     @classmethod
     def setup_credentials(cls):
@@ -89,7 +88,7 @@
 
 
 class DesignatePtrRecordNegative(BasePtrTest, tempest.test.BaseTestCase):
-    credentials = ['primary']
+    credentials = ["primary"]
 
     @classmethod
     def setup_credentials(cls):
diff --git a/designate_tempest_plugin/tests/api/v2/test_quotas.py b/designate_tempest_plugin/tests/api/v2/test_quotas.py
index 783ccdd..db870af 100644
--- a/designate_tempest_plugin/tests/api/v2/test_quotas.py
+++ b/designate_tempest_plugin/tests/api/v2/test_quotas.py
@@ -15,19 +15,18 @@
 from tempest import config
 from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
+from tempest.lib.common.utils import data_utils as tempest_data_utils
 
 from designate_tempest_plugin.tests import base
 from designate_tempest_plugin import data_utils as dns_data_utils
 
-LOG = logging.getLogger(__name__)
-
-
 CONF = config.CONF
+LOG = logging.getLogger(__name__)
 
 
 class QuotasV2Test(base.BaseDnsV2Test):
 
-    credentials = ['primary', 'admin', 'alt']
+    credentials = ["primary", "admin", "system_admin", "alt"]
 
     @classmethod
     def setup_credentials(cls):
@@ -48,16 +47,18 @@
     def setup_clients(cls):
         super(QuotasV2Test, cls).setup_clients()
 
+        if CONF.enforce_scope.designate:
+            cls.admin_client = cls.os_system_admin.dns_v2.QuotasClient()
+        else:
+            cls.admin_client = cls.os_admin.dns_v2.QuotasClient()
         cls.quotas_client = cls.os_primary.dns_v2.QuotasClient()
-        cls.admin_client = cls.os_admin.dns_v2.QuotasClient()
         cls.alt_client = cls.os_alt.dns_v2.QuotasClient()
+        cls.alt_zone_client = cls.os_alt.dns_v2.ZonesClient()
 
-    def _store_quotas(self, project_id=None, cleanup=True):
+    def _store_quotas(self, project_id, cleanup=True):
         """Remember current quotas and reset them after the test"""
-        params = {}
-        if project_id:
-            params['project_id'] = project_id
-            params['headers'] = {'X-Auth-All-Projects': True}
+        params = {'project_id': project_id,
+                  'headers': self.all_projects_header}
 
         _r, original_quotas = self.admin_client.show_quotas(**params)
         params.update(original_quotas)
@@ -67,33 +68,45 @@
 
     @decorators.idempotent_id('1dac991a-9e2e-452c-a47a-26ac37381ec5')
     def test_show_quotas(self):
-        self._store_quotas()
+        self._store_quotas(project_id=self.quotas_client.project_id)
         LOG.info("Updating quotas")
         quotas = dns_data_utils.rand_quotas()
-        _, body = self.admin_client.update_quotas(**quotas)
-        self.addCleanup(self.admin_client.delete_quotas)
+        _, body = self.admin_client.update_quotas(
+            project_id=self.quotas_client.project_id,
+            headers=self.all_projects_header,
+            **quotas)
 
         LOG.info("Fetching quotas")
-        _, body = self.admin_client.show_quotas()
+        _, body = self.admin_client.show_quotas(
+            project_id=self.quotas_client.project_id,
+            headers=self.all_projects_header)
 
         LOG.info("Ensuring the response has all quota types")
         self.assertExpected(quotas, body, [])
 
     @decorators.idempotent_id('0448b089-5803-4ce3-8a6c-5c15ff75a2cc')
     def test_delete_quotas(self):
-        self._store_quotas()
+        self._store_quotas(project_id=self.quotas_client.project_id)
         LOG.info("Deleting quotas")
-        _, body = self.admin_client.delete_quotas()
+        _, body = self.admin_client.delete_quotas(
+            project_id=self.quotas_client.project_id,
+            headers=self.all_projects_header)
 
         LOG.info("Ensuring an empty response body")
         self.assertEqual(body.strip(), b"")
 
     @decorators.idempotent_id('76d24c87-1b39-4e19-947c-c08e1380dc61')
     def test_update_quotas(self):
-        self._store_quotas()
+        if CONF.enforce_scope.designate:
+            raise self.skipException(
+                "System scoped tokens do not have a project_id.")
+
+        self._store_quotas(project_id=self.admin_client.project_id)
         LOG.info("Updating quotas")
         quotas = dns_data_utils.rand_quotas()
-        _, body = self.admin_client.update_quotas(**quotas)
+        _, body = self.admin_client.update_quotas(
+            project_id=self.admin_client.project_id,
+            **quotas)
 
         LOG.info("Ensuring the response has all quota types")
         self.assertExpected(quotas, body, [])
@@ -101,21 +114,22 @@
     @decorators.idempotent_id('9b09b3e2-7e88-4569-bce3-9be2f7ac70c3')
     def test_update_quotas_other_project(self):
 
-        project_id = self.quotas_client.tenant_id
+        project_id = self.quotas_client.project_id
         self._store_quotas(project_id=project_id)
 
         LOG.info("Updating quotas for %s ", project_id)
 
         quotas = dns_data_utils.rand_quotas()
         request = quotas.copy()
-        request['project_id'] = project_id
-        request['headers'] = {'X-Auth-All-Projects': True}
-        _, body = self.admin_client.update_quotas(**request)
+        _, body = self.admin_client.update_quotas(
+            project_id=project_id,
+            headers=self.all_projects_header,
+            **request)
 
         LOG.info("Ensuring the response has all quota types")
         self.assertExpected(quotas, body, [])
 
-        _, client_body = self.quotas_client.show_quotas()
+        _, client_body = self.quotas_client.show_quotas(project_id=project_id)
 
         self.assertExpected(quotas, client_body, [])
 
@@ -129,24 +143,28 @@
         LOG.info("Resetting quotas to default for %s ", project_id)
         self.admin_client.delete_quotas(
             project_id=project_id,
-            headers={'X-Auth-All-Projects': True})
+            headers=self.all_projects_header)
+
         _, default_quotas = self.admin_client.show_quotas(
-            project_id=project_id, headers={'X-Auth-All-Projects': True})
+            project_id=project_id,
+            headers=self.all_projects_header)
 
         LOG.info("Updating quotas for %s ", project_id)
 
         quotas = dns_data_utils.rand_quotas()
         request = quotas.copy()
-        request['project_id'] = project_id
-        request['headers'] = {'X-Auth-All-Projects': True}
-        _, body = self.admin_client.update_quotas(**request)
+        _, body = self.admin_client.update_quotas(
+            project_id=project_id,
+            headers=self.all_projects_header,
+            **request)
 
         self.admin_client.delete_quotas(
             project_id=project_id,
-            headers={'X-Auth-All-Projects': True})
+            headers=self.all_projects_header)
 
         _, final_quotas = self.admin_client.show_quotas(
-            project_id=project_id, headers={'X-Auth-All-Projects': True})
+            project_id=project_id,
+            headers=self.all_projects_header)
 
         self.assertExpected(default_quotas, final_quotas, [])
 
@@ -156,20 +174,87 @@
         if not CONF.dns_feature_enabled.api_v2_quotas_verify_project:
             raise self.skipException("Project ID in quotas "
                                      "is not being verified.")
-
+        original_quotas = self.quotas_client.show_quotas(
+            project_id=self.quotas_client.project_id)[1]
         project_id = 'project-that-does-not-exist'
-        original_quotas = self._store_quotas(project_id=project_id,
-                                             cleanup=False)
 
         LOG.info("Updating quotas for non-existing %s ", project_id)
-
         quotas = dns_data_utils.rand_quotas()
         request = quotas.copy()
-        request['project_id'] = project_id
-        request['headers'] = {'X-Auth-All-Projects': True}
         with self.assertRaisesDns(lib_exc.BadRequest, 'invalid_project', 400):
-            self.admin_client.update_quotas(**request)
+            self.admin_client.update_quotas(
+                project_id=project_id,
+                headers=self.all_projects_header,
+                **request)
 
-        _, client_body = self.quotas_client.show_quotas()
-
+        LOG.info("Make sure that the quotas weren't changed")
+        _, client_body = self.quotas_client.show_quotas(
+            project_id=self.quotas_client.project_id)
         self.assertExpected(original_quotas, client_body, [])
+
+    @decorators.idempotent_id('ae82a0ba-da60-11eb-bf12-74e5f9e2a801')
+    def test_admin_sets_quota_for_a_project(self):
+
+        primary_project_id = self.quotas_client.project_id
+        http_headers_to_use = [
+            {'X-Auth-All-Projects': True},
+            {'x-auth-sudo-project-id': primary_project_id}]
+
+        for http_header in http_headers_to_use:
+            LOG.info('As Admin user set Zones quota for a Primary user and {} '
+                     'HTTP header'.format(http_header))
+            quotas = dns_data_utils.rand_quotas()
+            self.admin_client.set_quotas(
+                project_id=primary_project_id,
+                quotas=quotas, headers=http_header)
+            self.addCleanup(self.admin_client.delete_quotas,
+                            project_id=primary_project_id)
+
+            LOG.info("As Admin fetch the quotas for a Primary user")
+            body = self.admin_client.show_quotas(
+                project_id=primary_project_id, headers=http_header)[1]
+            LOG.info('Ensuring that the "set" and "shown" quotas are same')
+            self.assertExpected(quotas, body, [])
+
+    @decorators.idempotent_id('40b9d7ac-da5f-11eb-bf12-74e5f9e2a801')
+    def test_primary_fails_to_set_quota(self):
+
+        primary_project_id = self.quotas_client.project_id
+        LOG.info('Try to set quota as Primary user')
+        self.assertRaises(
+            lib_exc.Forbidden, self.quotas_client.set_quotas,
+            project_id=primary_project_id,
+            quotas=dns_data_utils.rand_quotas())
+
+        LOG.info('Try to set quota as Primary user using '
+                 '"x-auth-sudo-project-id" HTTP header')
+        self.assertRaises(
+            lib_exc.Forbidden, self.quotas_client.set_quotas,
+            project_id=self.quotas_client.project_id,
+            quotas=dns_data_utils.rand_quotas(),
+            headers={'x-auth-sudo-project-id': primary_project_id})
+
+        LOG.info('Try to set quota as Primary user using '
+                 '"x-auth-all-projects" HTTP header')
+        self.assertRaises(
+            lib_exc.Forbidden, self.quotas_client.set_quotas,
+            project_id=self.quotas_client.project_id,
+            quotas=dns_data_utils.rand_quotas(),
+            headers={'x-auth-all-projects': True})
+
+    @decorators.idempotent_id('a6ce5b46-dcce-11eb-903e-74e5f9e2a801')
+    @decorators.skip_because(bug="1934596")
+    def test_admin_sets_invalid_quota_values(self):
+
+        primary_project_id = self.quotas_client.project_id
+        http_header = {'X-Auth-All-Projects': True}
+
+        for item in ['zones', 'zone_records',
+                     'zone_recordsets', 'recordset_records']:
+            quota = dns_data_utils.rand_quotas()
+            quota[item] = tempest_data_utils.rand_name()
+            self.assertRaises(
+                lib_exc.BadRequest, self.admin_client.set_quotas,
+                project_id=primary_project_id,
+                quotas=quota,
+                headers=http_header)
diff --git a/designate_tempest_plugin/tests/api/v2/test_recordset.py b/designate_tempest_plugin/tests/api/v2/test_recordset.py
index e3882e9..38a2dfd 100644
--- a/designate_tempest_plugin/tests/api/v2/test_recordset.py
+++ b/designate_tempest_plugin/tests/api/v2/test_recordset.py
@@ -19,12 +19,13 @@
 import ddt
 
 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
 
-LOG = logging.getLogger(__name__)
-
 CONF = config.CONF
+LOG = logging.getLogger(__name__)
 
 
 class BaseRecordsetsTest(base.BaseDnsV2Test):
@@ -50,7 +51,7 @@
 @ddt.ddt
 class RecordsetsTest(BaseRecordsetsTest):
 
-    credentials = ["admin", 'primary', 'alt']
+    credentials = ["admin", "system_admin", "primary", "alt"]
 
     @classmethod
     def setup_credentials(cls):
@@ -61,12 +62,16 @@
     @classmethod
     def setup_clients(cls):
         super(RecordsetsTest, cls).setup_clients()
+        if CONF.enforce_scope.designate:
+            cls.admin_client = cls.os_system_admin.dns_v2.RecordsetClient()
+            cls.admin_zone_client = cls.os_system_admin.dns_v2.ZonesClient()
+        else:
+            cls.admin_client = cls.os_admin.dns_v2.RecordsetClient()
+            cls.admin_zone_client = cls.os_admin.dns_v2.ZonesClient()
         cls.client = cls.os_primary.dns_v2.RecordsetClient()
         cls.alt_client = cls.os_alt.dns_v2.RecordsetClient()
-        cls.admin_client = cls.os_admin.dns_v2.RecordsetClient()
         cls.zone_client = cls.os_primary.dns_v2.ZonesClient()
         cls.alt_zone_client = cls.os_alt.dns_v2.ZonesClient()
-        cls.admin_zone_client = cls.os_admin.dns_v2.ZonesClient()
 
     @decorators.attr(type='smoke')
     @decorators.idempotent_id('631d74fd-6909-4684-a61b-5c4d2f92c3e7')
@@ -77,9 +82,12 @@
         LOG.info('Create a Recordset')
         resp, body = self.client.create_recordset(
             self.zone['id'], recordset_data)
+        self.addCleanup(
+            self.wait_recordset_delete, self.client,
+            self.zone['id'], body['id'])
 
         LOG.info('Ensure we respond with PENDING')
-        self.assertEqual('PENDING', body['status'])
+        self.assertEqual(const.PENDING, body['status'])
 
     # We cannot use DDT here as these tests are part of the refstack
     # interoperability test suite and need to be unique for traceability.
@@ -99,9 +107,12 @@
         LOG.info('Create a Recordset')
         resp, body = self.client.create_recordset(
             self.zone['id'], recordset_data)
+        self.addCleanup(
+            self.wait_recordset_delete, self.client,
+            self.zone['id'], body['id'])
 
         LOG.info('Ensure we respond with PENDING')
-        self.assertEqual('PENDING', body['status'])
+        self.assertEqual(const.PENDING, body['status'])
 
     @decorators.idempotent_id('d03b69a5-5052-43bc-a38a-b511b6b34304')
     def test_create_recordset_type_A(self):
@@ -170,9 +181,12 @@
         LOG.info('Create a Recordset')
         resp, body = self.client.create_recordset(
             self.zone['id'], recordset_data)
+        self.addCleanup(
+            self.wait_recordset_delete, self.client,
+            self.zone['id'], body['id'])
 
         LOG.info('Ensure we respond with PENDING')
-        self.assertEqual('PENDING', body['status'])
+        self.assertEqual(const.PENDING, body['status'])
 
     @decorators.idempotent_id('5964f730-5546-46e6-9105-5030e9c492b2')
     def test_list_recordsets(self):
@@ -182,6 +196,9 @@
         LOG.info('Create a Recordset')
         resp, body = self.client.create_recordset(
             self.zone['id'], recordset_data)
+        self.addCleanup(
+            self.wait_recordset_delete, self.client,
+            self.zone['id'], body['id'])
 
         LOG.info('List zone recordsets')
         _, body = self.client.list_recordset(self.zone['id'])
@@ -196,6 +213,9 @@
         LOG.info('Create a Recordset')
         resp, body = self.client.create_recordset(
             self.zone['id'], recordset_data)
+        self.addCleanup(
+            self.wait_recordset_delete, self.client,
+            self.zone['id'], body['id'])
 
         LOG.info('Re-Fetch the Recordset')
         _, record = self.client.show_recordset(self.zone['id'], body['id'])
@@ -211,6 +231,9 @@
         LOG.info('Create a Recordset')
         _, record = self.client.create_recordset(
             self.zone['id'], recordset_data)
+        self.addCleanup(
+            self.wait_recordset_delete, self.client,
+            self.zone['id'], record['id'])
 
         LOG.info('Delete a Recordset')
         _, body = self.client.delete_recordset(self.zone['id'], record['id'])
@@ -227,6 +250,9 @@
         LOG.info('Create a recordset')
         _, record = self.client.create_recordset(
             self.zone['id'], recordset_data)
+        self.addCleanup(
+            self.wait_recordset_delete, self.client,
+            self.zone['id'], record['id'])
 
         recordset_data = data_utils.rand_recordset_data(
             record_type='A', zone_name=self.zone['name'], name=record['name'])
@@ -246,6 +272,9 @@
         LOG.info('Create a recordset')
         _, record = self.client.create_recordset(
             self.zone['id'], recordset_data)
+        self.addCleanup(
+            self.wait_recordset_delete, self.client,
+            self.zone['id'], record['id'])
 
         recordset_data = {
             'ttl': data_utils.rand_ttl(start=record['ttl'] + 1)
@@ -268,12 +297,15 @@
             record_type='A', zone_name=self.zone['name'])
         resp, body = self.client.create_recordset(
             self.zone['id'], recordset_data)
-        self.assertEqual('PENDING', body['status'],
+        self.addCleanup(
+            self.wait_recordset_delete, self.client,
+            self.zone['id'], body['id'])
+        self.assertEqual(const.PENDING, body['status'],
                          'Failed, expected status is PENDING')
         LOG.info('Wait until the recordset is active')
         waiters.wait_for_recordset_status(
             self.client, self.zone['id'],
-            body['id'], 'ACTIVE')
+            body['id'], const.ACTIVE)
 
         LOG.info('Re-Fetch the Recordset as Alt tenant with '
                  '"x-auth-sudo-project-id" HTTP header included in request. '
@@ -305,13 +337,19 @@
             record_type='A', zone_name=self.zone['name'])
         body_pr_1 = self.client.create_recordset(
             self.zone['id'], recordset_data_primary_1)[1]
-        self.assertEqual('PENDING', body_pr_1['status'],
+        self.addCleanup(
+            self.wait_recordset_delete, self.client,
+            self.zone['id'], body_pr_1['id'])
+        self.assertEqual(const.PENDING, body_pr_1['status'],
                          'Failed, expected status is PENDING')
         recordset_data_primary_2 = data_utils.rand_recordset_data(
             record_type='A', zone_name=self.zone['name'])
         body_pr_2 = self.client.create_recordset(
             self.zone['id'], recordset_data_primary_2)[1]
-        self.assertEqual('PENDING', body_pr_2['status'],
+        self.addCleanup(
+            self.wait_recordset_delete, self.client,
+            self.zone['id'], body_pr_2['id'])
+        self.assertEqual(const.PENDING, body_pr_2['status'],
                          'Failed, expected status is PENDING')
 
         LOG.info('Re-Fetch Recordsets as Alt tenant for a Primary project. '
@@ -325,7 +363,7 @@
         self.assertRaises(lib_exc.Forbidden,
             lambda: self.alt_client.list_recordset(
                 self.zone['id'],
-                headers={'x-auth-all-projects': True}))
+                headers=self.all_projects_header))
 
         LOG.info('Re-Fetch Recordsets as Admin tenant for a Primary project '
                  'using "x-auth-all-projects" HTTP header.')
@@ -335,7 +373,7 @@
         primary_recordsets_ids = [
             item['id'] for item in self.admin_client.list_recordset(
                 self.zone['id'],
-                headers={'x-auth-all-projects': True},
+                headers=self.all_projects_header,
                 params={'limit': 1000})[1]['recordsets']]
 
         for recordset_id in [body_pr_1['id'], body_pr_2['id']]:
@@ -344,11 +382,29 @@
                 'Failed, recordset ID:{} was not found in listed '
                 'recordsets: {}'.format(recordset_id, primary_recordsets_ids))
 
+    @decorators.idempotent_id('48013b7c-f526-11eb-b04f-74e5f9e2a801')
+    def test_create_A_recordset_multiply_ips(self):
+        LOG.info('Create A type Recordset using a list of random IPs')
+        recordset_data = data_utils.rand_a_recordset(
+            zone_name=self.zone['name'],
+            ips=[data_utils.rand_ip() for _ in range(10)])
+        resp, body = self.client.create_recordset(
+            self.zone['id'], recordset_data)
+        self.addCleanup(
+            self.wait_recordset_delete, self.client,
+            self.zone['id'], body['id'])
+        LOG.info('Ensure we respond with PENDING')
+        self.assertEqual(const.PENDING, body['status'])
+        LOG.info('Wait until the recordset is active')
+        waiters.wait_for_recordset_status(
+            self.client, self.zone['id'],
+            body['id'], const.ACTIVE)
+
 
 @ddt.ddt
 class RecordsetsNegativeTest(BaseRecordsetsTest):
 
-    credentials = ['primary', 'alt']
+    credentials = ["primary", "alt"]
 
     @classmethod
     def setup_credentials(cls):
@@ -461,12 +517,15 @@
             record_type='A', zone_name=self.zone['name'])
         resp, body = self.client.create_recordset(
             self.zone['id'], recordset_data)
-        self.assertEqual('PENDING', body['status'],
+        self.addCleanup(
+            self.wait_recordset_delete, self.client,
+            self.zone['id'], body['id'])
+        self.assertEqual(const.PENDING, body['status'],
                          'Failed, expected status is PENDING')
         LOG.info('Wait until the recordset is active')
         waiters.wait_for_recordset_status(
             self.client, self.zone['id'],
-            body['id'], 'ACTIVE')
+            body['id'], const.ACTIVE)
 
         LOG.info('Ensure 404 NotFound status code is received if '
                  'recordset ID is invalid.')
@@ -531,6 +590,9 @@
         LOG.info('Create a Recordset')
         resp, zone_recordset = self.client.create_recordset(
             self.zone['id'], recordset_data)
+        self.addCleanup(
+            self.wait_recordset_delete, self.client,
+            self.zone['id'], zone_recordset['id'])
 
         self.client.show_zones_recordset(zone_recordset['id'])
 
@@ -542,6 +604,9 @@
         LOG.info('Create a Recordset')
         resp, zone_recordset = self.client.create_recordset(
             self.zone['id'], recordset_data)
+        self.addCleanup(
+            self.wait_recordset_delete, self.client,
+            self.zone['id'], zone_recordset['id'])
 
         LOG.info('Create another zone')
         _, zone2 = self.zone_client.create_zone()
@@ -553,6 +618,9 @@
             records=['10.0.1.3'])
         resp, zone_recordset2 = self.client.create_recordset(
             zone2['id'], recordset_data)
+        self.addCleanup(
+            self.wait_recordset_delete, self.client,
+            self.zone['id'], zone_recordset2['id'])
 
         LOG.info('List recordsets')
         _, body = self.client.list_zones_recordsets(params={"data": "10.0.*"})
@@ -589,7 +657,7 @@
 
 class RecordsetOwnershipTest(BaseRecordsetsTest):
 
-    credentials = ['primary', 'alt', 'admin']
+    credentials = ["primary", "alt", "admin", "system_admin"]
 
     @classmethod
     def setup_credentials(cls):
@@ -600,9 +668,12 @@
     @classmethod
     def setup_clients(cls):
         super(RecordsetOwnershipTest, cls).setup_clients()
+        if CONF.enforce_scope.designate:
+            cls.admin_client = cls.os_system_admin.dns_v2.RecordsetClient()
+        else:
+            cls.admin_client = cls.os_admin.dns_v2.RecordsetClient()
         cls.client = cls.os_primary.dns_v2.RecordsetClient()
         cls.alt_client = cls.os_alt.dns_v2.RecordsetClient()
-        cls.admin_client = cls.os_admin.dns_v2.RecordsetClient()
         cls.zone_client = cls.os_primary.dns_v2.ZonesClient()
         cls.alt_zone_client = cls.os_alt.dns_v2.ZonesClient()
 
@@ -620,19 +691,22 @@
                                 self.zone_client,
                                 zone['id'])
                 waiters.wait_for_zone_status(
-                    self.zone_client, zone['id'], 'ACTIVE')
+                    self.zone_client, zone['id'], const.ACTIVE)
 
                 # Create a recordset and wait till it's ACTIVE
                 recordset_data = data_utils.rand_recordset_data(
                     record_type='A', zone_name=zone['name'])
                 resp, body = self.client.create_recordset(
                     zone['id'], recordset_data)
-                self.assertEqual('PENDING', body['status'],
+                self.addCleanup(
+                    self.wait_recordset_delete, self.client,
+                    self.zone['id'], body['id'])
+                self.assertEqual(const.PENDING, body['status'],
                                  'Failed, expected status is PENDING')
                 LOG.info('Wait until the recordset is active')
                 waiters.wait_for_recordset_status(
                     self.client, zone['id'],
-                    body['id'], 'ACTIVE')
+                    body['id'], const.ACTIVE)
 
                 # Add "project_id" into the recordset_data
                 recordset_data['project_id'] = zone['project_id']
@@ -645,19 +719,22 @@
                                 self.alt_zone_client,
                                 alt_zone['id'])
                 waiters.wait_for_zone_status(
-                    self.alt_zone_client, alt_zone['id'], 'ACTIVE')
+                    self.alt_zone_client, alt_zone['id'], const.ACTIVE)
 
                 # Create a recordset and wait till it's ACTIVE
                 recordset_data = data_utils.rand_recordset_data(
                     record_type='A', zone_name=alt_zone['name'])
                 resp, body = self.alt_client.create_recordset(
                     alt_zone['id'], recordset_data)
-                self.assertEqual('PENDING', body['status'],
+                self.addCleanup(
+                    self.wait_recordset_delete, self.client,
+                    self.zone['id'], body['id'])
+                self.assertEqual(const.PENDING, body['status'],
                                  'Failed, expected status is PENDING')
                 LOG.info('Wait until the recordset is active')
                 waiters.wait_for_recordset_status(
                     self.alt_client, alt_zone['id'],
-                    body['id'], 'ACTIVE')
+                    body['id'], const.ACTIVE)
 
                 # Add "project_id" into the recordset_data
                 recordset_data['project_id'] = alt_zone['project_id']
@@ -672,6 +749,9 @@
             record_type='A', zone_name=self.zone['name'])
         resp, rrset = self.client.create_recordset(
             self.zone['id'], recordset_data)
+        self.addCleanup(
+            self.wait_recordset_delete, self.client,
+            self.zone['id'], rrset['id'])
         self.assertRaises(
             lib_exc.RestClientException,
             lambda: self.alt_client.create_recordset(
@@ -755,7 +835,7 @@
         #       in parallel will impact the list result set. Since the default
         #       pagination limit is only 20, we set a param limit of 1000 here.
         recordsets = self.admin_client.list_owned_recordsets(
-            headers={'x-auth-all-projects': True}, params={'limit': 1000})
+            headers=self.all_projects_header, params={'limit': 1000})
         LOG.info('Received by API recordsets are {} '.format(recordsets))
         project_ids_api = set([item['project_id'] for item in recordsets])
         for prj_id in project_ids_used:
diff --git a/designate_tempest_plugin/tests/api/v2/test_service_statuses.py b/designate_tempest_plugin/tests/api/v2/test_service_statuses.py
index 2f0a9bb..0deeb74 100644
--- a/designate_tempest_plugin/tests/api/v2/test_service_statuses.py
+++ b/designate_tempest_plugin/tests/api/v2/test_service_statuses.py
@@ -15,18 +15,18 @@
 from designate_tempest_plugin.common import constants as const
 from tempest import config
 from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
+
 
 from designate_tempest_plugin.tests import base
 
-LOG = logging.getLogger(__name__)
-
-
 CONF = config.CONF
+LOG = logging.getLogger(__name__)
 
 
 class ServiceStatus(base.BaseDnsV2Test):
 
-    credentials = ['primary', 'admin']
+    credentials = ["primary", "admin", "system_admin", "alt"]
 
     @classmethod
     def setup_credentials(cls):
@@ -37,12 +37,17 @@
     @classmethod
     def setup_clients(cls):
         super(ServiceStatus, cls).setup_clients()
-
+        if CONF.enforce_scope.designate:
+            cls.admin_client = cls.os_system_admin.dns_v2.ServiceClient()
+        else:
+            cls.admin_client = cls.os_admin.dns_v2.ServiceClient()
         cls.client = cls.os_primary.dns_v2.ServiceClient()
-        cls.admin_client = cls.os_admin.dns_v2.ServiceClient()
+
+        cls.primary_client = cls.os_primary.dns_v2.ServiceClient()
+        cls.alt_client = cls.os_alt.dns_v2.ServiceClient()
 
     @decorators.idempotent_id('bf277a76-8583-11eb-a557-74e5f9e2a801')
-    def test_list_service_statuses(self):
+    def test_admin_list_service_statuses(self):
 
         services_statuses_tup = [
             (item['service_name'],
@@ -64,3 +69,19 @@
             {const.UP}, set([item[1] for item in services_statuses_tup]),
             "Failed, not all listed services are in UP status, "
             "services: {}".format(services_statuses_tup))
+
+    @decorators.idempotent_id('d4753f76-de43-11eb-91d1-74e5f9e2a801')
+    def test_primary_is_forbidden_to_list_service_statuses(self):
+
+        LOG.info('Try to "list service statuses" as Primary user')
+        self.assertRaises(
+            lib_exc.Forbidden, self.primary_client.list_statuses)
+
+        headers = [{'x-auth-all-projects': True},
+                   {'x-auth-sudo-project-id': self.alt_client.project_id}]
+        for header in headers:
+            LOG.info('Try to "list service statuses" using {} '
+                     'HTTP header'.format(header))
+            self.assertRaises(
+                lib_exc.Forbidden, self.primary_client.list_statuses,
+                headers=header)
diff --git a/designate_tempest_plugin/tests/api/v2/test_tld.py b/designate_tempest_plugin/tests/api/v2/test_tld.py
index ce8a04f..831c13c 100644
--- a/designate_tempest_plugin/tests/api/v2/test_tld.py
+++ b/designate_tempest_plugin/tests/api/v2/test_tld.py
@@ -13,12 +13,14 @@
 #    under the License.
 
 from oslo_log import log as logging
+from tempest import config
 from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest.lib.common.utils import data_utils
 
 from designate_tempest_plugin.tests import base
 
+CONF = config.CONF
 LOG = logging.getLogger(__name__)
 
 
@@ -27,7 +29,7 @@
 
 
 class TldAdminTest(BaseTldTest):
-    credentials = ['admin']
+    credentials = ["admin", "system_admin", "primary"]
 
     @classmethod
     def setup_credentials(cls):
@@ -38,7 +40,12 @@
     @classmethod
     def setup_clients(cls):
         super(TldAdminTest, cls).setup_clients()
-        cls.admin_client = cls.os_admin.dns_v2.TldClient()
+        if CONF.enforce_scope.designate:
+            cls.admin_client = cls.os_system_admin.dns_v2.TldClient()
+        else:
+            cls.admin_client = cls.os_admin.dns_v2.TldClient()
+        cls.primary_client = cls.os_primary.dns_v2.TldClient()
+        cls.primary_zone_client = cls.os_primary.dns_v2.ZonesClient()
 
     @classmethod
     def resource_setup(cls):
@@ -65,6 +72,74 @@
 
         self.assertEqual(tld_data["name"], tld['name'])
 
+    @decorators.idempotent_id('961bd2e8-d4d0-11eb-b8ee-74e5f9e2a801')
+    def test_create_duplicated_tlds(self):
+        tld_data = {
+            "name": "org", "description": "test_create_duplicated_tlds"}
+
+        LOG.info('Create a first "org" TLD')
+        tld = self.admin_client.create_tld(
+            tld_data['name'], tld_data['description'])[1]
+        self.addCleanup(self.admin_client.delete_tld, tld['id'])
+        self.assertEqual(tld_data["name"], tld['name'])
+
+        LOG.info('Try to create a second "org" TLD')
+        self.assertRaises(
+            lib_exc.Conflict, self.admin_client.create_tld,
+            tld_name=tld_data['name'],
+            description=tld_data['description'])
+
+    @decorators.idempotent_id('0c0ab92e-d4db-11eb-b8ee-74e5f9e2a801')
+    def test_create_multiply_tlds(self):
+        tlds = ['abc', 'def', 'gih']
+        for tld_name in tlds:
+            tld_data = {
+                "name": tld_name, "description": "test_create_multiply_tlds"}
+            LOG.info('Create a "{}" TLD'.format(tld_name))
+            tld = self.admin_client.create_tld(
+                tld_data['name'], tld_data['description'])[1]
+            self.addCleanup(self.admin_client.delete_tld, tld['id'])
+            self.assertEqual(tld_data["name"], tld['name'])
+
+    @decorators.idempotent_id('52a4bb4b-4eff-4591-9dd3-ad98316806c3')
+    def test_create_invalid_tld(self):
+        invalid_tlds = ['   ', 'fff.', '^&$', 't' * 1000, '@p%']
+        for tld_name in invalid_tlds:
+            tld_data = {
+                "name": tld_name, "description": "test_create_invalid_tld"}
+            LOG.info('Create a "{}" TLD'.format(tld_name))
+            self.assertRaises(
+                lib_exc.BadRequest, self.admin_client.create_tld,
+                tld_name=tld_data['name'], description=tld_data['description'])
+        LOG.info('Create a "{}" TLD with huge size description.')
+        self.assertRaises(
+            lib_exc.BadRequest, self.admin_client.create_tld,
+            tld_name='org', description='test_create_invalid_tld' * 1000)
+
+    @decorators.idempotent_id('06deced8-d4de-11eb-b8ee-74e5f9e2a801')
+    def test_create_zone_for_not_existing_tld(self):
+        LOG.info('Create an "org" TLD')
+        tld_data = {"name": "org",
+                    "description": "test_create_zone_for_not_existing_tld"}
+        tld = self.admin_client.create_tld(
+            tld_data['name'], tld_data['description'])[1]
+        self.addCleanup(self.admin_client.delete_tld, tld['id'])
+        self.assertEqual(tld_data["name"], tld['name'])
+
+        LOG.info('Try to create a Primary zone with "zzz" (not existing) TLD.')
+        self.assertRaises(
+            lib_exc.BadRequest, self.primary_zone_client.create_zone,
+            name='example.zzz.')
+
+    @decorators.idempotent_id('757019c0-d4e2-11eb-b8ee-74e5f9e2a801')
+    def test_create_tld_as_primary_user(self):
+        tld_data = {
+            "name": "org", "description": "test_create_tld_as_primary_user"}
+        LOG.info('Try to create a TLD as primary user.')
+        self.assertRaises(
+            lib_exc.Forbidden, self.primary_client.create_tld,
+            tld_name=tld_data['name'], description=tld_data['description'])
+
     @decorators.idempotent_id('271af08c-2603-4f61-8eb1-05887b74e25a')
     def test_show_tld(self):
         tld_data = {
@@ -129,7 +204,7 @@
 
 class TestTldNotFoundAdmin(BaseTldTest):
 
-    credentials = ["admin"]
+    credentials = ["admin", "system_admin"]
 
     @classmethod
     def setup_credentials(cls):
@@ -140,7 +215,10 @@
     @classmethod
     def setup_clients(cls):
         super(TestTldNotFoundAdmin, cls).setup_clients()
-        cls.admin_client = cls.os_admin.dns_v2.TldClient()
+        if CONF.enforce_scope.designate:
+            cls.admin_client = cls.os_system_admin.dns_v2.TldClient()
+        else:
+            cls.admin_client = cls.os_admin.dns_v2.TldClient()
 
     @decorators.idempotent_id('b237d5ee-0d76-4294-a3b6-c2f8bf4b0e30')
     def test_show_tld_404(self):
@@ -172,7 +250,7 @@
 
 class TestTldInvalidIdAdmin(BaseTldTest):
 
-    credentials = ["admin"]
+    credentials = ["admin", "system_admin"]
 
     @classmethod
     def setup_credentials(cls):
@@ -183,7 +261,10 @@
     @classmethod
     def setup_clients(cls):
         super(TestTldInvalidIdAdmin, cls).setup_clients()
-        cls.admin_client = cls.os_admin.dns_v2.TldClient()
+        if CONF.enforce_scope.designate:
+            cls.admin_client = cls.os_system_admin.dns_v2.TldClient()
+        else:
+            cls.admin_client = cls.os_admin.dns_v2.TldClient()
 
     @decorators.idempotent_id('f9ec0730-57ff-4720-8d06-e11d377c7cfc')
     def test_show_tld_invalid_uuid(self):
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 b4ab5c8..616431c 100644
--- a/designate_tempest_plugin/tests/api/v2/test_transfer_accepts.py
+++ b/designate_tempest_plugin/tests/api/v2/test_transfer_accepts.py
@@ -12,12 +12,14 @@
 #    License for the specific language governing permissions and limitations
 #    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
 
+CONF = config.CONF
 LOG = logging.getLogger(__name__)
 
 
@@ -27,7 +29,7 @@
 
 
 class TransferAcceptTest(BaseTransferAcceptTest):
-    credentials = ['primary', 'alt', 'admin']
+    credentials = ["primary", "alt", "admin", "system_admin"]
 
     @classmethod
     def setup_credentials(cls):
@@ -50,9 +52,18 @@
         cls.alt_accept_client = cls.os_alt.dns_v2.TransferAcceptClient()
 
         # Admin clients
-        cls.admin_zone_client = cls.os_admin.dns_v2.ZonesClient()
-        cls.admin_request_client = cls.os_admin.dns_v2.TransferRequestClient()
-        cls.admin_accept_client = cls.os_admin.dns_v2.TransferAcceptClient()
+        if CONF.enforce_scope.designate:
+            cls.admin_zone_client = cls.os_system_admin.dns_v2.ZonesClient()
+            cls.admin_request_client = (cls.os_system_admin.dns_v2.
+                                        TransferRequestClient())
+            cls.admin_accept_client = (cls.os_system_admin.dns_v2.
+                                       TransferAcceptClient())
+        else:
+            cls.admin_zone_client = cls.os_admin.dns_v2.ZonesClient()
+            cls.admin_request_client = (cls.os_admin.dns_v2.
+                                        TransferRequestClient())
+            cls.admin_accept_client = (cls.os_admin.dns_v2.
+                                       TransferAcceptClient())
 
     @decorators.idempotent_id('1c6baf97-a83e-4d2e-a5d8-9d37fb7808f3')
     def test_create_transfer_accept(self):
@@ -60,7 +71,7 @@
         _, zone = self.prm_zone_client.create_zone(wait_until='ACTIVE')
         self.addCleanup(
             self.wait_zone_delete, self.admin_zone_client, zone['id'],
-            headers={'x-auth-all-projects': True},
+            headers=self.all_projects_header,
             ignore_errors=lib_exc.NotFound)
 
         LOG.info('Create a zone transfer_request')
@@ -89,7 +100,7 @@
         _, zone = self.prm_zone_client.create_zone(wait_until='ACTIVE')
         self.addCleanup(
             self.wait_zone_delete, self.admin_zone_client, zone['id'],
-            headers={'x-auth-all-projects': True},
+            headers=self.all_projects_header,
             ignore_errors=lib_exc.NotFound)
 
         LOG.info('Create a zone transfer_request')
@@ -125,7 +136,7 @@
         zone = self.prm_zone_client.create_zone(wait_until='ACTIVE')[1]
         self.addCleanup(
             self.wait_zone_delete, self.admin_zone_client, zone['id'],
-            headers={'x-auth-all-projects': True},
+            headers=self.all_projects_header,
             ignore_errors=lib_exc.NotFound)
 
         LOG.info('Create a Primary zone transfer_request')
@@ -170,7 +181,7 @@
             zone = self.prm_zone_client.create_zone(wait_until='ACTIVE')[1]
             self.addCleanup(
                 self.wait_zone_delete, self.admin_zone_client, zone['id'],
-                headers={'x-auth-all-projects': True},
+                headers=self.all_projects_header,
                 ignore_errors=lib_exc.NotFound)
 
             LOG.info('Create a Primary zone transfer_request')
@@ -203,7 +214,7 @@
         admin_client_accept_ids = [
             item['id'] for item in
             self.admin_accept_client.list_transfer_accept(
-                headers={'x-auth-all-projects': True}, params={'limit': 1000})]
+                headers=self.all_projects_header, params={'limit': 1000})]
         for tr_id in transfer_request_ids:
             self.assertIn(
                 tr_id, admin_client_accept_ids,
@@ -217,7 +228,7 @@
         admin_client_accept_ids = [
             item['id'] for item in
             self.admin_accept_client.list_transfer_accept(
-                headers={'x-auth-all-projects': True},
+                headers=self.all_projects_header,
                 params={'status': 'COMPLETE'})]
         for tr_id in transfer_request_ids:
             self.assertIn(
@@ -234,7 +245,7 @@
         admin_client_accept_ids = [
             item['id'] for item in
             self.admin_accept_client.list_transfer_accept(
-                headers={'x-auth-all-projects': True},
+                headers=self.all_projects_header,
                 params={'status': not_existing_status})]
         self.assertEmpty(
             admin_client_accept_ids,
@@ -255,7 +266,7 @@
         # for a zone.
         self.addCleanup(
             self.wait_zone_delete, self.admin_zone_client, zone['id'],
-            headers={'x-auth-all-projects': True},
+            headers=self.all_projects_header,
             ignore_errors=lib_exc.NotFound)
 
         LOG.info('Create a zone transfer_request as primary tenant')
@@ -294,7 +305,7 @@
 
 class TransferAcceptTestNegative(BaseTransferAcceptTest):
 
-    credentials = ['primary', 'alt', 'admin']
+    credentials = ["primary", "alt", "admin", "system_admin"]
 
     @classmethod
     def setup_credentials(cls):
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 5878dc9..794fafa 100644
--- a/designate_tempest_plugin/tests/api/v2/test_transfer_request.py
+++ b/designate_tempest_plugin/tests/api/v2/test_transfer_request.py
@@ -12,6 +12,7 @@
 #    License for the specific language governing permissions and limitations
 #    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
@@ -19,6 +20,7 @@
 from designate_tempest_plugin.tests import base
 from designate_tempest_plugin import data_utils as dns_data_utils
 
+CONF = config.CONF
 LOG = logging.getLogger(__name__)
 
 
@@ -27,7 +29,7 @@
 
 
 class TransferRequestTest(BaseTransferRequestTest):
-    credentials = ['primary', 'alt', 'admin']
+    credentials = ["primary", "alt", "admin", "system_admin"]
 
     @classmethod
     def setup_credentials(cls):
@@ -39,11 +41,15 @@
     def setup_clients(cls):
         super(TransferRequestTest, cls).setup_clients()
 
+        if CONF.enforce_scope.designate:
+            cls.admin_client = (cls.os_system_admin.dns_v2.
+                                TransferRequestClient())
+        else:
+            cls.admin_client = cls.os_admin.dns_v2.TransferRequestClient()
         cls.zone_client = cls.os_primary.dns_v2.ZonesClient()
         cls.alt_zone_client = cls.os_alt.dns_v2.ZonesClient()
         cls.client = cls.os_primary.dns_v2.TransferRequestClient()
         cls.alt_client = cls.os_alt.dns_v2.TransferRequestClient()
-        cls.admin_client = cls.os_admin.dns_v2.TransferRequestClient()
 
     @decorators.idempotent_id('2381d489-ad84-403d-b0a2-8b77e4e966bf')
     def test_create_transfer_request(self):
@@ -233,7 +239,7 @@
         #       pagination limit is only 20, we set a param limit of 1000 here.
         request_ids = [
             item['id'] for item in self.admin_client.list_transfer_requests(
-                headers={'x-auth-all-projects': True},
+                headers=self.all_projects_header,
                 params={'limit': 1000})[1]['transfer_requests']]
 
         for request_id in [primary_transfer_request['id'],
diff --git a/designate_tempest_plugin/tests/api/v2/test_tsigkey.py b/designate_tempest_plugin/tests/api/v2/test_tsigkey.py
index 5cd9512..292b821 100644
--- a/designate_tempest_plugin/tests/api/v2/test_tsigkey.py
+++ b/designate_tempest_plugin/tests/api/v2/test_tsigkey.py
@@ -13,12 +13,14 @@
 #    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
 
+CONF = config.CONF
 LOG = logging.getLogger(__name__)
 
 
@@ -27,7 +29,7 @@
 
 
 class TsigkeyAdminTest(BaseTsigkeyTest):
-    credentials = ['primary', 'admin']
+    credentials = ["primary", "admin", "system_admin"]
 
     @classmethod
     def setup_credentials(cls):
@@ -38,8 +40,11 @@
     @classmethod
     def setup_clients(cls):
         super(TsigkeyAdminTest, cls).setup_clients()
+        if CONF.enforce_scope.designate:
+            cls.admin_client = cls.os_system_admin.dns_v2.TsigkeyClient()
+        else:
+            cls.admin_client = cls.os_admin.dns_v2.TsigkeyClient()
         cls.zone_client = cls.os_primary.dns_v2.ZonesClient()
-        cls.admin_client = cls.os_admin.dns_v2.TsigkeyClient()
 
     @decorators.idempotent_id('e7b484e3-7ed5-4840-89d7-1e696986f8e4')
     def test_create_tsigkey(self):
@@ -140,7 +145,7 @@
 
 class TestTsigkeyNotFoundAdmin(BaseTsigkeyTest):
 
-    credentials = ["admin"]
+    credentials = ["admin", "system_admin"]
 
     @classmethod
     def setup_credentials(cls):
@@ -151,7 +156,10 @@
     @classmethod
     def setup_clients(cls):
         super(TestTsigkeyNotFoundAdmin, cls).setup_clients()
-        cls.admin_client = cls.os_admin.dns_v2.TsigkeyClient()
+        if CONF.enforce_scope.designate:
+            cls.admin_client = cls.os_system_admin.dns_v2.TsigkeyClient()
+        else:
+            cls.admin_client = cls.os_admin.dns_v2.TsigkeyClient()
 
     @decorators.idempotent_id('824c9b49-edc5-4282-929e-467a158d23e4')
     def test_show_tsigkey_404(self):
@@ -183,7 +191,7 @@
 
 class TestTsigkeyInvalidIdAdmin(BaseTsigkeyTest):
 
-    credentials = ["admin"]
+    credentials = ["admin", "system_admin"]
 
     @classmethod
     def setup_credentials(cls):
@@ -194,7 +202,10 @@
     @classmethod
     def setup_clients(cls):
         super(TestTsigkeyInvalidIdAdmin, cls).setup_clients()
-        cls.admin_client = cls.os_admin.dns_v2.TsigkeyClient()
+        if CONF.enforce_scope.designate:
+            cls.admin_client = cls.os_system_admin.dns_v2.TsigkeyClient()
+        else:
+            cls.admin_client = cls.os_admin.dns_v2.TsigkeyClient()
 
     @decorators.idempotent_id('2a8dfc75-9884-4b1c-8f1f-ed835d96f2fe')
     def test_show_tsigkey_invalid_uuid(self):
diff --git a/designate_tempest_plugin/tests/api/v2/test_zone_tasks.py b/designate_tempest_plugin/tests/api/v2/test_zone_tasks.py
index cb2b4fa..bbeea75 100644
--- a/designate_tempest_plugin/tests/api/v2/test_zone_tasks.py
+++ b/designate_tempest_plugin/tests/api/v2/test_zone_tasks.py
@@ -16,6 +16,7 @@
 from unittest import expectedFailure
 
 from oslo_log import log as logging
+from tempest import config
 from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 
@@ -26,6 +27,7 @@
 from designate_tempest_plugin.services.dns.query.query_client \
     import SingleQueryClient
 
+CONF = config.CONF
 LOG = logging.getLogger(__name__)
 
 
@@ -35,7 +37,7 @@
 
 
 class ZoneTasks(BaseZonesTest):
-    credentials = ['primary', 'alt', 'admin']
+    credentials = ["primary", "alt", "admin", "system_admin"]
 
     @classmethod
     def setup_credentials(cls):
@@ -46,8 +48,11 @@
     @classmethod
     def setup_clients(cls):
         super(ZoneTasks, cls).setup_clients()
+        if CONF.enforce_scope.designate:
+            cls.admin_client = cls.os_system_admin.dns_v2.ZonesClient()
+        else:
+            cls.admin_client = cls.os_admin.dns_v2.ZonesClient()
         cls.client = cls.os_primary.dns_v2.ZonesClient()
-        cls.admin_client = cls.os_admin.dns_v2.ZonesClient()
         cls.alt_client = cls.os_alt.dns_v2.ZonesClient()
 
     @decorators.idempotent_id('287e2cd0-a0e7-11eb-b962-74e5f9e2a801')
@@ -105,7 +110,7 @@
 
 
 class ZoneTasksNegative(BaseZonesTest):
-    credentials = ['primary', 'alt', 'admin']
+    credentials = ["primary", "alt", "admin", "system_admin"]
 
     @classmethod
     def setup_credentials(cls):
@@ -116,8 +121,11 @@
     @classmethod
     def setup_clients(cls):
         super(ZoneTasksNegative, cls).setup_clients()
+        if CONF.enforce_scope.designate:
+            cls.admin_client = cls.os_system_admin.dns_v2.ZonesClient()
+        else:
+            cls.admin_client = cls.os_admin.dns_v2.ZonesClient()
         cls.client = cls.os_primary.dns_v2.ZonesClient()
-        cls.admin_client = cls.os_admin.dns_v2.ZonesClient()
         cls.alt_client = cls.os_alt.dns_v2.ZonesClient()
 
     def _query_nameserver(self, nameserver, query_timeout,
diff --git a/designate_tempest_plugin/tests/api/v2/test_zones.py b/designate_tempest_plugin/tests/api/v2/test_zones.py
index dfd0a57..dec5028 100644
--- a/designate_tempest_plugin/tests/api/v2/test_zones.py
+++ b/designate_tempest_plugin/tests/api/v2/test_zones.py
@@ -13,6 +13,7 @@
 # under the License.
 import uuid
 from oslo_log import log as logging
+from tempest import config
 from tempest.lib import decorators
 from tempest.lib.common.utils import data_utils
 from tempest.lib import exceptions as lib_exc
@@ -24,6 +25,8 @@
 from designate_tempest_plugin.tests import base
 
 from designate_tempest_plugin.common import waiters
+
+CONF = config.CONF
 LOG = logging.getLogger(__name__)
 
 
@@ -33,7 +36,7 @@
 
 
 class ZonesTest(BaseZonesTest):
-    credentials = ['admin', 'primary']
+    credentials = ["admin", "system_admin", "primary"]
 
     @classmethod
     def setup_credentials(cls):
@@ -44,8 +47,12 @@
     @classmethod
     def setup_clients(cls):
         super(ZonesTest, cls).setup_clients()
+        if CONF.enforce_scope.designate:
+            cls.pool_client = cls.os_system_admin.dns_v2.PoolClient()
+        else:
+            cls.pool_client = cls.os_admin.dns_v2.PoolClient()
         cls.client = cls.os_primary.dns_v2.ZonesClient()
-        cls.pool_client = cls.os_admin.dns_v2.PoolClient()
+        cls.recordset_client = cls.os_primary.dns_v2.RecordsetClient()
 
     @decorators.idempotent_id('9d2e20fc-e56f-4a62-9c61-9752a9ec615c')
     def test_create_zones(self):
@@ -72,6 +79,31 @@
         self.assertEqual('CREATE', zone['action'])
         self.assertEqual('PENDING', zone['status'])
 
+    @decorators.idempotent_id('ec150c22-f52e-11eb-b09b-74e5f9e2a801')
+    def test_create_zone_validate_recordsets_created(self):
+        # Create a PRIMARY zone and wait till it's Active
+        LOG.info('Create a PRIMARY zone')
+        zone = self.client.create_zone()[1]
+        self.addCleanup(self.wait_zone_delete, self.client, zone['id'])
+
+        LOG.info('Ensure we respond with CREATE+PENDING')
+        self.assertEqual('CREATE', zone['action'])
+        self.assertEqual('PENDING', zone['status'])
+
+        LOG.info('Wait till the zone is Active')
+        waiters.wait_for_zone_status(self.client, zone['id'], 'ACTIVE')
+
+        LOG.info('Ensure that SOA and NS recordsets types has been created.')
+        recordsets = self.recordset_client.list_recordset(
+            zone['id'])[1]['recordsets']
+        types = [rec['type'] for rec in recordsets]
+        expected_types = ['SOA', 'NS']
+        for exp_type in expected_types:
+            self.assertIn(
+                exp_type, types,
+                'Failed, expected recordset type:{} was'
+                ' not created'.format(exp_type))
+
     @decorators.idempotent_id('02ca5d6a-86ce-4f02-9d94-9e5db55c3055')
     def test_show_zone(self):
         LOG.info('Create a zone')
@@ -192,7 +224,7 @@
 
 
 class ZonesAdminTest(BaseZonesTest):
-    credentials = ['primary', 'admin', 'alt']
+    credentials = ["primary", "admin", "system_admin", "alt"]
 
     @classmethod
     def setup_credentials(cls):
@@ -203,8 +235,11 @@
     @classmethod
     def setup_clients(cls):
         super(ZonesAdminTest, cls).setup_clients()
+        if CONF.enforce_scope.designate:
+            cls.admin_client = cls.os_system_admin.dns_v2.ZonesClient()
+        else:
+            cls.admin_client = cls.os_admin.dns_v2.ZonesClient()
         cls.client = cls.os_primary.dns_v2.ZonesClient()
-        cls.admin_client = cls.os_admin.dns_v2.ZonesClient()
         cls.alt_client = cls.os_alt.dns_v2.ZonesClient()
 
     @decorators.idempotent_id('f6fe8cce-8b04-11eb-a861-74e5f9e2a801')
@@ -261,19 +296,22 @@
             self.alt_client, alt_zone['id'], 'ACTIVE')
 
         LOG.info('Create zone "C" using Admin client')
-        admin_zone = self.admin_client.create_zone()[1]
+        admin_zone = self.admin_client.create_zone(
+            project_id="FakeProjectID")[1]
         self.addCleanup(
-            self.wait_zone_delete, self.admin_client, admin_zone['id'])
+            self.wait_zone_delete, self.admin_client, admin_zone['id'],
+            headers=self.all_projects_header)
         LOG.info('Wait till the zone is ACTIVE')
         waiters.wait_for_zone_status(
-            self.admin_client, admin_zone['id'], 'ACTIVE')
+            self.admin_client, admin_zone['id'], 'ACTIVE',
+            headers=self.all_projects_header)
 
         LOG.info('As admin user list all projects zones')
         # Note: This is an all-projects list call, so other tests running
         #       in parallel will impact the list result set. Since the default
         #       pagination limit is only 20, we set a param limit of 1000 here.
         body = self.admin_client.list_zones(
-            headers={'x-auth-all-projects': True},
+            headers=self.all_projects_header,
             params={'limit': 1000})[1]['zones']
         listed_zone_ids = [item['id'] for item in body]
 
@@ -288,7 +326,7 @@
 
 
 class ZoneOwnershipTest(BaseZonesTest):
-    credentials = ['primary', 'alt']
+    credentials = ["primary", "alt"]
 
     @classmethod
     def setup_credentials(cls):
diff --git a/designate_tempest_plugin/tests/api/v2/test_zones_exports.py b/designate_tempest_plugin/tests/api/v2/test_zones_exports.py
index e07f32a..4841d18 100644
--- a/designate_tempest_plugin/tests/api/v2/test_zones_exports.py
+++ b/designate_tempest_plugin/tests/api/v2/test_zones_exports.py
@@ -13,11 +13,13 @@
 #    under the License.
 
 from oslo_log import log as logging
+from tempest import config
 from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 
 from designate_tempest_plugin.tests import base
 
+CONF = config.CONF
 LOG = logging.getLogger(__name__)
 
 
@@ -27,7 +29,7 @@
 
 
 class ZonesExportTest(BaseZoneExportsTest):
-    credentials = ['primary', 'admin', 'alt']
+    credentials = ["primary", "admin", "system_admin", "alt"]
 
     @classmethod
     def setup_credentials(cls):
@@ -38,11 +40,14 @@
     @classmethod
     def setup_clients(cls):
         super(ZonesExportTest, cls).setup_clients()
+        if CONF.enforce_scope.designate:
+            cls.admin_client = cls.os_system_admin.dns_v2.ZoneExportsClient()
+        else:
+            cls.admin_client = cls.os_admin.dns_v2.ZoneExportsClient()
         cls.zone_client = cls.os_primary.dns_v2.ZonesClient()
         cls.alt_zone_client = cls.os_alt.dns_v2.ZonesClient()
         cls.client = cls.os_primary.dns_v2.ZoneExportsClient()
         cls.alt_client = cls.os_alt.dns_v2.ZoneExportsClient()
-        cls.admin_client = cls.os_admin.dns_v2.ZoneExportsClient()
 
     @decorators.idempotent_id('2dd8a9a0-98a2-4bf6-bb51-286583b30f40')
     def test_create_zone_export(self):
@@ -150,7 +155,7 @@
         #       pagination limit is only 20, we set a param limit of 1000 here.
         listed_exports_ids = [
             item['id'] for item in self.admin_client.list_zone_exports(
-                headers={'x-auth-all-projects': True},
+                headers=self.all_projects_header,
                 params={'limit': 1000})[1]['exports']]
 
         LOG.info('Make sure that all previously created zone '
@@ -185,7 +190,7 @@
                  ' expected: empty list')
         self.assertEqual(
             [], self.admin_client.list_zone_exports(
-                headers={'x-auth-all-projects': True},
+                headers=self.all_projects_header,
                 params={'status': 'ZAHLABUT'})[1]['exports'],
             'Failed, filtered result is expected to be empty.')
 
@@ -193,7 +198,7 @@
                  ' expected: empty list')
         self.assertEqual(
             [], self.admin_client.list_zone_exports(
-                headers={'x-auth-all-projects': True},
+                headers=self.all_projects_header,
                 params={'message': 'ZABABUN'})[1]['exports'],
             'Failed, filtered result is expected to be empty.')
 
@@ -201,7 +206,7 @@
                  'a primary zone. Expected: single zone export is listed')
         self.assertEqual(
             1, len(self.admin_client.list_zone_exports(
-                headers={'x-auth-all-projects': True},
+                headers=self.all_projects_header,
                 params={'zone_id': primary_zone['id']})[1]['exports']),
             'Failed, filtered result should contain a single zone '
             '(primary zone export)')
@@ -210,13 +215,13 @@
                  'an alt zone expected: empty list (it was deleted)')
         self.assertEqual(
             [], self.admin_client.list_zone_exports(
-                headers={'x-auth-all-projects': True},
+                headers=self.all_projects_header,
                 params={'zone_id': alt_zone['id']})[1]['exports'],
             'Failed, filtered result should be empty.')
 
 
 class ZonesExportTestNegative(BaseZoneExportsTest):
-    credentials = ['primary', 'alt']
+    credentials = ["primary", "alt"]
 
     @classmethod
     def setup_credentials(cls):
diff --git a/designate_tempest_plugin/tests/api/v2/test_zones_imports.py b/designate_tempest_plugin/tests/api/v2/test_zones_imports.py
index 7f1261b..510708d 100644
--- a/designate_tempest_plugin/tests/api/v2/test_zones_imports.py
+++ b/designate_tempest_plugin/tests/api/v2/test_zones_imports.py
@@ -13,6 +13,7 @@
 #    under the License.
 
 from oslo_log import log as logging
+from tempest import config
 from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 
@@ -21,6 +22,7 @@
 from designate_tempest_plugin.tests import base
 from designate_tempest_plugin import data_utils as dns_data_utils
 
+CONF = config.CONF
 LOG = logging.getLogger(__name__)
 
 
@@ -30,7 +32,7 @@
 
 
 class ZonesImportTest(BaseZonesImportTest):
-    credentials = ['primary', 'admin', 'alt']
+    credentials = ["primary", "admin", "system_admin", "alt"]
 
     @classmethod
     def setup_credentials(cls):
@@ -41,10 +43,13 @@
     @classmethod
     def setup_clients(cls):
         super(ZonesImportTest, cls).setup_clients()
+        if CONF.enforce_scope.designate:
+            cls.admin_client = cls.os_system_admin.dns_v2.ZoneImportsClient()
+        else:
+            cls.admin_client = cls.os_admin.dns_v2.ZoneImportsClient()
         cls.zone_client = cls.os_primary.dns_v2.ZonesClient()
         cls.client = cls.os_primary.dns_v2.ZoneImportsClient()
         cls.alt_client = cls.os_alt.dns_v2.ZoneImportsClient()
-        cls.admin_client = cls.os_admin.dns_v2.ZoneImportsClient()
 
     def clean_up_resources(self, zone_import_id):
         zone_import = self.client.show_zone_import(zone_import_id)[1]
@@ -195,15 +200,15 @@
                  '"x-auth-all-projects" HTTP header, Expected: 403 Forbidden')
         self.assertRaises(
             lib_exc.Forbidden, lambda: self.alt_client.list_zone_imports(
-                headers={'x-auth-all-projects': True}))
+                headers=self.all_projects_header))
 
         LOG.info('As Admin tenant list import zones for all projects')
         # Note: This is an all-projects list call, so other tests running
         #       in parallel will impact the list result set. Since the default
         #       pagination limit is only 20, we set a param limit of 1000 here.
-        body = self.admin_client.list_zone_imports(headers={
-                'x-auth-all-projects': True},
-                params={'limit': 1000})[1]['imports']
+        body = self.admin_client.list_zone_imports(
+            headers=self.all_projects_header,
+            params={'limit': 1000})[1]['imports']
 
         LOG.info('Ensure the fetched response includes previously '
                  'created import ID')
diff --git a/designate_tempest_plugin/tests/base.py b/designate_tempest_plugin/tests/base.py
index 6f2845e..2e02a8c 100644
--- a/designate_tempest_plugin/tests/base.py
+++ b/designate_tempest_plugin/tests/base.py
@@ -124,6 +124,17 @@
                               zone_client,
                               zone_id)
 
+    def wait_recordset_delete(self, recordset_client, zone_id,
+                              recordset_id, **kwargs):
+        self._delete_recordset(
+            recordset_client, zone_id, recordset_id, **kwargs)
+        utils.call_until_true(self._check_recordset_deleted,
+                              CONF.dns.build_timeout,
+                              CONF.dns.build_interval,
+                              recordset_client,
+                              zone_id,
+                              recordset_id)
+
     def _delete_zone(self, zone_client, zone_id, **kwargs):
         return utils.call_and_ignore_notfound_exc(zone_client.delete_zone,
                                                   zone_id, **kwargs)
@@ -132,10 +143,23 @@
         return utils.call_and_ignore_notfound_exc(zone_client.show_zone,
                                                   zone_id) is None
 
+    def _delete_recordset(self, recordset_client, zone_id,
+                          recordset_id, **kwargs):
+        return utils.call_and_ignore_notfound_exc(
+            recordset_client.delete_recordset,
+            zone_id, recordset_id, **kwargs)
+
+    def _check_recordset_deleted(
+            self, recordset_client, zone_id, recordset_id):
+        return utils.call_and_ignore_notfound_exc(
+            recordset_client.show_recordset, zone_id, recordset_id) is None
+
 
 class BaseDnsV2Test(BaseDnsTest):
     """Base class for DNS V2 API tests."""
 
+    all_projects_header = {'X-Auth-All-Projects': True}
+
     @classmethod
     def skip_checks(cls):
         super(BaseDnsV2Test, cls).skip_checks()
diff --git a/designate_tempest_plugin/tests/scenario/v2/test_blacklists.py b/designate_tempest_plugin/tests/scenario/v2/test_blacklists.py
new file mode 100644
index 0000000..1501300
--- /dev/null
+++ b/designate_tempest_plugin/tests/scenario/v2/test_blacklists.py
@@ -0,0 +1,102 @@
+# Copyright 2021 Red Hat.
+#
+# 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 import data_utils as dns_data_utils
+from designate_tempest_plugin.tests import base
+
+LOG = logging.getLogger(__name__)
+
+
+class BaseBlacklistsTest(base.BaseDnsV2Test):
+    excluded_keys = ['created_at', 'updated_at', 'links']
+
+
+class BlacklistE2E(BaseBlacklistsTest):
+
+    credentials = ["admin", 'primary']
+
+    @classmethod
+    def setup_credentials(cls):
+        # Do not create network resources for these test.
+        cls.set_network_resources()
+        super(BlacklistE2E, cls).setup_credentials()
+
+    @classmethod
+    def setup_clients(cls):
+        super(BlacklistE2E, cls).setup_clients()
+        cls.admin_blacklist_client = cls.os_admin.dns_v2.BlacklistsClient()
+        cls.admin_zone_client = cls.os_admin.dns_v2.ZonesClient()
+        cls.primary_zone_client = cls.os_primary.dns_v2.ZonesClient()
+
+    @decorators.idempotent_id('22b1ee72-d8d2-11eb-bcdc-74e5f9e2a801')
+    def test_primary_fails_to_create_zone_matches_blacklist_regex(self):
+        LOG.info('Create a blacklist using regex')
+        blacklist = {
+            'pattern': '^blacklistregextest.*',
+            'description': 'Zone starts with "blacklistregextest" char'}
+        body = self.admin_blacklist_client.create_blacklist(**blacklist)[1]
+        self.addCleanup(
+            self.admin_blacklist_client.delete_blacklist, body['id'])
+
+        LOG.info('Try to create a zone that is starts with '
+                 '"blacklistregextest".')
+        self.assertRaisesDns(
+            lib_exc.BadRequest, 'invalid_zone_name', 400,
+            self.primary_zone_client.create_zone,
+            name='blacklistregextest' + dns_data_utils.rand_zone_name())
+
+    @decorators.idempotent_id('6956f20c-d8d5-11eb-bcdc-74e5f9e2a801')
+    def test_primary_fails_to_create_zone_matches_blacklist_name(self):
+        LOG.info('Create a blacklist using the exact name(string)')
+        zone_name = 'blacklistnametest' + dns_data_utils.rand_zone_name()
+        blacklist = {
+            'pattern': zone_name,
+            'description': 'Zone named:{} '.format(zone_name)}
+        body = self.admin_blacklist_client.create_blacklist(**blacklist)[1]
+        self.addCleanup(
+            self.admin_blacklist_client.delete_blacklist, body['id'])
+
+        LOG.info('Try to create a zone named:{}'.format(zone_name))
+        self.assertRaisesDns(
+            lib_exc.BadRequest, 'invalid_zone_name', 400,
+            self.primary_zone_client.create_zone, name=zone_name)
+
+    @decorators.idempotent_id('de030088-d97e-11eb-8ab8-74e5f9e2a801')
+    def test_admin_creates_zone_matches_blacklist_name_or_regex(self):
+        LOG.info('Create a blacklists using: regex and exact string(name)')
+        zone_name = 'blacklistnameregextest1' + dns_data_utils.rand_zone_name()
+        blacklists = [
+            {'pattern': '^blacklistnameregextest2.*',
+             'description': 'Zone starts with "a" char'},
+            {'pattern': zone_name,
+             'description': 'Deny if Zone named:{} '.format(zone_name)}]
+        for blacklist in blacklists:
+            body = self.admin_blacklist_client.create_blacklist(**blacklist)[1]
+            self.addCleanup(
+                self.admin_blacklist_client.delete_blacklist, body['id'])
+
+        LOG.info('As Admin user try to create zones that are '
+                 'supposed to be blocked')
+        zone = self.admin_zone_client.create_zone(
+            name='blacklistnameregextest2' +
+                 dns_data_utils.rand_zone_name())[1]
+        self.addCleanup(
+            self.wait_zone_delete, self.admin_zone_client, zone['id'])
+        zone = self.admin_zone_client.create_zone(name=zone_name)[1]
+        self.addCleanup(
+            self.wait_zone_delete, self.admin_zone_client, zone['id'])
diff --git a/designate_tempest_plugin/tests/scenario/v2/test_quotas.py b/designate_tempest_plugin/tests/scenario/v2/test_quotas.py
new file mode 100644
index 0000000..0c20b3d
--- /dev/null
+++ b/designate_tempest_plugin/tests/scenario/v2/test_quotas.py
@@ -0,0 +1,92 @@
+# Copyright 2021 Red Hat.
+#
+# 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 import config
+from tempest.lib import decorators
+
+from designate_tempest_plugin.tests import base
+from designate_tempest_plugin import data_utils as dns_data_utils
+
+LOG = logging.getLogger(__name__)
+
+
+CONF = config.CONF
+
+
+class QuotasV2Test(base.BaseDnsV2Test):
+
+    credentials = ['primary', 'admin', 'system_admin', 'alt']
+
+    @classmethod
+    def setup_credentials(cls):
+        # Do not create network resources for these test.
+        cls.set_network_resources()
+        super(QuotasV2Test, cls).setup_credentials()
+
+    @classmethod
+    def skip_checks(cls):
+        super(QuotasV2Test, cls).skip_checks()
+
+        if not CONF.dns_feature_enabled.api_v2_quotas:
+            skip_msg = ("%s skipped as designate V2 Quotas API is not "
+                        "available" % cls.__name__)
+            raise cls.skipException(skip_msg)
+
+    @classmethod
+    def setup_clients(cls):
+        super(QuotasV2Test, cls).setup_clients()
+        if CONF.enforce_scope.designate:
+            cls.admin_client = cls.os_system_admin.dns_v2.QuotasClient()
+        else:
+            cls.admin_client = cls.os_admin.dns_v2.QuotasClient()
+        cls.quotas_client = cls.os_primary.dns_v2.QuotasClient()
+        cls.alt_client = cls.os_alt.dns_v2.QuotasClient()
+        cls.alt_zone_client = cls.os_alt.dns_v2.ZonesClient()
+
+    @decorators.idempotent_id('6987953a-dccf-11eb-903e-74e5f9e2a801')
+    def test_alt_reaches_zones_quota(self):
+
+        alt_project_id = self.alt_client.project_id
+        http_header = {'x-auth-sudo-project-id': alt_project_id}
+        limit_zones_quota = 3
+
+        LOG.info('As Admin user set Zones quota for Alt user '
+                 'to:{} '.format(limit_zones_quota))
+        quotas = dns_data_utils.rand_quotas()
+        quotas['zones'] = limit_zones_quota
+        self.admin_client.set_quotas(
+            project_id=alt_project_id, quotas=quotas, headers=http_header)
+        self.addCleanup(
+            self.admin_client.delete_quotas, project_id=alt_project_id)
+
+        LOG.info('As Alt user try to create zones, up untill'
+                 ' "zones" quota (status code 413) is reached')
+        attempt_number = 0
+        while attempt_number <= limit_zones_quota + 1:
+            attempt_number += 1
+            LOG.info('Attempt No:{} '.format(attempt_number))
+            try:
+                zone = self.alt_zone_client.create_zone()[1]
+                self.addCleanup(
+                    self.wait_zone_delete, self.alt_zone_client, zone['id'])
+            except Exception as err:
+                raised_error = str(err).replace(' ', '')
+                if not "'code':413" and "'type':'over_quota'" in raised_error \
+                        and attempt_number == limit_zones_quota + 1:
+                    raise (
+                        "Failed, expected status code 413 (type:over_quota) "
+                        "was not raised or maybe it has been raised mistakenly"
+                        "(bug) before the quota was actually reached."
+                        " Test failed with: {} ".format(err))