Merge "Remove _project_network_cidr in security group tests"
diff --git a/.gitignore b/.gitignore
index 287db4c..7cb052f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,6 +18,7 @@
 dist
 build
 .testrepository
+.stestr
 .idea
 .project
 .pydevproject
diff --git a/.stestr.conf b/.stestr.conf
new file mode 100644
index 0000000..e3201c1
--- /dev/null
+++ b/.stestr.conf
@@ -0,0 +1,4 @@
+[DEFAULT]
+test_path=./tempest/test_discover
+group_regex=([^\.]*\.)*
+
diff --git a/doc/source/microversion_testing.rst b/doc/source/microversion_testing.rst
index 307eb07..acf5593 100644
--- a/doc/source/microversion_testing.rst
+++ b/doc/source/microversion_testing.rst
@@ -338,4 +338,28 @@
 
  * `3.3`_
 
- .. _3.3:  https://docs.openstack.org/cinder/latest/contributor/api_microversion_history.html#id4
+ .. _3.3:  https://docs.openstack.org/cinder/latest/contributor/api_microversion_history.html#id3
+
+ * `3.9`_
+
+ .. _3.9:  https://docs.openstack.org/cinder/latest/contributor/api_microversion_history.html#id9
+
+ * `3.11`_
+
+ .. _3.11:  https://docs.openstack.org/cinder/latest/contributor/api_microversion_history.html#id11
+
+ * `3.12`_
+
+ .. _3.12:  https://docs.openstack.org/cinder/latest/contributor/api_microversion_history.html#id12
+
+ * `3.14`_
+
+ .. _3.14:  https://docs.openstack.org/cinder/latest/contributor/api_microversion_history.html#id14
+
+ * `3.19`_
+
+ .. _3.19:  https://docs.openstack.org/cinder/latest/contributor/api_microversion_history.html#id18
+
+ * `3.20`_
+
+ .. _3.20:  https://docs.openstack.org/cinder/latest/contributor/api_microversion_history.html#id19
diff --git a/releasenotes/notes/remove-deprecated-apis-from-v2-volumes-client-3ca4a5db5fea518f.yaml b/releasenotes/notes/remove-deprecated-apis-from-v2-volumes-client-3ca4a5db5fea518f.yaml
new file mode 100644
index 0000000..c75da2e
--- /dev/null
+++ b/releasenotes/notes/remove-deprecated-apis-from-v2-volumes-client-3ca4a5db5fea518f.yaml
@@ -0,0 +1,11 @@
+---
+upgrade:
+  - |
+    Remove deprecated APIs from volume v2 volumes_client, and the deprecated
+    APIs are re-realized in volume v2 transfers_client.
+
+    * create_volume_transfer
+    * show_volume_transfer
+    * list_volume_transfers
+    * delete_volume_transfer
+    * accept_volume_transfer
diff --git a/tempest/api/compute/flavors/test_flavors.py b/tempest/api/compute/flavors/test_flavors.py
index d5bb45a..20294e9 100644
--- a/tempest/api/compute/flavors/test_flavors.py
+++ b/tempest/api/compute/flavors/test_flavors.py
@@ -18,8 +18,6 @@
 
 
 class FlavorsV2TestJSON(base.BaseV2ComputeTest):
-    _min_disk = 'minDisk'
-    _min_ram = 'minRam'
 
     @decorators.attr(type='smoke')
     @decorators.idempotent_id('e36c0eaa-dff5-4082-ad1f-3f9a80aa3f59')
@@ -89,7 +87,7 @@
         flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor']
         flavor_id = flavor['id']
 
-        params = {self._min_disk: flavor['disk'] + 1}
+        params = {'minDisk': flavor['disk'] + 1}
         flavors = self.flavors_client.list_flavors(detail=True,
                                                    **params)['flavors']
         self.assertEmpty([i for i in flavors if i['id'] == flavor_id])
@@ -100,7 +98,7 @@
         flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor']
         flavor_id = flavor['id']
 
-        params = {self._min_ram: flavor['ram'] + 1}
+        params = {'minRam': flavor['ram'] + 1}
         flavors = self.flavors_client.list_flavors(detail=True,
                                                    **params)['flavors']
         self.assertEmpty([i for i in flavors if i['id'] == flavor_id])
@@ -111,7 +109,7 @@
         flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor']
         flavor_id = flavor['id']
 
-        params = {self._min_disk: flavor['disk'] + 1}
+        params = {'minDisk': flavor['disk'] + 1}
         flavors = self.flavors_client.list_flavors(**params)['flavors']
         self.assertEmpty([i for i in flavors if i['id'] == flavor_id])
 
@@ -121,6 +119,6 @@
         flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor']
         flavor_id = flavor['id']
 
