Merge "Make credentials_factory a bit nicer"
diff --git a/HACKING.rst b/HACKING.rst
index dbb758b..77a8612 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -2,7 +2,7 @@
 ====================
 
 - Step 1: Read the OpenStack Style Commandments
-  http://docs.openstack.org/developer/hacking/
+  https://docs.openstack.org/hacking/latest/
 - Step 2: Read on
 
 Tempest Specific Commandments
diff --git a/README.rst b/README.rst
index ac93992..a7eab2f 100644
--- a/README.rst
+++ b/README.rst
@@ -11,7 +11,7 @@
 ==============================================
 
 The documentation for Tempest is officially hosted at:
-http://docs.openstack.org/developer/tempest/
+https://docs.openstack.org/tempest/latest/
 
 This is a set of integration tests to be run against a live OpenStack
 cluster. Tempest has batteries of tests for OpenStack API validation,
@@ -117,7 +117,7 @@
    will run the same set of tests as the default gate jobs.
 
 .. _testr: https://testrepository.readthedocs.org/en/latest/MANUAL.html
-.. _ostestr: http://docs.openstack.org/developer/os-testr/
+.. _ostestr: https://docs.openstack.org/os-testr/latest/
 
 Library
 -------
diff --git a/REVIEWING.rst b/REVIEWING.rst
index 9b272bb..5807d50 100644
--- a/REVIEWING.rst
+++ b/REVIEWING.rst
@@ -91,7 +91,7 @@
 anything backwards incompatible or would require a user to take note or do
 something extra.
 
-.. _reno: http://docs.openstack.org/developer/reno/
+.. _reno: https://docs.openstack.org/reno/latest/
 
 Deprecated Code
 ---------------
diff --git a/doc/source/microversion_testing.rst b/doc/source/microversion_testing.rst
index d6d90ba..60f4f36 100644
--- a/doc/source/microversion_testing.rst
+++ b/doc/source/microversion_testing.rst
@@ -111,7 +111,7 @@
 This document explains how to implement Microversion tests using those
 interfaces.
 
-.. _API Microversion testing Framework: http://docs.openstack.org/developer/tempest/library/api_microversion_testing.html
+.. _API Microversion testing Framework: https://docs.openstack.org/tempest/latest/library/api_microversion_testing.html
 
 
 Step1: Add skip logic based on configured Microversion range
@@ -296,46 +296,46 @@
 
  * `2.1`_
 
- .. _2.1:  http://docs.openstack.org/developer/nova/api_microversion_history.html#id1
+ .. _2.1:  https://docs.openstack.org/nova/latest/api_microversion_history.html#id1
 
  * `2.2`_
 
- .. _2.2: http://docs.openstack.org/developer/nova/api_microversion_history.html#id2
+ .. _2.2: http://docs.openstack.org/nova/latest/api_microversion_history.html#id2
 
  * `2.10`_
 
- .. _2.10: http://docs.openstack.org/developer/nova/api_microversion_history.html#id9
+ .. _2.10: http://docs.openstack.org/nova/latest/api_microversion_history.html#id9
 
  * `2.20`_
 
- .. _2.20: http://docs.openstack.org/developer/nova/api_microversion_history.html#id18
+ .. _2.20: http://docs.openstack.org/nova/latest/api_microversion_history.html#id18
 
  * `2.25`_
 
- .. _2.25: http://docs.openstack.org/developer/nova/api_microversion_history.html#maximum-in-mitaka
+ .. _2.25: http://docs.openstack.org/nova/latest/api_microversion_history.html#maximum-in-mitaka
 
  * `2.32`_
 
- .. _2.32: http://docs.openstack.org/developer/nova/api_microversion_history.html#id29
+ .. _2.32: http://docs.openstack.org/nova/latest/api_microversion_history.html#id29
 
  * `2.37`_
 
- .. _2.37: http://docs.openstack.org/developer/nova/api_microversion_history.html#id34
+ .. _2.37: http://docs.openstack.org/nova/latest/api_microversion_history.html#id34
 
  * `2.42`_
 
- .. _2.42: http://docs.openstack.org/developer/nova/api_microversion_history.html#maximum-in-ocata
+ .. _2.42: http://docs.openstack.org/nova/latest/api_microversion_history.html#maximum-in-ocata
 
  * `2.47`_
 
- .. _2.47: http://docs.openstack.org/developer/nova/api_microversion_history.html#id42
+ .. _2.47: http://docs.openstack.org/nova/latest/api_microversion_history.html#id42
 
  * `2.48`_
 
- .. _2.48: http://docs.openstack.org/developer/nova/api_microversion_history.html#id43
+ .. _2.48: http://docs.openstack.org/nova/latest/api_microversion_history.html#id43
 
 * Volume
 
  * `3.3`_
 
