Merge "Use new tempest option to verify redirects"
diff --git a/.gitignore b/.gitignore
index a6a0b0b..8c8997c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,7 +14,7 @@
 *.log
 .coverage
 .coverage.*
-/.testrepository/*
+.stestr/
 .tox
 .venv
 cover
diff --git a/.stestr.conf b/.stestr.conf
new file mode 100644
index 0000000..9006406
--- /dev/null
+++ b/.stestr.conf
@@ -0,0 +1,4 @@
+[DEFAULT]
+test_path=${OS_TEST_PATH:-./designate_tempest_plugin}
+top_dir=./
+
diff --git a/.testr.conf b/.testr.conf
deleted file mode 100644
index fee97eb..0000000
--- a/.testr.conf
+++ /dev/null
@@ -1,12 +0,0 @@
-[DEFAULT]
-test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \
-             OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \
-             OS_LOG_CAPTURE=${OS_LOG_CAPTURE:-1} \
-             OS_DEBUG=${OS_DEBUG:-1} \
-             OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-500} \
-             OS_TEST_LOCK_PATH=${OS_TEST_LOCK_PATH:-${TMPDIR:-'/tmp'}} \
-             ${PYTHON:-python} -m subunit.run discover -t ${OS_TOP_LEVEL:-./} ${OS_TEST_PATH:-./designate_tempest_plugin} $LISTOPT $IDOPTION
-
-test_id_option=--load-list $IDFILE
-test_list_option=--list
-group_regex=([^\.]*\.)*
diff --git a/.zuul.yaml b/.zuul.yaml
index 64c99f4..9cc66cf 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -1,6 +1,11 @@
 - project:
     templates:
       - designate-devstack-jobs
+      - check-requirements
+      - publish-openstack-docs-pti
+      - tempest-plugin-jobs
     check:
       jobs:
         - neutron-tempest-plugin-designate-scenario
+    gate:
+      queue: designate
diff --git a/designate_tempest_plugin/config.py b/designate_tempest_plugin/config.py
index fea31f2..2f97565 100644
--- a/designate_tempest_plugin/config.py
+++ b/designate_tempest_plugin/config.py
@@ -77,8 +77,12 @@
     cfg.BoolOpt('api_v2_quotas',
                 default=False,
                 help="Is the v2 quota API enabled."),
-    cfg.BoolOpt('bug_1573141_fixed',
+    cfg.BoolOpt('api_v2_quotas_verify_project',
                 default=False,
+                help="Is project IDs verified when setting v2 quotas. "
+                "Must be set to True starting from Rocky release."),
+    cfg.BoolOpt('bug_1573141_fixed',
+                default=True,
                 help="Is https://bugs.launchpad.net/designate/+bug/1573141 "
                 "fixed"),
 ]
diff --git a/designate_tempest_plugin/services/dns/query/query_client.py b/designate_tempest_plugin/services/dns/query/query_client.py
index 65552c7..5c6b021 100644
--- a/designate_tempest_plugin/services/dns/query/query_client.py
+++ b/designate_tempest_plugin/services/dns/query/query_client.py
@@ -14,6 +14,7 @@
 import dns
 import dns.exception
 import dns.query
+import six
 from tempest import config
 
 CONF = config.CONF
@@ -50,7 +51,7 @@
     @classmethod
     def _prepare_query(cls, zone_name, rdatatype):
         # support plain strings: "SOA", "A"
-        if isinstance(rdatatype, basestring):
+        if isinstance(rdatatype, six.string_types):
             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_quotas.py b/designate_tempest_plugin/tests/api/v2/test_quotas.py
index b32591f..fe6c318 100644
--- a/designate_tempest_plugin/tests/api/v2/test_quotas.py
+++ b/designate_tempest_plugin/tests/api/v2/test_quotas.py
@@ -14,6 +14,7 @@
 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
 from designate_tempest_plugin import data_utils as dns_data_utils
@@ -26,7 +27,7 @@
 
 class QuotasV2Test(base.BaseDnsV2Test):
 
-    credentials = ['primary', 'admin']
+    credentials = ['primary', 'admin', 'alt']
 
     @classmethod
     def setup_credentials(cls):
@@ -49,6 +50,7 @@
 
         cls.quotas_client = cls.os_primary.quotas_client
         cls.admin_client = cls.os_admin.quotas_client
+        cls.alt_client = cls.os_alt.quotas_client
 
     @decorators.idempotent_id('1dac991a-9e2e-452c-a47a-26ac37381ec5')
     def test_show_quotas(self):
@@ -105,8 +107,8 @@
     @decorators.idempotent_id('21e45d30-dbc1-4173-9d6b-9b6813ef514b')
     def test_reset_quotas_other_project(self):
 
-        # Use a fake project for this
-        project_id = '21e45d30-dbc1-4173-9d6b-9b6813ef514b'
+        LOG.info("Using 'alt' project id to set quotas on.")
+        project_id = self.alt_client.tenant_id
 
         _, original_quotas = self.admin_client.show_quotas(
             project_id=project_id, headers={'X-Auth-All-Projects': True})
@@ -128,3 +130,29 @@
             project_id=project_id, headers={'X-Auth-All-Projects': True})
 
         self.assertExpected(original_quotas, final_quotas, [])
+
+    @decorators.idempotent_id('9b09b3e2-7e88-4569-bce3-9be2f7ac70c4')
+    def test_update_quotas_invalid_project(self):
+
+        if not CONF.dns_feature_enabled.api_v2_quotas_verify_project:
+            raise self.skipException("Project ID in quotas "
+                                     "is not being verified.")
+
+        project_id = 'project-that-does-not-exist'
+
+        LOG.info("Updating quotas for non-existing %s ", project_id)
+
+        _, original_quotas = self.admin_client.show_quotas(
+            project_id=project_id, headers={'X-Auth-All-Projects': True})
+
+        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.addCleanup(self.admin_client.delete_quotas, project_id=project_id)
+
+        _, client_body = self.quotas_client.show_quotas()
+
+        self.assertExpected(original_quotas, client_body, [])
diff --git a/doc/source/conf.py b/doc/source/conf.py
index d6ccf8e..23a2069 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -37,8 +37,8 @@
 # We ask git for the SHA checksum
 # The git SHA checksum is used by "log-a-bug"
 git_cmd = ["/usr/bin/git", "rev-parse", "HEAD"]
-gitsha = subprocess.Popen(
-    git_cmd, stdout=subprocess.PIPE).communicate()[0].strip('\n')
+gitsha = str(subprocess.Popen(
+    git_cmd, stdout=subprocess.PIPE).communicate())[0].strip('\n')
 # tag that reported bugs will be tagged with
 bug_tag = "tempest-plugin-docs"
 # source tree
@@ -127,7 +127,7 @@
 # Add any paths that contain custom static files (such as style sheets) here,
 # relative to this directory. They are copied after the builtin static files,
 # so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
+# html_static_path = ['_static']
 
 # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
 # using the given strftime format.
diff --git a/doc/source/index.rst b/doc/source/index.rst
index ac57e68..82eda14 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -245,7 +245,7 @@
 
 
 @decorators.attr
-~~~~~~~~~~
+~~~~~~~~~~~~~~~~
 
 The `attr` decorator is used to set test attributes, this is most commonly used
 to set the test type. Currently, we use one test type "smoke", which should be
diff --git a/tools/pretty_tox.sh b/tools/pretty_tox.sh
deleted file mode 100755
index 0fc3605..0000000
--- a/tools/pretty_tox.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-#! /bin/sh
-
-TESTRARGS=$1
-
-exec 3>&1
-status=$(exec 4>&1 >&3; ( python setup.py testr --slowest --testr-args="--subunit $TESTRARGS"; echo $? >&4 ) | subunit-trace -f) && exit $status
diff --git a/tox.ini b/tox.ini
index f183956..4d9c7df 100644
--- a/tox.ini
+++ b/tox.ini
@@ -18,7 +18,7 @@
                       rm
 commands =
   find . -type f -name "*.pyc" -delete
-  sh tools/pretty_tox.sh '{posargs}'
+  stestr run {posargs}
 passenv = http_proxy
           HTTP_PROXY
           https_proxy