-        params = {self._min_ram: flavor['ram'] + 1}
+        params = {'minRam': flavor['ram'] + 1}
         flavors = self.flavors_client.list_flavors(**params)['flavors']
         self.assertEmpty([i for i in flavors if i['id'] == flavor_id])
diff --git a/tempest/api/compute/floating_ips/test_floating_ips_actions.py b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
index 86e244b..8938570 100644
--- a/tempest/api/compute/floating_ips/test_floating_ips_actions.py
+++ b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
@@ -26,8 +26,6 @@
 
 
 class FloatingIPsTestJSON(base.BaseFloatingIPsTest):
-    server_id = None
-    floating_ip = None
 
     @classmethod
     def skip_checks(cls):
diff --git a/tempest/api/compute/images/test_images_oneserver.py b/tempest/api/compute/images/test_images_oneserver.py
index e62e25e..058e7e6 100644
--- a/tempest/api/compute/images/test_images_oneserver.py
+++ b/tempest/api/compute/images/test_images_oneserver.py
@@ -15,6 +15,7 @@
 
 from tempest.api.compute import base
 from tempest import config
+from tempest.lib.common import api_version_utils
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
 
@@ -86,5 +87,9 @@
         # 4 byte utf-8 character.
         utf8_name = data_utils.rand_name(b'\xe2\x82\xa1'.decode('utf-8'))
         body = self.client.create_image(self.server_id, name=utf8_name)
-        image_id = data_utils.parse_image_id(body.response['location'])
+        if api_version_utils.compare_version_header_to_response(
+            "OpenStack-API-Version", "compute 2.45", body.response, "lt"):
+            image_id = body['image_id']
+        else:
+            image_id = data_utils.parse_image_id(body.response['location'])
         self.addCleanup(self.client.delete_image, image_id)
diff --git a/tempest/api/compute/images/test_images_oneserver_negative.py b/tempest/api/compute/images/test_images_oneserver_negative.py
index 7ecfa0a..4de00ce 100644
--- a/tempest/api/compute/images/test_images_oneserver_negative.py
+++ b/tempest/api/compute/images/test_images_oneserver_negative.py
@@ -19,6 +19,7 @@
 from tempest.api.compute import base
 from tempest.common import waiters
 from tempest import config
+from tempest.lib.common import api_version_utils
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
@@ -105,7 +106,11 @@
         self.assertRaises(lib_exc.Conflict, self.create_image_from_server,
                           self.server_id)
 
-        image_id = data_utils.parse_image_id(image.response['location'])
+        if api_version_utils.compare_version_header_to_response(
+            "OpenStack-API-Version", "compute 2.45", image.response, "lt"):
+            image_id = image['image_id']
+        else:
+            image_id = data_utils.parse_image_id(image.response['location'])
         self.client.delete_image(image_id)
 
     @decorators.attr(type=['negative'])
@@ -123,7 +128,11 @@
         # Return an error while trying to delete an image what is creating
 
         image = self.create_image_from_server(self.server_id)
-        image_id = data_utils.parse_image_id(image.response['location'])
+        if api_version_utils.compare_version_header_to_response(
+            "OpenStack-API-Version", "compute 2.45", image.response, "lt"):
+            image_id = image['image_id']
+        else:
+            image_id = data_utils.parse_image_id(image.response['location'])
 
         self.addCleanup(self._reset_server)
 
diff --git a/tempest/api/object_storage/base.py b/tempest/api/object_storage/base.py
index 24c9c24..ee72163 100644
--- a/tempest/api/object_storage/base.py
+++ b/tempest/api/object_storage/base.py
@@ -106,7 +106,7 @@
     def create_container(cls):
         # wrapper that returns a test container
         container_name = data_utils.rand_name(name='TestContainer')
-        cls.container_client.create_container(container_name)
+        cls.container_client.update_container(container_name)
         cls.containers.append(container_name)
 
         return container_name
diff --git a/tempest/api/object_storage/test_account_services.py b/tempest/api/object_storage/test_account_services.py
index 0f86540..d7c85a2 100644
--- a/tempest/api/object_storage/test_account_services.py
+++ b/tempest/api/object_storage/test_account_services.py
@@ -43,7 +43,7 @@
         super(AccountTest, cls).resource_setup()
         for i in range(ord('a'), ord('f') + 1):
             name = data_utils.rand_name(name='%s-' % six.int2byte(i))
-            cls.container_client.create_container(name)
+            cls.container_client.update_container(name)
             cls.containers.append(name)
         cls.containers_count = len(cls.containers)
 
diff --git a/tempest/api/object_storage/test_container_acl_negative.py b/tempest/api/object_storage/test_container_acl_negative.py
index 03a5879..90b24b4 100644
--- a/tempest/api/object_storage/test_container_acl_negative.py
+++ b/tempest/api/object_storage/test_container_acl_negative.py
@@ -39,7 +39,7 @@
     def setUp(self):
         super(ObjectACLsNegativeTest, self).setUp()
         self.container_name = data_utils.rand_name(name='TestContainer')