- .. _3.3:  https://docs.openstack.org/developer/cinder/devref/api_microversion_history.html#id4
+ .. _3.3:  https://docs.openstack.org/cinder/latest/devref/api_microversion_history.html#id4
diff --git a/doc/source/test_removal.rst b/doc/source/test_removal.rst
index d06e4ba..07c3046 100644
--- a/doc/source/test_removal.rst
+++ b/doc/source/test_removal.rst
@@ -171,7 +171,7 @@
 `tempest plugin mechanism`_
 to maintain continuity after migrating the tests out of tempest.
 
-.. _tempest plugin mechanism: http://docs.openstack.org/developer/tempest/plugin.html
+.. _tempest plugin mechanism: https://docs.openstack.org/tempest/latest/plugin.html
 
 API Compatibility
 """""""""""""""""
diff --git a/releasenotes/notes/10/10.0.0-Tempest-library-interface-0eb680b810139a50.yaml b/releasenotes/notes/10/10.0.0-Tempest-library-interface-0eb680b810139a50.yaml
index 0ed3130..c1edd63 100644
--- a/releasenotes/notes/10/10.0.0-Tempest-library-interface-0eb680b810139a50.yaml
+++ b/releasenotes/notes/10/10.0.0-Tempest-library-interface-0eb680b810139a50.yaml
@@ -5,7 +5,7 @@
     it lives directly in the tempest project. For more information refer to
     the `library docs`_.
 
-    .. _library docs: http://docs.openstack.org/developer/tempest/library.html#library
+    .. _library docs: https://docs.openstack.org/tempest/latest/library.html#current-library-apis
 
 features:
   - Tempest library interface
diff --git a/setup.cfg b/setup.cfg
index b292970..f52137e 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -5,7 +5,7 @@
     README.rst
 author = OpenStack
 author-email = openstack-dev@lists.openstack.org
-home-page = http://docs.openstack.org/developer/tempest/
+home-page = https://docs.openstack.org/tempest/latest/
 classifier =
     Intended Audience :: Information Technology
     Intended Audience :: System Administrators
diff --git a/tempest/services/object_storage/bulk_middleware_client.py b/tempest/services/object_storage/bulk_middleware_client.py
index c194ea9..83d2d80 100644
--- a/tempest/services/object_storage/bulk_middleware_client.py
+++ b/tempest/services/object_storage/bulk_middleware_client.py
@@ -24,7 +24,7 @@
 
         To extract containers and objects on Swift cluster from
         uploaded archived file. For More information please check:
-        http://docs.openstack.org/developer/swift/middleware.html#module-swift.common.middleware.bulk
+        https://docs.openstack.org/swift/latest/middleware.html#module-swift.common.middleware.bulk
         """
         url = '%s?extract-archive=%s' % (upload_path, archive_file_format)
         if headers is None:
@@ -37,7 +37,7 @@
         """Delete multiple objects or containers from their account.
 
         For More information please check:
-        http://docs.openstack.org/developer/swift/middleware.html#module-swift.common.middleware.bulk
+        https://docs.openstack.org/swift/latest/middleware.html#module-swift.common.middleware.bulk
         """
         url = '?bulk-delete'
 
@@ -51,7 +51,7 @@
         """Delete multiple objects or containers with POST request.
 
         For More information please check:
-        http://docs.openstack.org/developer/swift/middleware.html#module-swift.common.middleware.bulk
+        https://docs.openstack.org/swift/latest/middleware.html#module-swift.common.middleware.bulk
         """
         url = '?bulk-delete'
 
