Merge "Add tests for "new" Transfers API (mv 3.55)"
diff --git a/doc/source/microversion_testing.rst b/doc/source/microversion_testing.rst
index f37342e..0b80b72 100644
--- a/doc/source/microversion_testing.rst
+++ b/doc/source/microversion_testing.rst
@@ -463,3 +463,7 @@
   * `3.20`_
 
   .. _3.20:  https://docs.openstack.org/cinder/latest/contributor/api_microversion_history.html#id19
+
+  * `3.55`_
+
+  .. _3.55:  https://docs.openstack.org/cinder/latest/contributor/api_microversion_history.html#maximum-in-rocky
diff --git a/releasenotes/notes/add-volume-transfers-v3.55-73f75073ad2c4091.yaml b/releasenotes/notes/add-volume-transfers-v3.55-73f75073ad2c4091.yaml
new file mode 100644
index 0000000..c35dd67
--- /dev/null
+++ b/releasenotes/notes/add-volume-transfers-v3.55-73f75073ad2c4091.yaml
@@ -0,0 +1,8 @@
+---
+features:
+  - |
+    Add a ``TransfersV355Client`` to the volume v3 ``transfer_client`` library
+    supporting create, list, show, delete, and accept operations for the `new
+    Volume Transfers API
+    <https://docs.openstack.org/api-ref/block-storage/v3/#volume-transfers-volume-transfers-3-55-or-later>`_
+    of the Block Storage API v3.  The min_microversion of this API is 3.55.
diff --git a/tempest/api/volume/test_volume_transfers.py b/tempest/api/volume/test_volume_transfers.py
index 3eb81f5..9600aa9 100644
--- a/tempest/api/volume/test_volume_transfers.py
+++ b/tempest/api/volume/test_volume_transfers.py
@@ -104,3 +104,30 @@
         self.client.delete_volume_transfer(transfer_id)
         waiters.wait_for_volume_resource_status(
             self.volumes_client, volume['id'], 'available')
+
+
+class VolumesTransfersV355Test(VolumesTransfersTest):
+    """Test volume transfer for the "new" Transfers API mv 3.55"""
+
+    min_microversion = '3.55'
+    max_microversion = 'latest'
+
+    credentials = ['primary', 'alt', 'admin']
+
+    @classmethod
+    def setup_clients(cls):
+        super(VolumesTransfersV355Test, cls).setup_clients()
+        cls.client = cls.os_primary.volume_transfers_mv355_client_latest
+        cls.alt_client = cls.os_alt.volume_transfers_mv355_client_latest
+
+    @decorators.idempotent_id('9f36bb2b-619f-4507-b246-76aeb9a28851')
+    def test_create_get_list_accept_volume_transfer(self):
+        """Test create, get, list, accept with volume-transfers API mv 3.55"""
+        super(VolumesTransfersV355Test, self). \
+            test_create_get_list_accept_volume_transfer()
+
+    @decorators.idempotent_id('af4a5b97-0859-4f31-aa3c-85b05bb63322')
+    def test_create_list_delete_volume_transfer(self):
+        """Test create, list, delete with volume-transfers API mv 3.55"""
+        super(VolumesTransfersV355Test, self). \
+            test_create_list_delete_volume_transfer()
diff --git a/tempest/clients.py b/tempest/clients.py
index 6807fc4..6080f01 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -264,6 +264,8 @@
             self.volume_v3.SchedulerStatsClient()
         self.volume_transfers_client_latest = \
             self.volume_v3.TransfersClient()
+        self.volume_transfers_mv355_client_latest = \
+            self.volume_v3.TransfersV355Client()
         self.volume_availability_zone_client_latest = \
             self.volume_v3.AvailabilityZoneClient()
         self.volume_limits_client_latest = self.volume_v3.LimitsClient()
diff --git a/tempest/lib/services/volume/v3/__init__.py b/tempest/lib/services/volume/v3/__init__.py
index e2fa836..039640b 100644
--- a/tempest/lib/services/volume/v3/__init__.py
+++ b/tempest/lib/services/volume/v3/__init__.py
@@ -39,6 +39,7 @@
     SnapshotManageClient
 from tempest.lib.services.volume.v3.snapshots_client import SnapshotsClient
 from tempest.lib.services.volume.v3.transfers_client import TransfersClient
+from tempest.lib.services.volume.v3.transfers_client import TransfersV355Client
 from tempest.lib.services.volume.v3.types_client import TypesClient
 from tempest.lib.services.volume.v3.versions_client import VersionsClient
 from tempest.lib.services.volume.v3.volume_manage_client import \
@@ -50,5 +51,6 @@
            'GroupsClient', 'HostsClient', 'LimitsClient', 'MessagesClient',
            'QosSpecsClient', 'QuotaClassesClient', 'QuotasClient',
            'SchedulerStatsClient', 'ServicesClient', 'SnapshotManageClient',
