Merge "Modify the comment for backups_client in v1"
diff --git a/.gitignore b/.gitignore
index 06a2281..9767e52 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,9 @@
+# Don't add patterns to exclude files created by preferred personal tools
+# (editors, IDEs, your operating system itself even). These should instead be
+# maintained outside the repository, for example in a ~/.gitignore file added
+# with:
+#
+# git config --global core.excludesfile '~/.gitignore'
 AUTHORS
 ChangeLog
 *.pyc
diff --git a/.zuul.yaml b/.zuul.yaml
index d77a528..d893483 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -613,6 +613,10 @@
               - ^tempest/hacking/.*$
               - ^tempest/tests/.*$
               - ^tools/.*$
+              - ^.coveragerc$
+              - ^.gitignore$
+              - ^.gitreview$
+              - ^.mailmap$
         - tempest-full-py3:
             irrelevant-files: *tempest-irrelevant-files
         - tempest-full-py3-ipv6:
@@ -643,6 +647,10 @@
               - ^setup.cfg$
               - ^tempest/hacking/.*$
               - ^tempest/tests/.*$
+              - ^.coveragerc$
+              - ^.gitignore$
+              - ^.gitreview$
+              - ^.mailmap$
               # tools/ is not here since this relies on a script in tools/.
         - tempest-ipv6-only:
             irrelevant-files: *tempest-irrelevant-files-2
diff --git a/REVIEWING.rst b/REVIEWING.rst
index 498ce66..e07e358 100644
--- a/REVIEWING.rst
+++ b/REVIEWING.rst
@@ -183,6 +183,9 @@
     * the project's PTL +1's the change
     * the patch does not affect any other project's testing gates
     * the patch does not cause any negative side effects
+  * If fixing and removing the faulty plugin (which leads to fail
+    voting ``tempest-tox-plugin-sanity-check`` job) and unblock the
+    tempest gate
 
   Note that such a policy should be used judiciously, as we should strive to
   have two +2's on each patch set, prior to approval.
diff --git a/doc/source/conf.py b/doc/source/conf.py
index e6fb8fd..7ce431e 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -67,9 +67,6 @@
 bug_project = 'tempest'
 bug_tag = 'doc'
 
-# Must set this variable to include year, month, day, hours, and minutes.
-html_last_updated_fmt = '%Y-%m-%d %H:%M'
-
 # Add any paths that contain templates here, relative to this directory.
 templates_path = ['_templates']
 
@@ -83,7 +80,6 @@
 master_doc = 'index'
 
 # General information about the project.
-project = u'Tempest'
 copyright = u'2013, OpenStack QA Team'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
diff --git a/releasenotes/source/conf.py b/releasenotes/source/conf.py
index 57ec7e1..92df4c4 100644
--- a/releasenotes/source/conf.py
+++ b/releasenotes/source/conf.py
@@ -46,9 +46,6 @@
 bug_project = 'tempest'
 bug_tag = ''
 
-# Must set this variable to include year, month, day, hours, and minutes.
-html_last_updated_fmt = '%Y-%m-%d %H:%M'
-
 # Add any paths that contain templates here, relative to this directory.
 templates_path = ['_templates']
 
@@ -62,7 +59,6 @@
 master_doc = 'index'
 
 # General information about the project.
-project = u'tempest Release Notes'
 copyright = u'2016, tempest Developers'
 
 # Release do not need a version number in the title, they
@@ -193,17 +189,6 @@
 
 # -- Options for LaTeX output ---------------------------------------------
 
-latex_elements = {
-    # The paper size ('letterpaper' or 'a4paper').
-    # 'papersize': 'letterpaper',
-
-    # The font size ('10pt', '11pt' or '12pt').
-    # 'pointsize': '10pt',
-
-    # Additional stuff for the LaTeX preamble.
-    # 'preamble': '',
-}
-
 # Grouping the document tree into LaTeX files. List of tuples
 # (source start file, target name, title,
 #  author, documentclass [howto, manual, or own class]).
diff --git a/tempest/api/volume/admin/test_volume_pools.py b/tempest/api/volume/admin/test_volume_pools.py
index d389c26..744bc01 100644
--- a/tempest/api/volume/admin/test_volume_pools.py
+++ b/tempest/api/volume/admin/test_volume_pools.py
@@ -24,6 +24,7 @@
     def _assert_pools(self, with_detail=False):
         cinder_pools = self.admin_scheduler_stats_client.list_pools(
             detail=with_detail)['pools']