-        self.container_client.create_container(self.container_name)
+        self.container_client.update_container(self.container_name)
 
     def tearDown(self):
         self.delete_containers([self.container_name])
diff --git a/tempest/api/object_storage/test_container_services.py b/tempest/api/object_storage/test_container_services.py
index c6f21ec..cdc420e 100644
--- a/tempest/api/object_storage/test_container_services.py
+++ b/tempest/api/object_storage/test_container_services.py
@@ -27,7 +27,7 @@
     @decorators.idempotent_id('92139d73-7819-4db1-85f8-3f2f22a8d91f')
     def test_create_container(self):
         container_name = data_utils.rand_name(name='TestContainer')
-        resp, _ = self.container_client.create_container(container_name)
+        resp, _ = self.container_client.update_container(container_name)
         self.containers.append(container_name)
         self.assertHeaders(resp, 'Container', 'PUT')
 
@@ -35,20 +35,20 @@
     def test_create_container_overwrite(self):
         # overwrite container with the same name
         container_name = data_utils.rand_name(name='TestContainer')
-        self.container_client.create_container(container_name)
+        self.container_client.update_container(container_name)
         self.containers.append(container_name)
 
-        resp, _ = self.container_client.create_container(container_name)
+        resp, _ = self.container_client.update_container(container_name)
         self.assertHeaders(resp, 'Container', 'PUT')
 
     @decorators.idempotent_id('c2ac4d59-d0f5-40d5-ba19-0635056d48cd')
     def test_create_container_with_metadata_key(self):
         # create container with the blank value of metadata
         container_name = data_utils.rand_name(name='TestContainer')
-        metadata = {'test-container-meta': ''}
-        resp, _ = self.container_client.create_container(
+        headers = {'X-Container-Meta-test-container-meta': ''}
+        resp, _ = self.container_client.update_container(
             container_name,
-            metadata=metadata)
+            **headers)
         self.containers.append(container_name)
         self.assertHeaders(resp, 'Container', 'PUT')
 
@@ -64,10 +64,10 @@
         container_name = data_utils.rand_name(name='TestContainer')
 
         # metadata name using underscores should be converted to hyphens
-        metadata = {'test_container_meta': 'Meta1'}
-        resp, _ = self.container_client.create_container(
+        headers = {'X-Container-Meta-test_container_meta': 'Meta1'}
+        resp, _ = self.container_client.update_container(
             container_name,
-            metadata=metadata)
+            **headers)
         self.containers.append(container_name)
         self.assertHeaders(resp, 'Container', 'PUT')
 
@@ -75,22 +75,20 @@
             container_name)
         self.assertIn('x-container-meta-test-container-meta', resp)
         self.assertEqual(resp['x-container-meta-test-container-meta'],
-                         metadata['test_container_meta'])
+                         headers['X-Container-Meta-test_container_meta'])
 
     @decorators.idempotent_id('24d16451-1c0c-4e4f-b59c-9840a3aba40e')
     def test_create_container_with_remove_metadata_key(self):
         # create container with the blank value of remove metadata
         container_name = data_utils.rand_name(name='TestContainer')
-        metadata_1 = {'test-container-meta': 'Meta1'}
-        self.container_client.create_container(
-            container_name,
-            metadata=metadata_1)
+        headers = {'X-Container-Meta-test-container-meta': 'Meta1'}
+        self.container_client.update_container(container_name, **headers)
         self.containers.append(container_name)
 
