Merge "Adding new test cases to "quota" scenario test suite"
diff --git a/designate_tempest_plugin/services/dns/json/base.py b/designate_tempest_plugin/services/dns/json/base.py
index 37f585f..6ac9a85 100644
--- a/designate_tempest_plugin/services/dns/json/base.py
+++ b/designate_tempest_plugin/services/dns/json/base.py
@@ -17,8 +17,7 @@
 from oslo_serialization import jsonutils as json
 from tempest.lib.common import rest_client
 from tempest.lib import exceptions as lib_exc
-from six.moves.urllib import parse as urllib
-import six
+from urllib import parse as urllib_parse
 
 from designate_tempest_plugin.common import models
 
@@ -58,7 +57,7 @@
     DELETE_STATUS_CODES = []
 
     def serialize(self, data):
-        if isinstance(data, six.string_types):
+        if isinstance(data, str):
             return data
         return json.dumps(data)
 
@@ -106,7 +105,7 @@
         else:
             uuid = '/%s' % uuid if uuid else ''
 
-        params = '?%s' % urllib.urlencode(params) if params else ''
+        params = '?%s' % urllib_parse.urlencode(params) if params else ''
 
         return uri_pattern.format(pref=self.uri_prefix,
                                   res=resource_name,
diff --git a/designate_tempest_plugin/services/dns/query/query_client.py b/designate_tempest_plugin/services/dns/query/query_client.py
index da1d1b0..ce9c7c1 100644
--- a/designate_tempest_plugin/services/dns/query/query_client.py
+++ b/designate_tempest_plugin/services/dns/query/query_client.py
@@ -14,7 +14,6 @@
 import dns
 import dns.exception
 import dns.query
-import six
 from tempest import config
 
 CONF = config.CONF
@@ -51,7 +50,7 @@
     @classmethod
     def _prepare_query(cls, zone_name, rdatatype):
         # support plain strings: "SOA", "A"
-        if isinstance(rdatatype, six.string_types):
+        if isinstance(rdatatype, str):
             rdatatype = dns.rdatatype.from_text(rdatatype)
         dns_message = dns.message.make_query(zone_name, rdatatype)
         dns_message.set_opcode(dns.opcode.QUERY)
diff --git a/designate_tempest_plugin/tests/api/v2/test_blacklists.py b/designate_tempest_plugin/tests/api/v2/test_blacklists.py
index cd859af..ecb5ce5 100644
--- a/designate_tempest_plugin/tests/api/v2/test_blacklists.py
+++ b/designate_tempest_plugin/tests/api/v2/test_blacklists.py
@@ -66,7 +66,6 @@
                                         expected_allowed, False)
 
     @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:
diff --git a/designate_tempest_plugin/tests/base.py b/designate_tempest_plugin/tests/base.py
index e581e0a..091c3ca 100644
--- a/designate_tempest_plugin/tests/base.py
+++ b/designate_tempest_plugin/tests/base.py
@@ -11,7 +11,6 @@
 # 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 six
 from tempest import test
 from tempest import config
 from tempest.lib.common.utils import test_utils as utils
@@ -106,7 +105,7 @@
         )
 
     def assertExpected(self, expected, actual, excluded_keys):
-        for key, value in six.iteritems(expected):
+        for key, value in expected.items():
             if key not in excluded_keys:
                 self.assertIn(key, actual)
                 self.assertEqual(value, actual[key], key)
diff --git a/designate_tempest_plugin/tests/scenario/v2/test_zones.py b/designate_tempest_plugin/tests/scenario/v2/test_zones.py
index 2c89c20..74f9563 100644
--- a/designate_tempest_plugin/tests/scenario/v2/test_zones.py
+++ b/designate_tempest_plugin/tests/scenario/v2/test_zones.py
@@ -11,6 +11,10 @@
 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 # License for the specific language governing permissions and limitations
 # under the License.
+
+import time
+import math
+
 from oslo_log import log as logging
 from tempest import config
 from tempest.lib import decorators
@@ -21,6 +25,10 @@
 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.services.dns.query.query_client \
+    import SingleQueryClient
+
+CONF = config.CONF
 
 CONF = config.CONF
 LOG = logging.getLogger(__name__)