-           'SnapshotsClient', 'TransfersClient', 'TypesClient',
-           'VersionsClient', 'VolumeManageClient', 'VolumesClient']
+           'SnapshotsClient', 'TransfersClient', 'TransfersV355Client',
+           'TypesClient', 'VersionsClient', 'VolumeManageClient',
+           'VolumesClient']
diff --git a/tempest/lib/services/volume/v3/transfers_client.py b/tempest/lib/services/volume/v3/transfers_client.py
index 36198c3..cc4e1b2 100644
--- a/tempest/lib/services/volume/v3/transfers_client.py
+++ b/tempest/lib/services/volume/v3/transfers_client.py
@@ -24,6 +24,8 @@
 class TransfersClient(rest_client.RestClient):
     """Client class to send CRUD Volume Transfer API requests"""
 
+    resource_path = 'os-volume-transfer'
+
     def create_volume_transfer(self, **kwargs):
         """Create a volume transfer.
 
@@ -32,14 +34,14 @@
         https://docs.openstack.org/api-ref/block-storage/v3/index.html#create-a-volume-transfer
         """
         post_body = json.dumps({'transfer': kwargs})
-        resp, body = self.post('os-volume-transfer', post_body)
+        resp, body = self.post(self.resource_path, post_body)
         body = json.loads(body)
         self.validate_response(schema.create_volume_transfer, resp, body)
         return rest_client.ResponseBody(resp, body)
 
     def show_volume_transfer(self, transfer_id):
         """Returns the details of a volume transfer."""
-        url = "os-volume-transfer/%s" % transfer_id
+        url = "%s/%s" % (self.resource_path, transfer_id)
         resp, body = self.get(url)
         body = json.loads(body)
         self.validate_response(schema.show_volume_transfer, resp, body)
@@ -53,7 +55,7 @@
         https://docs.openstack.org/api-ref/block-storage/v3/index.html#list-volume-transfers-for-a-project
         https://docs.openstack.org/api-ref/block-storage/v3/index.html#list-volume-transfers-and-details
         """
-        url = 'os-volume-transfer'
+        url = self.resource_path
         schema_list_transfers = schema.list_volume_transfers_no_detail
         if detail:
             url += '/detail'
@@ -67,7 +69,7 @@
 
     def delete_volume_transfer(self, transfer_id):
         """Delete a volume transfer."""
-        resp, body = self.delete("os-volume-transfer/%s" % transfer_id)
+        resp, body = self.delete("%s/%s" % (self.resource_path, transfer_id))
         self.validate_response(schema.delete_volume_transfer, resp, body)
         return rest_client.ResponseBody(resp, body)
 
@@ -78,9 +80,14 @@
         API reference:
         https://docs.openstack.org/api-ref/block-storage/v3/index.html#accept-a-volume-transfer
         """
-        url = 'os-volume-transfer/%s/accept' % transfer_id
+        url = '%s/%s/accept' % (self.resource_path, transfer_id)
         post_body = json.dumps({'accept': kwargs})
         resp, body = self.post(url, post_body)
         body = json.loads(body)
         self.validate_response(schema.accept_volume_transfer, resp, body)
         return rest_client.ResponseBody(resp, body)
+
+
+class TransfersV355Client(TransfersClient):
+    """Client class to send CRUD for the "new" Transfers API (mv 3.55)"""
+    resource_path = 'volume-transfers'
diff --git a/tempest/tests/lib/services/volume/v3/test_transfers_client.py b/tempest/tests/lib/services/volume/v3/test_transfers_client.py
index 1dfe2df..3626184 100644
--- a/tempest/tests/lib/services/volume/v3/test_transfers_client.py
+++ b/tempest/tests/lib/services/volume/v3/test_transfers_client.py
@@ -52,6 +52,7 @@
         self.client = transfers_client.TransfersClient(fake_auth,
                                                        'volume',
                                                        'regionOne')
+        self.resource_path = 'os-volume-transfer'
 
     def _test_create_volume_transfer(self, bytes_body=False):
         resp_body = copy.deepcopy(self.FAKE_VOLUME_TRANSFER_INFO)
@@ -72,7 +73,7 @@
                 resp_body,
                 to_utf=bytes_body,
                 status=202,
-                mock_args=['os-volume-transfer', payload],
+                mock_args=[self.resource_path, payload],
                 **kwargs)
 
     def _test_accept_volume_transfer(self, bytes_body=False):
@@ -93,8 +94,9 @@
                 resp_body,
                 to_utf=bytes_body,
                 status=202,
-                mock_args=['os-volume-transfer/%s/accept' %
-                           self.FAKE_VOLUME_TRANSFER_ID, payload],
+                mock_args=['%s/%s/accept' % (self.resource_path,
+                                             self.FAKE_VOLUME_TRANSFER_ID),
+                           payload],
                 transfer_id=self.FAKE_VOLUME_TRANSFER_ID,
                 **kwargs)
 
@@ -156,3 +158,14 @@
             {},
             status=202,
             transfer_id="0e89cdd1-6249-421b-96d8-25fac0623d42")
+
+
+class TestTransfersV355Client(TestTransfersClient):
+
+    def setUp(self):
+        super(TestTransfersV355Client, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = transfers_client.TransfersV355Client(fake_auth,
+                                                           'volume',
+                                                           'regionOne')
+        self.resource_path = 'volume-transfers'