-        metadata_2 = {'test-container-meta': ''}
-        resp, _ = self.container_client.create_container(
+        headers = {'X-Remove-Container-Meta-test-container-meta': ''}
+        resp, _ = self.container_client.update_container(
             container_name,
-            remove_metadata=metadata_2)
+            **headers)
         self.assertHeaders(resp, 'Container', 'PUT')
 
         resp, _ = self.container_client.list_container_metadata(
@@ -101,14 +99,13 @@
     def test_create_container_with_remove_metadata_value(self):
         # create container with remove metadata
         container_name = data_utils.rand_name(name='TestContainer')
-        metadata = {'test-container-meta': 'Meta1'}
-        self.container_client.create_container(container_name,
-                                               metadata=metadata)
+        headers = {'X-Container-Meta-test-container-meta': 'Meta1'}
+        self.container_client.update_container(container_name, **headers)
         self.containers.append(container_name)
-
-        resp, _ = self.container_client.create_container(
+        headers = {'X-Remove-Container-Meta-test-container-meta': 'Meta1'}
+        resp, _ = self.container_client.update_container(
             container_name,
-            remove_metadata=metadata)
+            **headers)
         self.assertHeaders(resp, 'Container', 'PUT')
 
         resp, _ = self.container_client.list_container_metadata(
@@ -301,9 +298,8 @@
     def test_update_container_metadata_with_create_and_delete_metadata(self):
         # Send one request of adding and deleting metadata
         container_name = data_utils.rand_name(name='TestContainer')
-        metadata_1 = {'test-container-meta1': 'Meta1'}
-        self.container_client.create_container(container_name,
-                                               metadata=metadata_1)
+        metadata_1 = {'X-Container-Meta-test-container-meta1': 'Meta1'}
+        self.container_client.update_container(container_name, **metadata_1)
         self.containers.append(container_name)
 
         metadata_2 = {'test-container-meta2': 'Meta2'}
@@ -311,7 +307,7 @@
             self.container_client.create_update_or_delete_container_metadata(
                 container_name,
                 create_update_metadata=metadata_2,
-                delete_metadata=metadata_1))
+                delete_metadata={'test-container-meta1': 'Meta1'}))
         self.assertHeaders(resp, 'Container', 'POST')
 
         resp, _ = self.container_client.list_container_metadata(
@@ -343,15 +339,14 @@
     def test_update_container_metadata_with_delete_metadata(self):
         # update container metadata using delete metadata
         container_name = data_utils.rand_name(name='TestContainer')
-        metadata = {'test-container-meta1': 'Meta1'}
-        self.container_client.create_container(container_name,
-                                               metadata=metadata)
+        metadata = {'X-Container-Meta-test-container-meta1': 'Meta1'}
+        self.container_client.update_container(container_name, **metadata)
         self.containers.append(container_name)
 
         resp, _ = (
             self.container_client.create_update_or_delete_container_metadata(
                 container_name,
-                delete_metadata=metadata))
+                delete_metadata={'test-container-meta1': 'Meta1'}))
         self.assertHeaders(resp, 'Container', 'POST')
 
         resp, _ = self.container_client.list_container_metadata(
@@ -378,9 +373,8 @@
     def test_update_container_metadata_with_delete_metadata_key(self):
         # update container metadata with a blank value of metadata
         container_name = data_utils.rand_name(name='TestContainer')
-        metadata = {'test-container-meta1': 'Meta1'}
-        self.container_client.create_container(container_name,
-                                               metadata=metadata)
+        headers = {'X-Container-Meta-test-container-meta1': 'Meta1'}
+        self.container_client.update_container(container_name, **headers)
         self.containers.append(container_name)
 
         metadata = {'test-container-meta1': ''}
diff --git a/tempest/api/object_storage/test_container_services_negative.py b/tempest/api/object_storage/test_container_services_negative.py
index 707c016..b8c83b7 100644
--- a/tempest/api/object_storage/test_container_services_negative.py
+++ b/tempest/api/object_storage/test_container_services_negative.py
@@ -45,9 +45,10 @@
         max_length = self.constraints['max_container_name_length']
         # create a container with long name
         container_name = data_utils.arbitrary_string(size=max_length + 1)
-        ex = self.assertRaises(exceptions.BadRequest,
-                               self.container_client.create_container,
-                               container_name)
+        ex = self.assertRaises(
+            exceptions.BadRequest,
+            self.container_client.update_container,
+            container_name)
         self.assertIn('Container name length of ' + str(max_length + 1) +
                       ' longer than ' + str(max_length), str(ex))
 
@@ -61,11 +62,13 @@
         # that is longer than max.
         max_length = self.constraints['max_meta_name_length']
         container_name = data_utils.rand_name(name='TestContainer')
-        metadata_name = data_utils.arbitrary_string(size=max_length + 1)
+        metadata_name = 'X-Container-Meta-' + data_utils.arbitrary_string(
+            size=max_length + 1)
         metadata = {metadata_name: 'penguin'}
-        ex = self.assertRaises(exceptions.BadRequest,
-                               self.container_client.create_container,
-                               container_name, metadata=metadata)
+        ex = self.assertRaises(
+            exceptions.BadRequest,
+            self.container_client.update_container,
+            container_name, **metadata)
         self.assertIn('Metadata name too long', str(ex))
 
     @decorators.attr(type=["negative"])
@@ -79,10 +82,11 @@
         max_length = self.constraints['max_meta_value_length']
         container_name = data_utils.rand_name(name='TestContainer')
         metadata_value = data_utils.arbitrary_string(size=max_length + 1)
-        metadata = {'animal': metadata_value}
-        ex = self.assertRaises(exceptions.BadRequest,
-                               self.container_client.create_container,
-                               container_name, metadata=metadata)
+        metadata = {'X-Container-Meta-animal': metadata_value}
+        ex = self.assertRaises(
+            exceptions.BadRequest,
+            self.container_client.update_container,
+            container_name, **metadata)
         self.assertIn('Metadata value longer than ' + str(max_length), str(ex))
 
     @decorators.attr(type=["negative"])
@@ -97,11 +101,12 @@
         container_name = data_utils.rand_name(name='TestContainer')
         metadata = {}
         for i in range(max_count + 1):
-            metadata['animal-' + str(i)] = 'penguin'
+            metadata['X-Container-Meta-animal-' + str(i)] = 'penguin'
 
-        ex = self.assertRaises(exceptions.BadRequest,
-                               self.container_client.create_container,
-                               container_name, metadata=metadata)
+        ex = self.assertRaises(
+            exceptions.BadRequest,
+            self.container_client.update_container,
+            container_name, **metadata)
         self.assertIn('Too many metadata items; max ' + str(max_count),
                       str(ex))
 
diff --git a/tempest/api/object_storage/test_object_services.py b/tempest/api/object_storage/test_object_services.py
index 836a875..61cbe30 100644
--- a/tempest/api/object_storage/test_object_services.py
+++ b/tempest/api/object_storage/test_object_services.py
@@ -786,12 +786,12 @@
     def test_copy_object_across_containers(self):
         # create a container to use as a source container
         src_container_name = data_utils.rand_name(name='TestSourceContainer')
-        self.container_client.create_container(src_container_name)
+        self.container_client.update_container(src_container_name)
         self.containers.append(src_container_name)
         # create a container to use as a destination container
         dst_container_name = data_utils.rand_name(
             name='TestDestinationContainer')
-        self.container_client.create_container(dst_container_name)
+        self.container_client.update_container(dst_container_name)
         self.containers.append(dst_container_name)
         # create object in source container
         object_name = data_utils.rand_name(name='Object')
@@ -977,7 +977,7 @@
     def setUp(self):
         super(PublicObjectTest, self).setUp()
         self.container_name = data_utils.rand_name(name='TestContainer')
-        self.container_client.create_container(self.container_name)
+        self.container_client.update_container(self.container_name)
 
     def tearDown(self):
         self.delete_containers([self.container_name])
diff --git a/tempest/api/object_storage/test_object_version.py b/tempest/api/object_storage/test_object_version.py
index 4799053..51b0a1d 100644
--- a/tempest/api/object_storage/test_object_version.py
+++ b/tempest/api/object_storage/test_object_version.py
@@ -51,18 +51,16 @@
     def test_versioned_container(self):
         # create container
         vers_container_name = data_utils.rand_name(name='TestVersionContainer')
-        resp, _ = self.container_client.create_container(
-            vers_container_name)
+        resp, _ = self.container_client.update_container(vers_container_name)
         self.containers.append(vers_container_name)
         self.assertHeaders(resp, 'Container', 'PUT')
         self.assertContainer(vers_container_name, '0', '0', 'Missing Header')
 
         base_container_name = data_utils.rand_name(name='TestBaseContainer')
         headers = {'X-versions-Location': vers_container_name}
-        resp, _ = self.container_client.create_container(
+        resp, _ = self.container_client.update_container(
             base_container_name,
-            metadata=headers,
-            metadata_prefix='')
+            **headers)
         self.containers.append(base_container_name)
         self.assertHeaders(resp, 'Container', 'PUT')
         self.assertContainer(base_container_name, '0', '0',
diff --git a/tempest/api/volume/test_volumes_extend.py b/tempest/api/volume/test_volumes_extend.py
index 1eb76a0..de28a30 100644
--- a/tempest/api/volume/test_volumes_extend.py
+++ b/tempest/api/volume/test_volumes_extend.py
@@ -13,12 +13,15 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import time
+
 import testtools
 
 from tempest.api.volume import base
 from tempest.common import waiters
 from tempest import config
 from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
 
 CONF = config.CONF
 
@@ -53,3 +56,129 @@
         resized_volume = self.volumes_client.show_volume(
             volume['id'])['volume']
         self.assertEqual(extend_size, resized_volume['size'])
+
+
+class VolumesExtendAttachedTest(base.BaseVolumeTest):
+    """Tests extending the size of an attached volume."""
+
+    # We need admin credentials for getting instance action event details. By
+    # default a non-admin can list and show instance actions if they own the
+    # server instance, but since the event details can contain error messages
+    # and tracebacks, like an instance fault, those are not viewable by
+    # non-admins. This is obviously not a great user experience since the user
+    # may not know when the operation is actually complete. A microversion in
+    # the compute API will be added so that non-admins can see instance action
+    # events but will continue to hide the traceback field.
+    # TODO(mriedem): Change this to not rely on the admin user to get the event
+    # details once that microversion is available in Nova.
+    credentials = ['primary', 'admin']
+
+    _api_version = 3
+    # NOTE(mriedem): The minimum required volume API version is 3.42 and the
+    # minimum required compute API microversion is 2.51, but the compute call
+    # is implicit - Cinder calls Nova at that microversion, Tempest does not.
+    min_microversion = '3.42'
+
+    @classmethod
+    def setup_clients(cls):
+        super(VolumesExtendAttachedTest, cls).setup_clients()
+        cls.admin_servers_client = cls.os_admin.servers_client
+
+    def _find_extend_volume_instance_action(self, server_id):
+        actions = self.servers_client.list_instance_actions(
+            server_id)['instanceActions']
+        for action in actions:
+            if action['action'] == 'extend_volume':
+                return action
+
+    def _find_extend_volume_instance_action_finish_event(self, action):
+        # This has to be called by an admin client otherwise
+        # the events don't show up.
+        action = self.admin_servers_client.show_instance_action(
+            action['instance_uuid'], action['request_id'])['instanceAction']
+        for event in action['events']:
+            if (event['event'] == 'compute_extend_volume' and
+                    event['finish_time']):
+                return event
+
+    @decorators.idempotent_id('301f5a30-1c6f-4ea0-be1a-91fd28d44354')
+    @testtools.skipUnless(CONF.volume_feature_enabled.extend_attached_volume,
+                          "Attached volume extend is disabled.")
+    def test_extend_attached_volume(self):
+        """This is a happy path test which does the following:
+
+        * Create a volume at the configured volume_size.
+        * Create a server instance.
+        * Attach the volume to the server.
+        * Wait for the volume status to be "in-use".
+        * Extend the size of the volume and wait for the volume status to go
+          back to "in-use".
+        * Assert the volume size change is reflected in the volume API.
+        * Wait for the "compute_extend_volume" instance action event to show
+          up in the compute API with the success or failure status. We fail
+          if we timeout waiting for the instance action event to show up, or
+          if the action on the server fails.
+        """
+        # Create a test volume. Will be automatically cleaned up on teardown.
+        volume = self.create_volume()
+        # Create a test server. Will be automatically cleaned up on teardown.
+        server = self.create_server()
+        # Attach the volume to the server and wait for the volume status to be
+        # "in-use".
+        self.attach_volume(server['id'], volume['id'])
+        # Extend the size of the volume. If this is successful, the volume API
+        # will change the status on the volume to "extending" before doing an
+        # RPC cast to the volume manager on the backend. Note that we multiply
+        # the size of the volume since certain Cinder backends, e.g. ScaleIO,
+        # require multiples of 8GB.
+        extend_size = volume['size'] * 2
+        self.volumes_client.extend_volume(volume['id'], new_size=extend_size)
+        # The volume status should go back to in-use since it is still attached
+        # to the server instance.
+        waiters.wait_for_volume_resource_status(self.volumes_client,
+                                                volume['id'], 'in-use')
+        # Assert that the volume size has changed in the volume API.
+        volume = self.volumes_client.show_volume(volume['id'])['volume']
+        self.assertEqual(extend_size, volume['size'])
+        # Now we wait for the "compute_extend_volume" instance action event
+        # to show up for the server instance. This is our indication that the
+        # asynchronous operation is complete on the compute side.
+        start_time = int(time.time())
+        timeout = self.servers_client.build_timeout
+        action = self._find_extend_volume_instance_action(server['id'])
+        while action is None and int(time.time()) - start_time < timeout:
+            time.sleep(self.servers_client.build_interval)
+            action = self._find_extend_volume_instance_action(server['id'])
+
+        if action is None:
+            msg = ("Timed out waiting to get 'extend_volume' instance action "
+                   "record for server %(server)s after %(timeout)s seconds." %
+                   {'server': server['id'], 'timeout': timeout})
+            raise lib_exc.TimeoutException(msg)
+
+        # Now that we found the extend_volume instance action, we can wait for
+        # the compute_extend_volume instance action event to show up to
+        # indicate the operation is complete.
+        start_time = int(time.time())
+        event = self._find_extend_volume_instance_action_finish_event(action)
+        while event is None and int(time.time()) - start_time < timeout:
+            time.sleep(self.servers_client.build_interval)
+            event = self._find_extend_volume_instance_action_finish_event(
+                action)
+
+        if event is None:
+            msg = ("Timed out waiting to get 'compute_extend_volume' instance "
+                   "action event record for server %(server)s and request "
+                   "%(request_id)s after %(timeout)s seconds." %
+                   {'server': server['id'],
+                    'request_id': action['request_id'],
+                    'timeout': timeout})
+            raise lib_exc.TimeoutException(msg)
+
+        # Finally, assert that the action completed successfully.
+        self.assertTrue(
+            event['result'].lower() == 'success',
+            "Unexpected compute_extend_volume result '%(result)s' for request "
+            "%(request_id)s." %
+            {'result': event['result'],
+             'request_id': action['request_id']})
diff --git a/tempest/config.py b/tempest/config.py
index 4d0839a..024a638 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -836,7 +836,14 @@
                 help="Is the v2 volume API enabled"),
     cfg.BoolOpt('api_v3',
                 default=True,
-                help="Is the v3 volume API enabled")
+                help="Is the v3 volume API enabled"),
+    cfg.BoolOpt('extend_attached_volume',
+                default=False,
+                help='Does the cloud support extending the size of a volume '
+                     'which is currently attached to a server instance? This '
+                     'depends on the 3.42 volume API microversion and the '
+                     '2.51 compute API microversion. Also, not all volume or '
+                     'compute backends support this operation.')
 ]
 
 
