Merge "Update v3 oauth consumers tests to work w/ pre-prov"
diff --git a/tempest/api/compute/admin/test_live_migration.py b/tempest/api/compute/admin/test_live_migration.py
index 5a60dc6..b1a7c52 100644
--- a/tempest/api/compute/admin/test_live_migration.py
+++ b/tempest/api/compute/admin/test_live_migration.py
@@ -50,8 +50,6 @@
         # a subnet so the instance being migrated has a single port, but
         # we need that to make sure we are properly updating the port
         # host bindings during the live migration.
-        # TODO(mriedem): SSH validation before and after the instance is
-        # live migrated would be a nice test wrinkle addition.
         cls.set_network_resources(network=True, subnet=True)
         super(LiveMigrationTestBase, cls).setup_credentials()
 
diff --git a/tempest/api/identity/admin/v3/test_endpoint_groups.py b/tempest/api/identity/admin/v3/test_endpoint_groups.py
index eef93c2..625568d 100644
--- a/tempest/api/identity/admin/v3/test_endpoint_groups.py
+++ b/tempest/api/identity/admin/v3/test_endpoint_groups.py
@@ -20,6 +20,10 @@
 
 
 class EndPointGroupsTest(base.BaseIdentityV3AdminTest):
+    # NOTE: force_tenant_isolation is true in the base class by default but
+    # overridden to false here to allow test execution for clouds using the
+    # pre-provisioned credentials provider.
+    force_tenant_isolation = False
 
     @classmethod
     def setup_clients(cls):
diff --git a/tempest/api/identity/admin/v3/test_projects_negative.py b/tempest/api/identity/admin/v3/test_projects_negative.py
index 33a9c8c..12f1d4a 100644
--- a/tempest/api/identity/admin/v3/test_projects_negative.py
+++ b/tempest/api/identity/admin/v3/test_projects_negative.py
@@ -22,6 +22,22 @@
 class ProjectsNegativeTestJSON(base.BaseIdentityV3AdminTest):
 
     @decorators.attr(type=['negative'])
+    @decorators.idempotent_id('8d68c012-89e0-4394-8d6b-ccd7196def97')
+    def test_project_delete_by_unauthorized_user(self):
+        # Non-admin user should not be able to delete a project
+        project = self.setup_test_project()
+        self.assertRaises(
+            lib_exc.Forbidden, self.non_admin_projects_client.delete_project,
+            project['id'])
+
+
+class ProjectsNegativeStaticTestJSON(base.BaseIdentityV3AdminTest):
+    # NOTE: force_tenant_isolation is true in the base class by default but
+    # overridden to false here to allow test execution for clouds using the
+    # pre-provisioned credentials provider.
+    force_tenant_isolation = False
+
+    @decorators.attr(type=['negative'])
     @decorators.idempotent_id('24c49279-45dd-4155-887a-cb738c2385aa')
     def test_list_projects_by_unauthorized_user(self):
         # Non-admin user should not be able to list projects
@@ -63,15 +79,6 @@
                           self.projects_client.create_project, project_name)
 
     @decorators.attr(type=['negative'])
-    @decorators.idempotent_id('8d68c012-89e0-4394-8d6b-ccd7196def97')
-    def test_project_delete_by_unauthorized_user(self):
-        # Non-admin user should not be able to delete a project
-        project = self.setup_test_project()
-        self.assertRaises(
-            lib_exc.Forbidden, self.non_admin_projects_client.delete_project,
-            project['id'])
-
-    @decorators.attr(type=['negative'])
     @decorators.idempotent_id('7965b581-60c1-43b7-8169-95d4ab7fc6fb')
     def test_delete_non_existent_project(self):
         # Attempt to delete a non existent project should fail
diff --git a/tempest/clients.py b/tempest/clients.py
index 204ce08..e5d5be1 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -82,10 +82,8 @@
             self.schemas_client = self.image_v2.SchemasClient()
             self.namespace_properties_client = \
                 self.image_v2.NamespacePropertiesClient()
-            self.namespace_tags_client = \
-                self.image_v2.NamespaceTagsClient()
-            self.image_versions_client = \
-                self.image_v2.VersionsClient()
+            self.namespace_tags_client = self.image_v2.NamespaceTagsClient()
+            self.image_versions_client = self.image_v2.VersionsClient()
 
     def _set_compute_clients(self):
         self.agents_client = self.compute.AgentsClient()
@@ -284,8 +282,7 @@
                 self.volume_v3.QuotaClassesClient()
             self.volume_scheduler_stats_v2_client = \
                 self.volume_v3.SchedulerStatsClient()
-            self.volume_transfers_v2_client = \
-                self.volume_v3.TransfersClient()
+            self.volume_transfers_v2_client = self.volume_v3.TransfersClient()
             self.volume_v2_availability_zone_client = \
                 self.volume_v3.AvailabilityZoneClient()
             self.volume_v2_limits_client = self.volume_v3.LimitsClient()