+        self.assertNotEmpty(cinder_pools, "no cinder pools listed.")
         self.assertIn('name', cinder_pools[0])
         if with_detail:
             self.assertIn(CONF.volume.vendor_name,
diff --git a/tempest/api/volume/test_versions.py b/tempest/api/volume/test_versions.py
index b4d48db..b602032 100644
--- a/tempest/api/volume/test_versions.py
+++ b/tempest/api/volume/test_versions.py
@@ -27,3 +27,15 @@
         #       with JSON-Schema validation. It is enough to just call
         #       the API here.
         self.versions_client.list_versions()
+
+    @decorators.idempotent_id('7f755ae2-caa9-4049-988c-331d8f7a579f')
+    def test_show_version(self):
+        # NOTE: The version data is checked on service client side
+        # with JSON-Schema validation. So we will loop through each
+        # version and call show version.
+        versions = self.versions_client.list_versions()['versions']
+        for version_dict in versions:
+            version = version_dict['id']
+            major_version = version.split('.')[0]
+            response = self.versions_client.show_version(major_version)
+            self.assertEqual(version, response['versions'][0]['id'])
diff --git a/tempest/api/volume/test_volumes_backup.py b/tempest/api/volume/test_volumes_backup.py
index 6ce5d3e..c178272 100644
--- a/tempest/api/volume/test_volumes_backup.py
+++ b/tempest/api/volume/test_volumes_backup.py
@@ -50,7 +50,6 @@
                                                 'available')
         return restored_volume
 
-    @decorators.skip_because(bug="1483434")
     @testtools.skipIf(CONF.volume.storage_protocol == 'ceph',
                       'ceph does not support arbitrary container names')
     @decorators.idempotent_id('a66eb488-8ee1-47d4-8e9f-575a095728c6')
diff --git a/tempest/lib/services/volume/v3/versions_client.py b/tempest/lib/services/volume/v3/versions_client.py
index fc8e92f..175f1f5 100644
--- a/tempest/lib/services/volume/v3/versions_client.py
+++ b/tempest/lib/services/volume/v3/versions_client.py
@@ -12,9 +12,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import os
 import time
 
+from six.moves.urllib.parse import urljoin
+
 from oslo_serialization import jsonutils as json
 
 from tempest.lib.api_schema.response.volume import versions as schema
@@ -50,13 +51,18 @@
     def show_version(self, version):
         """Show API version details
 
+        Use raw_request in order to have access to the endpoints minus
+        version and project in order to add version only back.
+
         For a full list of available parameters, please refer to the official
         API reference:
         https://docs.openstack.org/api-ref/block-storage/v3/#show-api-v3-details
         """
 
-        version_url = os.path.join(self._get_base_version_url(), version)
-        resp, body = self.get(version_url)
+        version_url = urljoin(self._get_base_version_url(), version + '/')
+        resp, body = self.raw_request(version_url, 'GET',
+                                      {'X-Auth-Token': self.token})
+        self._error_checker(resp, body)
         body = json.loads(body)
         self.validate_response(schema.volume_api_version_details, resp, body)
         return rest_client.ResponseBody(resp, body)
diff --git a/tempest/test.py b/tempest/test.py
index 85000b6..438f4d9 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -20,6 +20,7 @@
 import debtcollector.moves
 import fixtures
 from oslo_log import log as logging
+import pkg_resources
 import six
 import testtools
 
@@ -77,6 +78,10 @@
 atexit.register(validate_tearDownClass)
 
 