diff --git a/tempest/lib/services/volume/v2/volumes_client.py b/tempest/lib/services/volume/v2/volumes_client.py
index d13e449..79973ee 100644
--- a/tempest/lib/services/volume/v2/volumes_client.py
+++ b/tempest/lib/services/volume/v2/volumes_client.py
@@ -13,7 +13,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from debtcollector import moves
 from debtcollector import removals
 from oslo_serialization import jsonutils as json
 import six
@@ -22,43 +21,12 @@
 from tempest.lib.common import rest_client
 from tempest.lib import exceptions as lib_exc
 from tempest.lib.services.volume import base_client
-from tempest.lib.services.volume.v2 import transfers_client
 
 
 class VolumesClient(base_client.BaseClient):
     """Client class to send CRUD Volume V2 API requests"""
     api_version = "v2"
 
-    create_volume_transfer = moves.moved_function(
-        transfers_client.TransfersClient.create_volume_transfer,
-        'VolumesClient.create_volume_transfer', __name__,
-        message='Use create_volume_transfer from new location.',
-        version='Pike', removal_version='Queens')
-
-    show_volume_transfer = moves.moved_function(
-        transfers_client.TransfersClient.show_volume_transfer,
-        'VolumesClient.show_volume_transfer', __name__,
-        message='Use show_volume_transfer from new location.',
-        version='Pike', removal_version='Queens')
-
-    list_volume_transfers = moves.moved_function(
-        transfers_client.TransfersClient.list_volume_transfers,
-        'VolumesClient.list_volume_transfers', __name__,
-        message='Use list_volume_transfer from new location.',
-        version='Pike', removal_version='Queens')
-
-    delete_volume_transfer = moves.moved_function(
-        transfers_client.TransfersClient.delete_volume_transfer,
-        'VolumesClient.delete_volume_transfer', __name__,
-        message='Use delete_volume_transfer from new location.',
-        version='Pike', removal_version='Queens')
-
-    accept_volume_transfer = moves.moved_function(
-        transfers_client.TransfersClient.accept_volume_transfer,
-        'VolumesClient.accept_volume_transfer', __name__,
-        message='Use accept_volume_transfer from new location.',
-        version='Pike', removal_version='Queens')
-
     def _prepare_params(self, params):
         """Prepares params for use in get or _ext_get methods.
 
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 00c9b61..c70ab49 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -504,9 +504,6 @@
         waiters.wait_for_volume_resource_status(self.volumes_client,
                                                 volume['id'], 'available')
 
-        volume = self.volumes_client.show_volume(volume['id'])['volume']
-        self.assertEqual('available', volume['status'])
-
     def rebuild_server(self, server_id, image=None,
                        preserve_ephemeral=False, wait=True,
                        rebuild_kwargs=None):
@@ -1006,23 +1003,6 @@
                         client.delete_security_group, secgroup['id'])
         return secgroup
 
-    def _default_security_group(self, client=None, tenant_id=None):
-        """Get default secgroup for given tenant_id.
-
-        :returns: default secgroup for given tenant
-        """
-        if client is None:
-            client = self.security_groups_client
-        if not tenant_id:
-            tenant_id = client.tenant_id
-        sgs = [
-            sg for sg in list(client.list_security_groups().values())[0]
-            if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
-        ]
-        msg = "No default security group for tenant %s." % (tenant_id)
-        self.assertNotEmpty(sgs, msg)
-        return sgs[0]
-
     def _create_security_group_rule(self, secgroup=None,
                                     sec_group_rules_client=None,
                                     tenant_id=None,
@@ -1051,8 +1031,12 @@
         if not tenant_id:
             tenant_id = security_groups_client.tenant_id
         if secgroup is None:
-            secgroup = self._default_security_group(
-                client=security_groups_client, tenant_id=tenant_id)
+            # Get default secgroup for tenant_id
+            default_secgroups = security_groups_client.list_security_groups(
+                name='default', tenant_id=tenant_id)['security_groups']
+            msg = "No default security group for tenant %s." % (tenant_id)
+            self.assertNotEmpty(default_secgroups, msg)
+            secgroup = default_secgroups[0]
 
         ruleset = dict(security_group_id=secgroup['id'],
                        tenant_id=secgroup['tenant_id'])
@@ -1294,7 +1278,7 @@
     def create_container(self, container_name=None):
         name = container_name or data_utils.rand_name(
             'swift-scenario-container')
-        self.container_client.create_container(name)
+        self.container_client.update_container(name)
         # look for the container to assure it is created
         self.list_and_check_container_objects(name)
         LOG.debug('Container %s created', name)
diff --git a/tempest/services/object_storage/container_client.py b/tempest/services/object_storage/container_client.py
index a253599..2da8e24 100644
--- a/tempest/services/object_storage/container_client.py
+++ b/tempest/services/object_storage/container_client.py
@@ -24,30 +24,25 @@
 
 class ContainerClient(rest_client.RestClient):
 
-    def create_container(
-            self, container_name,
-            metadata=None,
-            remove_metadata=None,
-            metadata_prefix='X-Container-Meta-',
-            remove_metadata_prefix='X-Remove-Container-Meta-'):
-        """Creates a container
+    def update_container(self, container_name, **headers):
+        """Creates or Updates a container
 
-        with optional metadata passed in as a dictionary
+        with optional metadata passed in as a dictionary.
+        Full list of allowed headers or value, please refer to the
+        official API reference:
+        https://developer.openstack.org/api-ref/object-store/#create-container
         """
         url = str(container_name)