diff --git a/tempest/tests/lib/services/volume/v2/test_snapshot_manage_client.py b/tempest/tests/lib/services/volume/v2/test_snapshot_manage_client.py
new file mode 100644
index 0000000..3fe8970
--- /dev/null
+++ b/tempest/tests/lib/services/volume/v2/test_snapshot_manage_client.py
@@ -0,0 +1,83 @@
+# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD
+# All Rights Reserved.
+#
+#    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.
+
+import mock
+
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.services.volume.v2 import snapshot_manage_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestSnapshotManageClient(base.BaseServiceTest):
+
+    SNAPSHOT_MANAGE_REQUEST = {
+        "snapshot": {
+            "description": "snapshot-manage-description",
+            "metadata": None,
+            "ref": {
+                "source-name": "_snapshot-22b71da0-94f9-4aca-ad45-7522b3fa96bb"
+            },
+            "name": "snapshot-managed",
+            "volume_id": "7c064b34-1e4b-40bd-93ca-4ac5a973661b"
+        }
+    }
+
+    SNAPSHOT_MANAGE_RESPONSE = {
+        "snapshot": {
+            "status": "creating",
+            "description": "snapshot-manage-description",
+            "updated_at": None,
+            "volume_id": "32bafcc8-7109-42cd-8342-70d8de2bedef",
+            "id": "8fd6eb9d-0a82-456d-b1ec-dea4ac7f1ee2",
+            "size": 1,
+            "name": "snapshot-managed",
+            "created_at": "2017-07-11T10:07:58.000000",
+            "metadata": {}
+        }
+    }
+
+    def setUp(self):
+        super(TestSnapshotManageClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = snapshot_manage_client.SnapshotManageClient(fake_auth,
+                                                                  'volume',
+                                                                  'regionOne')
+
+    def _test_manage_snapshot(self, bytes_body=False):
+        payload = json.dumps(self.SNAPSHOT_MANAGE_REQUEST, sort_keys=True)
+        json_dumps = json.dumps
+
+        # NOTE: Use sort_keys for json.dumps so that the expected and actual
+        # payloads are guaranteed to be identical for mock_args assert check.
+        with mock.patch.object(snapshot_manage_client.json,
+                               'dumps') as mock_dumps:
+            mock_dumps.side_effect = lambda d: json_dumps(d, sort_keys=True)
+
+            self.check_service_client_function(
+                self.client.manage_snapshot,
+                'tempest.lib.common.rest_client.RestClient.post',
+                self.SNAPSHOT_MANAGE_RESPONSE,
+                to_utf=bytes_body,
+                status=202,
+                mock_args=['os-snapshot-manage', payload],
+                **self.SNAPSHOT_MANAGE_REQUEST['snapshot'])
+
+    def test_manage_snapshot_with_str_body(self):
+        self._test_manage_snapshot()
+
+    def test_manage_snapshot_with_bytes_body(self):
+        self._test_manage_snapshot(bytes_body=True)
diff --git a/tempest/tests/lib/services/volume/v2/test_volume_manage_client.py b/tempest/tests/lib/services/volume/v2/test_volume_manage_client.py
new file mode 100644
index 0000000..ea4a9f9
--- /dev/null
+++ b/tempest/tests/lib/services/volume/v2/test_volume_manage_client.py
@@ -0,0 +1,111 @@
+# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD
+# All Rights Reserved.
+#
+#    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.
+
+import mock
+
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.services.volume.v2 import volume_manage_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestVolumeManageClient(base.BaseServiceTest):
+
+    VOLUME_MANAGE_REQUEST = {
+        "volume": {
+            "host": "controller1@rbd#rbd",
+            "name": "volume-managed",
+            "availability_zone": "nova",
+            "bootable": False,
+            "metadata": None,
+            "ref": {
+                "source-name": "volume-2ce6ca46-e6c1-4fe5-8268-3a1c536fcbf3"
+            },
+            "volume_type": None,
+            "description": "volume-manage-description"
+        }
+    }
+
+    VOLUME_MANAGE_RESPONSE = {
+        "volume": {
+            "migration_status": None,
+            "attachments": [],
+            "links": [
+                {
+                    "href": "fake-url-1",
+                    "rel": "self"
+                },
+                {
+                    "href": "fake-url-2",
+                    "rel": "bookmark"
+                }
+            ],
+            "availability_zone": "nova",
+            "os-vol-host-attr:host": "controller1@rbd#rbd",
+            "encrypted": False,
+            "updated_at": None,
+            "replication_status": None,
+            "snapshot_id": None,
+            "id": "c07cd4a4-b52b-4511-a176-fbaa2011a227",
+            "size": 0,
+            "user_id": "142d8663efce464c89811c63e45bd82e",
+            "os-vol-tenant-attr:tenant_id": "f21a9c86d7114bf99c711f4874d80474",
+            "os-vol-mig-status-attr:migstat": None,
+            "metadata": {},
+            "status": "creating",
+            "description": "volume-manage-description",
+            "multiattach": False,
+            "source_volid": None,
+            "consistencygroup_id": None,
+            "os-vol-mig-status-attr:name_id": None,
+            "name": "volume-managed",
+            "bootable": "false",
+            "created_at": "2017-07-11T09:14:01.000000",
+            "volume_type": None
+        }
+    }
+
+    def setUp(self):
+        super(TestVolumeManageClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = volume_manage_client.VolumeManageClient(fake_auth,
+                                                              'volume',
+                                                              'regionOne')
+
+    def _test_manage_volume(self, bytes_body=False):
+        payload = json.dumps(self.VOLUME_MANAGE_REQUEST, sort_keys=True)
+        json_dumps = json.dumps
+
+        # NOTE: Use sort_keys for json.dumps so that the expected and actual
+        # payloads are guaranteed to be identical for mock_args assert check.
+        with mock.patch.object(volume_manage_client.json,
+                               'dumps') as mock_dumps:
+            mock_dumps.side_effect = lambda d: json_dumps(d, sort_keys=True)
+
+            self.check_service_client_function(
+                self.client.manage_volume,
+                'tempest.lib.common.rest_client.RestClient.post',
+                self.VOLUME_MANAGE_RESPONSE,
+                to_utf=bytes_body,
+                status=202,
+                mock_args=['os-volume-manage', payload],
+                **self.VOLUME_MANAGE_REQUEST['volume'])
+
+    def test_manage_volume_with_str_body(self):
+        self._test_manage_volume()
+
+    def test_manage_volume_with_bytes_body(self):
+        self._test_manage_volume(bytes_body=True)