@@ -34,14 +42,16 @@
         super(ZonesTest, cls).setup_clients()
         if CONF.enforce_scope.designate:
             cls.admin_tld_client = cls.os_system_admin.dns_v2.TldClient()
+            cls.rec_client = cls.os_system_admin.dns_v2.RecordsetClient()
         else:
             cls.admin_tld_client = cls.os_admin.dns_v2.TldClient()
+            cls.rec_client = cls.os_admin.dns_v2.RecordsetClient()
         cls.client = cls.os_primary.dns_v2.ZonesClient()
+        cls.primary_client = cls.os_primary.dns_v2.BlacklistsClient()
 
     @classmethod
     def resource_setup(cls):
         super(ZonesTest, cls).resource_setup()
-
         # Make sure we have an allowed TLD available
         tld_name = dns_data_utils.rand_zone_name(name="ZonesTest")
         cls.tld_name = f".{tld_name}"
@@ -183,3 +193,66 @@
         waiters.wait_for_zone_404(self.client, zone['id'])
         waiters.wait_for_query(self.query_client, zone['name'], const.SOA,
                                found=False)
+
+    @decorators.attr(type='slow')
+    @decorators.idempotent_id('ff9b9fc4-85b4-11ec-bcf5-201e8823901f')
+    @testtools.skipUnless(
+        config.CONF.dns.nameservers,
+        "Config option dns.nameservers is missing or empty")
+    def test_notify_msg_sent_to_nameservers(self):
+
+        # Test will only run when the SOA record Refresh is close to one hour,
+        # otherwise skipped.
+        # This implies that the only reason "A" record was propagated is as a
+        # result of successfully sent NOTIFY message.
+
+        LOG.info('Create a zone, wait until ACTIVE and get the Serial'
+                 ' and SOA Refresh values')
+        zone_name = dns_data_utils.rand_zone_name(
+            name="test_notify_msg_sent_to_nameservers", suffix=self.tld_name)
+        zone = self.client.create_zone(name=zone_name, wait_until='ACTIVE')[1]
+
+        org_serial = zone['serial']
+        self.addCleanup(self.wait_zone_delete, self.client, zone['id'])
+        try:
+            soa = [
+                rec['records'] for rec in self.rec_client.list_recordset(
+                    zone['id'], headers=self.all_projects_header)[1][
+                    'recordsets'] if rec['type'] == 'SOA'][0]
+            refresh = int(soa[0].split(' ')[3])
+            if math.isclose(3600, refresh, rel_tol=0.1) is False:
+                raise self.skipException(
+                    'Test is skipped, actual SOA REFRESH is:{} unlike test'
+                    ' prerequisites that requires a value close to 3600'
+                    ' (one hour)'.format(refresh))
+        except Exception as e:
+            raise self.skipException(
+                'Test is skipped, something went wrong on getting SOA REFRESH'
+                ' value, the error was:{}'.format(e))
+
+        LOG.info("Update Zone's TTL, wait until ACTIVE and"
+                 " ensure Zone's Serial has changed")
+        updated_zone = self.client.update_zone(
+            zone['id'], ttl=dns_data_utils.rand_ttl(), wait_until='ACTIVE')[1]
+        new_serial = updated_zone['serial']
+        self.assertNotEqual(
+            new_serial, org_serial,
+            "Failed, expected behaviour is that the Designate DNS changes the"
+            " Serial after updating Zone's TTL value")
+        waiters.wait_for_query(self.query_client, zone['name'], "SOA")
+
+        LOG.info('Per Nameserver "dig" for a SOA record until either:'
+                 ' updated Serial is detected or build timeout has reached')
+        for ns in config.CONF.dns.nameservers:
+            start = time.time()
+            while True:
+                ns_obj = SingleQueryClient(ns, config.CONF.dns.query_timeout)
+                ns_soa_record = ns_obj.query(zone['name'], rdatatype='SOA')
+                if str(new_serial) in str(ns_soa_record):
+                    return
+                if time.time() - start >= config.CONF.dns.build_timeout:
+                    raise lib_exc.TimeoutException(
+                        'Failed, expected Serial:{} for a Zone was not'
+                        ' detected on Nameserver:{} within a timeout of:{}'
+                        ' seconds.'.format(
+                            new_serial, ns, config.CONF.dns.build_timeout))