-        headers = {}
-
-        if metadata is not None:
-            for key in metadata:
-                headers[metadata_prefix + key] = metadata[key]
-        if remove_metadata is not None:
-            for key in remove_metadata:
-                headers[remove_metadata_prefix + key] = remove_metadata[key]
 
         resp, body = self.put(url, body=None, headers=headers)
         self.expected_success([201, 202], resp.status)
         return resp, body
 
+    # NOTE: This alias is for the usability because PUT can be used for both
+    # updating/creating a resource and this PUT is mainly used for creating
+    # on Swift container API.
+    create_container = update_container
+
     def delete_container(self, container_name):
         """Deletes the container (if it's empty)."""
         url = str(container_name)
diff --git a/tempest/tests/test_list_tests.py b/tempest/tests/test_list_tests.py
index a238879..4af7463 100644
--- a/tempest/tests/test_list_tests.py
+++ b/tempest/tests/test_list_tests.py
@@ -23,12 +23,10 @@
 
 class TestTestList(base.TestCase):
 
-    def test_testr_list_tests_no_errors(self):
-        # Remove unit test discover path from env to test tempest tests
+    def test_stestr_list_no_errors(self):
         test_env = os.environ.copy()
-        test_env.pop('OS_TEST_PATH')
         import_failures = []