diff --git a/tempest/cmd/verify_tempest_config.py b/tempest/cmd/verify_tempest_config.py
index 6c2fee8..d25d3ca 100644
--- a/tempest/cmd/verify_tempest_config.py
+++ b/tempest/cmd/verify_tempest_config.py
@@ -365,11 +365,11 @@
         catalog_type = getattr(cfg, 'catalog_type', None)
         if not catalog_type:
             continue
-        else:
-            if cfgname == 'identity':
-                # Keystone is a required service for tempest
-                continue
-            if catalog_type not in services:
+        if cfgname == 'identity':
+            # Keystone is a required service for tempest
+            continue
+        if catalog_type not in services:
+            try:
                 if getattr(CONF.service_available, codename_match[cfgname]):
                     print('Endpoint type %s not found either disable service '
                           '%s or fix the catalog_type in the config file' % (
@@ -377,7 +377,13 @@
                     if update:
                         change_option(codename_match[cfgname],
                                       'service_available', False)
-            else:
+            except KeyError:
+                print('%s is a third party plugin, cannot be verified '
+                      'automatically, but it is suggested that it is set to '
+                      'False because %s service is not available ' % (
+                          cfgname, catalog_type))
+        else:
+            try:
                 if not getattr(CONF.service_available,
                                codename_match[cfgname]):
                     print('Endpoint type %s is available, service %s should be'
@@ -391,6 +397,11 @@
                         avail_services.append(codename_match[cfgname])
                 else:
                     avail_services.append(codename_match[cfgname])
+            except KeyError:
+                print('%s is a third party plugin, cannot be verified '
+                      'automatically, but it is suggested that it is set to '
+                      'True because %s service is available ' % (
+                          cfgname, catalog_type))
     return avail_services
 
 
diff --git a/tempest/scenario/test_network_advanced_server_ops.py b/tempest/scenario/test_network_advanced_server_ops.py
index e94ce3d..4be2b29 100644
--- a/tempest/scenario/test_network_advanced_server_ops.py
+++ b/tempest/scenario/test_network_advanced_server_ops.py
@@ -230,6 +230,32 @@
 
         self.assertNotEqual(src_host, dst_host)
 
+    @decorators.idempotent_id('03fd1562-faad-11e7-9ea0-fa163e65f5ce')
+    @testtools.skipUnless(CONF.compute_feature_enabled.live_migration,
+                          'Live migration is not available.')
+    @testtools.skipUnless(CONF.compute.min_compute_nodes > 1,
+                          'Less than 2 compute nodes, skipping multinode '
+                          'tests.')
+    @decorators.attr(type='slow')
+    @utils.services('compute', 'network')
+    def test_server_connectivity_live_migration(self):
+        keypair = self.create_keypair()
+        server = self._setup_server(keypair)
+        floating_ip = self._setup_network(server, keypair)
+        self._wait_server_status_and_check_network_connectivity(
+            server, keypair, floating_ip)
+
+        block_migration = (CONF.compute_feature_enabled.
+                           block_migration_for_live_migration)
+        self.admin_servers_client.live_migrate_server(
+            server['id'], host=None, block_migration=block_migration,
+            disk_over_commit=False)
+        waiters.wait_for_server_status(self.servers_client,
+                                       server['id'], 'ACTIVE')
+
+        self._wait_server_status_and_check_network_connectivity(
+            server, keypair, floating_ip)
+
     @decorators.skip_because(bug='1788403')
     @decorators.idempotent_id('25b188d7-0183-4b1e-a11d-15840c8e2fd6')
     @testtools.skipUnless(CONF.compute_feature_enabled.cold_migration,
diff --git a/tempest/tests/lib/common/test_http.py b/tempest/tests/lib/common/test_http.py
index 336ef4a..a19153f 100644
--- a/tempest/tests/lib/common/test_http.py
+++ b/tempest/tests/lib/common/test_http.py
@@ -170,9 +170,6 @@
 
 
 class TestClosingHttpRedirects(base.TestCase):
-    def setUp(self):
-        super(TestClosingHttpRedirects, self).setUp()
-
     def test_redirect_default(self):
         connection = http.ClosingHttp()
         self.assertTrue(connection.follow_redirects)
@@ -183,9 +180,6 @@
 
 
 class TestClosingProxyHttpRedirects(base.TestCase):
-    def setUp(self):
-        super(TestClosingProxyHttpRedirects, self).setUp()
-
     def test_redirect_default(self):
         connection = http.ClosingProxyHttp(proxy_url=PROXY_URL)
         self.assertTrue(connection.follow_redirects)
diff --git a/tempest/tests/lib/services/volume/v3/test_types_client.py b/tempest/tests/lib/services/volume/v3/test_types_client.py
new file mode 100644
index 0000000..7021a3f
--- /dev/null
+++ b/tempest/tests/lib/services/volume/v3/test_types_client.py
@@ -0,0 +1,281 @@
+#    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 tempest.lib.services.volume.v3 import types_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestTypesClient(base.BaseServiceTest):
+    FAKE_CREATE_VOLUME_TYPE = {
+        'volume_type': {
+            'id': '6685584b-1eac-4da6-b5c3-555430cf68ff',
+            'name': 'vol-type-001',
+            'description': 'volume type 0001',
+            'is_public': True,
+            'os-volume-type-access:is_public': True,
+            'extra_specs': {
+                'volume_backend_name': 'rbd'
+            }
+        }
+    }
+
+    FAKE_DEFAULT_VOLUME_TYPE_INFO = {
+        'volume_type': {
+            'id': '6685584b-1eac-4da6-b5c3-555430cf68ff',
+            'qos_specs_id': None,
+            'name': 'volume-type-test',
+            'description': 'default volume type',
+            'is_public': True,
+            'os-volume-type-access:is_public': True,
+            'extra_specs': {
+                'volume_backend_name': 'rbd'
+            }
+        }
+    }
+
+    FAKE_UPDATE_VOLUME_TYPE = {
+        'volume_type': {
+            'id': '6685584b-1eac-4da6-b5c3-555430cf68ff',
+            'qos_specs_id': None,
+            'name': 'volume-type-test',
+            'description': 'default volume type',
+            'os-volume-type-access:is_public': True,
+            'is_public': True,
+            'extra_specs': {
+                'volume_backend_name': 'rbd'
+            }
+        }
+    }
+
+    FAKE_VOLUME_TYPES = {
+        'volume_types': [
+            {
+                'name': 'volume_type01',
+                'qos_specs_id': None,
+                'extra_specs': {
+                    'volume_backend_name': 'lvmdriver-1'
+                },
+                'os-volume-type-access:is_public': True,
+                'is_public': True,
+                'id': '6685584b-1eac-4da6-b5c3-555430cf68ff',
+                'description': None
+            },
+            {
+                'name': 'volume_type02',
+                'qos_specs_id': None,
+                'extra_specs': {
+                    'volume_backend_name': 'lvmdriver-1'
+                },
+                'os-volume-type-access:is_public': True,
+                'is_public': True,
+                'id': '8eb69a46-df97-4e41-9586-9a40a7533803',
+                'description': None
+            }
+        ]
+    }
+
+    FAKE_VOLUME_TYPE_EXTRA_SPECS = {
+        'extra_specs': {
+            'capabilities': 'gpu'
+        }
+    }
+
+    FAKE_SHOW_VOLUME_TYPE_EXTRA_SPECS = {
+        'capabilities': 'gpu'
+    }
+
+    FAKE_VOLUME_TYPE_ACCESS = {
+        'volume_type_access': [{
+            'volume_type_id': '3c67e124-39ad-4ace-a507-8bb7bf510c26',
+            'project_id': 'f270b245cb11498ca4031deb7e141cfa'
+        }]
+    }
+
+    def setUp(self):
+        super(TestTypesClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = types_client.TypesClient(fake_auth,
+                                               'volume',
+                                               'regionOne')
+
+    def _test_list_volume_types(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_volume_types,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_VOLUME_TYPES,
+            bytes_body)
+
+    def _test_show_volume_type(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.show_volume_type,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_DEFAULT_VOLUME_TYPE_INFO,
+            to_utf=bytes_body,
+            volume_type_id="6685584b-1eac-4da6-b5c3-555430cf68ff")
+
+    def _test_create_volume_type(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.create_volume_type,
+            'tempest.lib.common.rest_client.RestClient.post',
+            self.FAKE_CREATE_VOLUME_TYPE,
+            to_utf=bytes_body,
+            name='volume-type-test')
+
+    def _test_delete_volume_type(self):
+        self.check_service_client_function(
+            self.client.delete_volume_type,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {}, status=202,
+            volume_type_id='6685584b-1eac-4da6-b5c3-555430cf68ff')
+
+    def _test_list_volume_types_extra_specs(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_volume_types_extra_specs,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_VOLUME_TYPE_EXTRA_SPECS,
+            to_utf=bytes_body,
+            volume_type_id='6685584b-1eac-4da6-b5c3-555430cf68ff')
+
+    def _test_show_volume_type_extra_specs(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.show_volume_type_extra_specs,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_SHOW_VOLUME_TYPE_EXTRA_SPECS,
+            volume_type_id='6685584b-1eac-4da6-b5c3-555430cf68ff',
+            extra_specs_name='capabilities',
+            to_utf=bytes_body)
+
+    def _test_create_volume_type_extra_specs(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.create_volume_type_extra_specs,
+            'tempest.lib.common.rest_client.RestClient.post',
+            self.FAKE_VOLUME_TYPE_EXTRA_SPECS,
+            volume_type_id="6685584b-1eac-4da6-b5c3-555430cf68ff",
+            extra_specs=self.FAKE_VOLUME_TYPE_EXTRA_SPECS,
+            to_utf=bytes_body)
+
+    def _test_delete_volume_type_extra_specs(self):
+        self.check_service_client_function(
+            self.client.delete_volume_type_extra_specs,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {}, status=202,
+            volume_type_id='6685584b-1eac-4da6-b5c3-555430cf68ff',
+            extra_spec_name='volume_backend_name')
+
+    def _test_update_volume_type(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.update_volume_type,
+            'tempest.lib.common.rest_client.RestClient.put',
+            self.FAKE_UPDATE_VOLUME_TYPE,
+            volume_type_id='6685584b-1eac-4da6-b5c3-555430cf68ff',
+            to_utf=bytes_body,
+            name='update-volume-type-test',
+            description='test update volume type description')
+
+    def _test_update_volume_type_extra_specs(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.update_volume_type_extra_specs,
+            'tempest.lib.common.rest_client.RestClient.put',
+            self.FAKE_SHOW_VOLUME_TYPE_EXTRA_SPECS,
+            extra_spec_name='capabilities',
+            volume_type_id='6685584b-1eac-4da6-b5c3-555430cf68ff',
+            extra_specs=self.FAKE_SHOW_VOLUME_TYPE_EXTRA_SPECS,
+            to_utf=bytes_body)
+
+    def _test_add_type_access(self):
+        self.check_service_client_function(
+            self.client.add_type_access,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {}, status=202,
+            volume_type_id='6685584b-1eac-4da6-b5c3-555430cf68ff')
+
+    def _test_remove_type_access(self):
+        self.check_service_client_function(
+            self.client.remove_type_access,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {}, status=202,
+            volume_type_id='6685584b-1eac-4da6-b5c3-555430cf68ff')
+
+    def _test_list_type_access(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_type_access,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_VOLUME_TYPE_ACCESS,
+            volume_type_id='3c67e124-39ad-4ace-a507-8bb7bf510c26',
+            to_utf=bytes_body)
+
+    def test_list_volume_types_with_str_body(self):
+        self._test_list_volume_types()
+
+    def test_list_volume_types_with_bytes_body(self):
+        self._test_list_volume_types(bytes_body=True)
+
+    def test_show_volume_type_with_str_body(self):
+        self._test_show_volume_type()
+
+    def test_show_volume_type_with_bytes_body(self):
+        self._test_show_volume_type(bytes_body=True)
+
+    def test_create_volume_type_str_body(self):
+        self._test_create_volume_type()
+
+    def test_create_volume_type_with_bytes_body(self):
+        self._test_create_volume_type(bytes_body=True)
+
+    def test_list_volume_types_extra_specs_with_str_body(self):
+        self._test_list_volume_types_extra_specs()
+
+    def test_list_volume_types_extra_specs_with_bytes_body(self):
+        self._test_list_volume_types_extra_specs(bytes_body=True)
+
+    def test_show_volume_type_extra_specs_with_str_body(self):
+        self._test_show_volume_type_extra_specs()
+
+    def test_show_volume_type_extra_specs_with_bytes_body(self):
+        self._test_show_volume_type_extra_specs(bytes_body=True)
+
+    def test_create_volume_type_extra_specs_with_str_body(self):
+        self._test_create_volume_type_extra_specs()
+
+    def test_create_volume_type_extra_specs_with_bytes_body(self):
+        self._test_create_volume_type_extra_specs(bytes_body=True)
+
+    def test_delete_volume_type_extra_specs(self):
+        self._test_delete_volume_type_extra_specs()
+
+    def test_update_volume_type_with_str_body(self):
+        self._test_update_volume_type()
+
+    def test_update_volume_type_with_bytes_body(self):
+        self._test_update_volume_type(bytes_body=True)
+
+    def test_delete_volume_type(self):
+        self._test_delete_volume_type()
+
+    def test_update_volume_type_extra_specs_with_str_body(self):
+        self._test_update_volume_type_extra_specs()
+
+    def test_update_volume_type_extra_specs_with_bytes_body(self):
+        self._test_update_volume_type_extra_specs(bytes_body=True)
+
+    def test_add_type_access(self):
+        self._test_add_type_access()
+
+    def test_remove_type_access(self):
+        self._test_remove_type_access()
+
+    def test_list_type_access_with_str_body(self):
+        self._test_list_type_access()
+
+    def test_list_type_access_with_bytes_body(self):
+        self._test_list_type_access(bytes_body=True)