+class DummyException(Exception):
+    pass
+
+
 class BaseTestCase(testtools.testcase.WithAttributes,
                    testtools.TestCase):
     """The test base class defines Tempest framework for class level fixtures.
@@ -140,6 +145,26 @@
         cls._teardowns = []
 
     @classmethod
+    def handle_skip_exception(cls):
+        try:
+            stestr_version = pkg_resources.parse_version(
+                pkg_resources.get_distribution("stestr").version)
+            stestr_min = pkg_resources.parse_version('2.5.0')
+            new_stestr = (stestr_version >= stestr_min)
+            import unittest
+            import unittest2
+            if sys.version_info >= (3, 5) and new_stestr:
+                exc = unittest2.case.SkipTest
+                exc_to_raise = unittest.case.SkipTest
+            else:
+                exc = unittest.case.SkipTest
+                exc_to_raise = unittest2.case.SkipTest
+        except Exception:
+            exc = DummyException
+            exc_to_raise = DummyException
+        return exc, exc_to_raise
+
+    @classmethod
     def setUpClass(cls):
         cls.__setupclass_called = True
         # Reset state
@@ -148,11 +173,24 @@
         if hasattr(super(BaseTestCase, cls), 'setUpClass'):
             super(BaseTestCase, cls).setUpClass()
         # All the configuration checks that may generate a skip
-        cls.skip_checks()
-        if not cls.__skip_checks_called:
-            raise RuntimeError("skip_checks for %s did not call the super's "
-                               "skip_checks" % cls.__name__)
+        # TODO(gmann): cls.handle_skip_exception is really workaround for
+        # testtools bug- https://github.com/testing-cabal/testtools/issues/272
+        # stestr which is used by Tempest internally to run the test switch
+        # the customize test runner(which use stdlib unittest) for >=py3.5
+        # else testtools.run.- https://github.com/mtreinish/stestr/pull/265
+        # These two test runner are not compatible due to skip exception
+        # handling(due to unittest2). testtools.run treat unittestt.SkipTest
+        # as error and stdlib unittest treat unittest2.case.SkipTest raised
+        # by testtools.TestCase.skipException.
+        # The below workaround can be removed once testtools fix issue# 272.
         try:
+            exc, exc_to_raise = cls.handle_skip_exception()
+            cls.skip_checks()
+
+            if not cls.__skip_checks_called:
+                raise RuntimeError(
+                    "skip_checks for %s did not call the super's "
+                    "skip_checks" % cls.__name__)
             # Allocation of all required credentials and client managers
             cls._teardowns.append(('credentials', cls.clear_credentials))
             cls.setup_credentials()
@@ -164,6 +202,8 @@
             # Additional class-wide test resources
             cls._teardowns.append(('resources', cls.resource_cleanup))
             cls.resource_setup()
+        except exc as e:
+            raise exc_to_raise(e.args)
         except Exception:
             etype, value, trace = sys.exc_info()
             LOG.info("%s raised in %s.setUpClass. Invoking tearDownClass.",
diff --git a/tempest/tests/lib/services/identity/v3/test_projects_client.py b/tempest/tests/lib/services/identity/v3/test_projects_client.py
index 6ffbcde..d26de06 100644
--- a/tempest/tests/lib/services/identity/v3/test_projects_client.py
+++ b/tempest/tests/lib/services/identity/v3/test_projects_client.py
@@ -62,7 +62,8 @@
                             "/0c4e939acacf4376bdcd1129f1a054ad"
                 },
                 "name": "admin",
-                "parent_id": None
+                "parent_id": None,
+                "tags": []
             },
             {
                 "is_domain": False,
@@ -75,7 +76,8 @@
                             "/0cbd49cbf76d405d9c86562e1d579bd3"
                 },
                 "name": "demo",
-                "parent_id": None
+                "parent_id": None,
+                "tags": []
             },
             {
                 "is_domain": False,
@@ -88,7 +90,8 @@
                             "/2db68fed84324f29bb73130c6c2094fb"
                 },
                 "name": "swifttenanttest2",
-                "parent_id": None
+                "parent_id": None,
+                "tags": []
             },
             {
                 "is_domain": False,
@@ -101,7 +104,8 @@
                             "/3d594eb0f04741069dbbb521635b21c7"
                 },
                 "name": "service",
-                "parent_id": None
+                "parent_id": None,
+                "tags": []
             }
         ]
     }
diff --git a/tempest/tests/lib/services/identity/v3/test_users_client.py b/tempest/tests/lib/services/identity/v3/test_users_client.py
index 5b572f5..d030c5e 100644
--- a/tempest/tests/lib/services/identity/v3/test_users_client.py
+++ b/tempest/tests/lib/services/identity/v3/test_users_client.py
@@ -104,6 +104,38 @@
         ]
     }
 
+    FAKE_PROJECT_LIST = {
+        "links": {
+            "self": "http://example.com/identity/v3/users/313233/projects",
+            "previous": None,
+            "next": None
+        },
+        "projects": [
+            {
+                "description": "description of this project",
+                "domain_id": "161718",
+                "enabled": True,
+                "id": "456788",
+                "links": {
+                    "self": "http://example.com/identity/v3/projects/456788"
+                },
+                "name": "a project name",
+                "parent_id": "212223"
+            },
+            {
+                "description": "description of this project",
+                "domain_id": "161718",
+                "enabled": True,
+                "id": "456789",
+                "links": {
+                    "self": "http://example.com/identity/v3/projects/456789"
+                },
+                "name": "another domain",
+                "parent_id": "212223"
+            },
+        ]
+    }
+
     def setUp(self):
         super(TestUsersClient, self).setUp()
         fake_auth = fake_auth_provider.FakeAuthProvider()
@@ -155,6 +187,15 @@
             user_id='817fb3c23fd7465ba6d7fe1b1320121d',
         )
 
+    def _test_list_user_projects(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_user_projects,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_PROJECT_LIST,
+            bytes_body,
+            user_id='817fb3c23fd7465ba6d7fe1b1320121d',
+        )
+
     def test_create_user_with_string_body(self):
         self._test_create_user()
 
@@ -185,6 +226,12 @@
     def test_list_user_groups_with_bytes_body(self):
         self._test_list_user_groups(bytes_body=True)
 
+    def test_list_user_projects_with_string_body(self):
+        self._test_list_user_projects()
+
+    def test_list_user_projects_with_bytes_body(self):
+        self._test_list_user_projects(bytes_body=True)
+
     def test_delete_user(self):
         self.check_service_client_function(
             self.client.delete_user,
diff --git a/tempest/tests/lib/services/volume/v3/test_versions_client.py b/tempest/tests/lib/services/volume/v3/test_versions_client.py
index b9abd45..575cae3 100644
--- a/tempest/tests/lib/services/volume/v3/test_versions_client.py
+++ b/tempest/tests/lib/services/volume/v3/test_versions_client.py
@@ -97,6 +97,14 @@
                                                      'volume',
                                                      'regionOne')
 
+    def _test_get_base_version_url(self, url, expected_base_url):
+        fake_auth = fake_auth_provider.FakeAuthProvider(fake_base_url=url)
+        client = versions_client.VersionsClient(fake_auth,
+                                                'volume',
+                                                'regionOne')
+        self.assertEqual(expected_base_url,
+                         client._get_base_version_url())
+
     def _test_list_versions(self, bytes_body=False):
         self.check_service_client_function(
             self.client.list_versions,
@@ -105,22 +113,30 @@
             bytes_body,
             300)
 
+    def _test_show_version(self, version, bytes_body=False):
+        self.check_service_client_function(
+            self.client.show_version,
+            'tempest.lib.common.rest_client.RestClient.raw_request',
+            self.FAKE_VERSION_DETAILS,
+            bytes_body,
+            200, version=version)
+
     def test_list_versions_with_str_body(self):
         self._test_list_versions()
 
     def test_list_versions_with_bytes_body(self):
         self._test_list_versions(bytes_body=True)
 
-    def _test_show_version(self, bytes_body=False):
-        self.check_service_client_function(
-            self.client.show_version,
-            'tempest.lib.common.rest_client.RestClient.get',
-            self.FAKE_VERSION_DETAILS,
-            bytes_body,
-            200, version='v3')
-
     def test_show_version_details_with_str_body(self):
-        self._test_show_version()
+        self._test_show_version('v3')
 
     def test_show_version_details_with_bytes_body(self):
-        self._test_show_version(bytes_body=True)
+        self._test_show_version('v3', bytes_body=True)
+
+    def test_get_base_version_url_app_name(self):
+        self._test_get_base_version_url('https://bar.org/volume/v1/123',
+                                        'https://bar.org/volume/')
+        self._test_get_base_version_url('https://bar.org/volume/v2/123',
+                                        'https://bar.org/volume/')
+        self._test_get_base_version_url('https://bar.org/volume/v3/123',
+                                        'https://bar.org/volume/')
diff --git a/tempest/tests/test_test.py b/tempest/tests/test_test.py
index fc50736..ad0793c 100644
--- a/tempest/tests/test_test.py
+++ b/tempest/tests/test_test.py
@@ -531,8 +531,8 @@
     def test_skip_only(self):
         # If a skip condition is hit in the test, no credentials or resource
         # is provisioned / cleaned-up
-        self.mocks['skip_checks'].side_effect = (
-            testtools.testcase.TestSkipped())
+        exc, _ = test.BaseTestCase.handle_skip_exception()
+        self.mocks['skip_checks'].side_effect = (exc)
         suite = unittest.TestSuite((self.test,))
         log = []
         result = LoggingTestResult(log)
diff --git a/tools/generate-tempest-plugins-list.py b/tools/generate-tempest-plugins-list.py
index 255487e..64adcbe 100644
--- a/tools/generate-tempest-plugins-list.py
+++ b/tools/generate-tempest-plugins-list.py
@@ -35,8 +35,6 @@
 # TODO(masayukig): Some of these can be removed from BLACKLIST in the future
 # when the patches are merged.
 BLACKLIST = [
-    'openstack/barbican-tempest-plugin',
-    # https://review.opendev.org/#/c/634631/
     'x/gce-api',  # It looks gce-api doesn't support python3 yet.
     'x/group-based-policy',  # It looks this doesn't support python3 yet.
     'x/intel-nfv-ci-tests',  # https://review.opendev.org/#/c/634640/