-        p = subprocess.Popen(['testr', 'list-tests'], stdout=subprocess.PIPE,
+        p = subprocess.Popen(['stestr', 'list'], stdout=subprocess.PIPE,
                              env=test_env)
         ids, err = p.communicate()
         self.assertEqual(0, p.returncode,
diff --git a/tox.ini b/tox.ini
index 7bdc580..21696eb 100644
--- a/tox.ini
+++ b/tox.ini
@@ -16,12 +16,11 @@
 [testenv]
 setenv =
     VIRTUAL_ENV={envdir}
-    OS_TEST_PATH=./tempest/tests
     OS_LOG_CAPTURE=1
     PYTHONWARNINGS=default::DeprecationWarning
     BRANCH_NAME=master
     CLIENT_NAME=tempest
-passenv = OS_STDOUT_CAPTURE OS_STDERR_CAPTURE OS_TEST_TIMEOUT OS_TEST_LOCK_PATH OS_TEST_PATH TEMPEST_CONFIG TEMPEST_CONFIG_DIR http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY ZUUL_CACHE_DIR REQUIREMENTS_PIP_LOCATION GENERATE_TEMPEST_PLUGIN_LIST
+passenv = OS_STDOUT_CAPTURE OS_STDERR_CAPTURE OS_TEST_TIMEOUT OS_TEST_LOCK_PATH TEMPEST_CONFIG TEMPEST_CONFIG_DIR http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY ZUUL_CACHE_DIR REQUIREMENTS_PIP_LOCATION GENERATE_TEMPEST_PLUGIN_LIST
 usedevelop = True
 install_command =
     {toxinidir}/tools/tox_install.sh {env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages}
@@ -31,7 +30,7 @@
     -r{toxinidir}/test-requirements.txt
 commands =
     find . -type f -name "*.pyc" -delete
-    ostestr {posargs}
+    stestr --test-path ./tempest/tests run {posargs}
 
 [testenv:genconfig]
 commands = oslo-config-generator --config-file tempest/cmd/config-generator.tempest.conf