Merge "Fix with using oslo_serialization base64 module"
diff --git a/releasenotes/notes/12.3.0-volume-clients-as-library-660811011be29d1a.yaml b/releasenotes/notes/12.3.0-volume-clients-as-library-660811011be29d1a.yaml
new file mode 100644
index 0000000..9e9eff6
--- /dev/null
+++ b/releasenotes/notes/12.3.0-volume-clients-as-library-660811011be29d1a.yaml
@@ -0,0 +1,6 @@
+---
+features:
+  - |
+    Define the v1 and v2 types_client clients for the volume service as
+    library interfaces, allowing other projects to use these modules as
+    stable libraries without maintenance changes.
diff --git a/run_tempest.sh b/run_tempest.sh
index af01734..414146b 100755
--- a/run_tempest.sh
+++ b/run_tempest.sh
@@ -1,5 +1,7 @@
 #!/usr/bin/env bash
 
+echo "WARNING: This script is deprecated and will be removed in the near future. Please migrate to tempest run or another method of launching a test runner"
+
 function usage {
   echo "Usage: $0 [OPTION]..."
   echo "Run Tempest test suite"
diff --git a/tempest/api/compute/admin/test_aggregates.py b/tempest/api/compute/admin/test_aggregates.py
index fbcc1d1..667d30b 100644
--- a/tempest/api/compute/admin/test_aggregates.py
+++ b/tempest/api/compute/admin/test_aggregates.py
@@ -215,10 +215,8 @@
         self.client.add_host(aggregate['id'], host=self.host)
         self.addCleanup(self.client.remove_host, aggregate['id'],
                         host=self.host)
-        server_name = data_utils.rand_name('test_server')
         admin_servers_client = self.os_adm.servers_client
-        server = self.create_test_server(name=server_name,
-                                         availability_zone=az_name,
+        server = self.create_test_server(availability_zone=az_name,
                                          wait_until='ACTIVE')
         body = admin_servers_client.show_server(server['id'])['server']
         self.assertEqual(self.host, body['OS-EXT-SRV-ATTR:host'])
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 5e75493..27afff3 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -219,6 +219,8 @@
         :param validatable: Whether the server will be pingable or sshable.
         :param volume_backed: Whether the instance is volume backed or not.
         """
+        if 'name' not in kwargs:
+            kwargs['name'] = data_utils.rand_name(cls.__name__ + "-server")
         tenant_network = cls.get_tenant_network()
         body, servers = compute.create_test_server(
             cls.os,
diff --git a/tempest/api/compute/security_groups/test_security_groups.py b/tempest/api/compute/security_groups/test_security_groups.py
index f6353c8..755336f 100644
--- a/tempest/api/compute/security_groups/test_security_groups.py
+++ b/tempest/api/compute/security_groups/test_security_groups.py
@@ -94,8 +94,7 @@
 
         # Create server and add the security group created
         # above to the server we just created
-        server_name = data_utils.rand_name('server')
-        server = self.create_test_server(name=server_name)
+        server = self.create_test_server()
         server_id = server['id']
         waiters.wait_for_server_status(self.servers_client, server_id,
                                        'ACTIVE')
diff --git a/tempest/api/identity/admin/v3/test_credentials.py b/tempest/api/identity/admin/v3/test_credentials.py
index 12b236f..a0d8748 100644
--- a/tempest/api/identity/admin/v3/test_credentials.py
+++ b/tempest/api/identity/admin/v3/test_credentials.py
@@ -12,6 +12,7 @@
 #    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 oslo_serialization import jsonutils as json
 
 from tempest.api.identity import base
 from tempest.common.utils import data_utils
@@ -70,6 +71,7 @@
         update_body = self.creds_client.update_credential(
             cred['id'], blob=blob, project_id=self.projects[1],
             type='ec2')['credential']
+        update_body['blob'] = json.loads(update_body['blob'])
         self.assertEqual(cred['id'], update_body['id'])
         self.assertEqual(self.projects[1], update_body['project_id'])
         self.assertEqual(self.user_body['id'], update_body['user_id'])
@@ -77,6 +79,7 @@
         self.assertEqual(update_body['blob']['secret'], new_keys[1])
 
         get_body = self.creds_client.show_credential(cred['id'])['credential']
+        get_body['blob'] = json.loads(get_body['blob'])
         for value1 in self.creds_list[0]:
             self.assertEqual(update_body[value1],
                              get_body[value1])
diff --git a/tempest/api/network/admin/test_quotas.py b/tempest/api/network/admin/test_quotas.py
index 2ff31e0..3a264ff 100644
--- a/tempest/api/network/admin/test_quotas.py
+++ b/tempest/api/network/admin/test_quotas.py
@@ -87,5 +87,5 @@
 
     @test.idempotent_id('2390f766-836d-40ef-9aeb-e810d78207fb')
     def test_quotas(self):
-        new_quotas = {'network': 0, 'security_group': 0}
+        new_quotas = {'network': 0, 'port': 0}
         self._check_quotas(new_quotas)
diff --git a/tempest/lib/services/identity/v3/credentials_client.py b/tempest/lib/services/identity/v3/credentials_client.py
index 8c04d2c..6e5fd31 100644
--- a/tempest/lib/services/identity/v3/credentials_client.py
+++ b/tempest/lib/services/identity/v3/credentials_client.py
@@ -37,7 +37,6 @@
         resp, body = self.post('credentials', post_body)
         self.expected_success(201, resp.status)
         body = json.loads(body)
-        body['credential']['blob'] = json.loads(body['credential']['blob'])
         return rest_client.ResponseBody(resp, body)
 
     def update_credential(self, credential_id, **kwargs):
@@ -51,7 +50,6 @@
         resp, body = self.patch('credentials/%s' % credential_id, post_body)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        body['credential']['blob'] = json.loads(body['credential']['blob'])
         return rest_client.ResponseBody(resp, body)
 
     def show_credential(self, credential_id):
@@ -64,7 +62,6 @@
         resp, body = self.get('credentials/%s' % credential_id)
         self.expected_success(200, resp.status)
         body = json.loads(body)
-        body['credential']['blob'] = json.loads(body['credential']['blob'])
         return rest_client.ResponseBody(resp, body)
 
     def list_credentials(self, **params):
diff --git a/tempest/services/volume/v1/json/encryption_types_client.py b/tempest/lib/services/volume/v1/encryption_types_client.py
similarity index 100%
rename from tempest/services/volume/v1/json/encryption_types_client.py
rename to tempest/lib/services/volume/v1/encryption_types_client.py
diff --git a/tempest/services/volume/v1/json/admin/types_client.py b/tempest/lib/services/volume/v1/types_client.py
similarity index 100%
rename from tempest/services/volume/v1/json/admin/types_client.py
rename to tempest/lib/services/volume/v1/types_client.py
diff --git a/tempest/services/volume/v2/json/admin/types_client.py b/tempest/lib/services/volume/v2/types_client.py
similarity index 100%
rename from tempest/services/volume/v2/json/admin/types_client.py
rename to tempest/lib/services/volume/v2/types_client.py
diff --git a/tempest/scenario/test_minimum_basic.py b/tempest/scenario/test_minimum_basic.py
index dba1c92..a67927a 100644
--- a/tempest/scenario/test_minimum_basic.py
+++ b/tempest/scenario/test_minimum_basic.py
@@ -96,6 +96,13 @@
                    '%s' % (secgroup['id'], server['id']))
             raise exceptions.TimeoutException(msg)
 
+    def _get_floating_ip_in_server_addresses(self, floating_ip, server):
+        for network_name, addresses in server['addresses'].items():
+            for address in addresses:
+                if (address['OS-EXT-IPS:type'] == 'floating' and
+                        address['addr'] == floating_ip['ip']):
+                    return address
+
     @test.idempotent_id('bdbb5441-9204-419d-a225-b4fdbfb1a1a8')
     @test.services('compute', 'volume', 'image', 'network')
     def test_minimum_basic_scenario(self):
@@ -121,6 +128,16 @@
         self.cinder_show(volume)
 
         floating_ip = self.create_floating_ip(server)
+        # fetch the server again to make sure the addresses were refreshed
+        # after associating the floating IP
+        server = self.servers_client.show_server(server['id'])['server']
+        address = self._get_floating_ip_in_server_addresses(
+            floating_ip, server)
+        self.assertIsNotNone(
+            address,
+            "Failed to find floating IP '%s' in server addresses: %s" %
+            (floating_ip['ip'], server['addresses']))
+
         self.create_and_add_security_group_to_server(server)
 
         # check that we can SSH to the server before reboot
@@ -135,3 +152,13 @@
             floating_ip['ip'], private_key=keypair['private_key'])
 
         self.check_partitions()
+
+        # delete the floating IP, this should refresh the server addresses
+        self.compute_floating_ips_client.delete_floating_ip(floating_ip['id'])
+        server = self.servers_client.show_server(server['id'])['server']
+        address = self._get_floating_ip_in_server_addresses(
+            floating_ip, server)
+        self.assertIsNone(
+            address,
+            "Floating IP '%s' should not be in server addresses: %s" %
+            (floating_ip['ip'], server['addresses']))
diff --git a/tempest/services/volume/v1/__init__.py b/tempest/services/volume/v1/__init__.py
index 72868bc..a7d9270 100644
--- a/tempest/services/volume/v1/__init__.py
+++ b/tempest/services/volume/v1/__init__.py
@@ -14,19 +14,19 @@
 
 from tempest.lib.services.volume.v1.availability_zone_client import \
     AvailabilityZoneClient
+from tempest.lib.services.volume.v1.encryption_types_client import \
+    EncryptionTypesClient
 from tempest.lib.services.volume.v1.extensions_client import ExtensionsClient
 from tempest.lib.services.volume.v1.hosts_client import HostsClient
 from tempest.lib.services.volume.v1.quotas_client import QuotasClient
 from tempest.lib.services.volume.v1.services_client import ServicesClient
-from tempest.services.volume.v1.json.admin.types_client import TypesClient
+from tempest.lib.services.volume.v1.types_client import TypesClient
 from tempest.services.volume.v1.json.backups_client import BackupsClient
-from tempest.services.volume.v1.json.encryption_types_client import \
-    EncryptionTypesClient
 from tempest.services.volume.v1.json.qos_client import QosSpecsClient
 from tempest.services.volume.v1.json.snapshots_client import SnapshotsClient
 from tempest.services.volume.v1.json.volumes_client import VolumesClient
 
-__all__ = ['HostsClient', 'QuotasClient', 'ServicesClient', 'TypesClient',
-           'AvailabilityZoneClient', 'BackupsClient', 'ExtensionsClient',
-           'QosSpecsClient', 'SnapshotsClient', 'VolumesClient',
-           'EncryptionTypesClient']
+__all__ = ['AvailabilityZoneClient', 'EncryptionTypesClient',
+           'ExtensionsClient', 'HostsClient', 'QuotasClient', 'ServicesClient',
+           'TypesClient', 'BackupsClient', 'QosSpecsClient', 'SnapshotsClient',
+           'VolumesClient', ]
diff --git a/tempest/services/volume/v2/__init__.py b/tempest/services/volume/v2/__init__.py
index 4afcc29..c99a81a 100644
--- a/tempest/services/volume/v2/__init__.py
+++ b/tempest/services/volume/v2/__init__.py
@@ -18,7 +18,7 @@
 from tempest.lib.services.volume.v2.hosts_client import HostsClient
 from tempest.lib.services.volume.v2.quotas_client import QuotasClient
 from tempest.lib.services.volume.v2.services_client import ServicesClient
-from tempest.services.volume.v2.json.admin.types_client import TypesClient
+from tempest.lib.services.volume.v2.types_client import TypesClient
 from tempest.services.volume.v2.json.backups_client import BackupsClient
 from tempest.services.volume.v2.json.encryption_types_client import \
     EncryptionTypesClient
@@ -26,7 +26,7 @@
 from tempest.services.volume.v2.json.snapshots_client import SnapshotsClient
 from tempest.services.volume.v2.json.volumes_client import VolumesClient
 
-__all__ = ['HostsClient', 'QuotasClient', 'ServicesClient', 'TypesClient',
-           'AvailabilityZoneClient', 'BackupsClient', 'ExtensionsClient',
-           'QosSpecsClient', 'SnapshotsClient', 'VolumesClient',
-           'EncryptionTypesClient']
+__all__ = ['AvailabilityZoneClient', 'ExtensionsClient', 'HostsClient',
+           'QuotasClient', 'ServicesClient', 'TypesClient', 'BackupsClient',
+           'EncryptionTypesClient', 'QosSpecsClient', 'SnapshotsClient',
+           'VolumesClient', ]
diff --git a/tempest/tests/lib/services/base.py b/tempest/tests/lib/services/base.py
index 3165689..a244aa2 100644
--- a/tempest/tests/lib/services/base.py
+++ b/tempest/tests/lib/services/base.py
@@ -12,7 +12,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import copy
 from oslo_serialization import jsonutils as json
 from oslotest import mockpatch
 
@@ -32,7 +31,7 @@
 
     def check_service_client_function(self, function, function2mock,
                                       body, to_utf=False, status=200,
-                                      headers=None, cr_blob=False, **kwargs):
+                                      headers=None, **kwargs):
         mocked_response = self.create_response(body, to_utf, status, headers)
         self.useFixture(mockpatch.Patch(
             function2mock, return_value=mocked_response))
@@ -40,11 +39,4 @@
             resp = function(**kwargs)
         else:
             resp = function()
-
-        if cr_blob:
-            evaluated_body = copy.deepcopy(body)
-            nested_json = json.loads(evaluated_body['credential']['blob'])
-            evaluated_body['credential']['blob'] = nested_json
-            self.assertEqual(evaluated_body, resp)
-        else:
-            self.assertEqual(body, resp)
+        self.assertEqual(body, resp)
diff --git a/tempest/tests/lib/services/identity/v3/test_credentials_client.py b/tempest/tests/lib/services/identity/v3/test_credentials_client.py
index a2a22ff..29d7496 100644
--- a/tempest/tests/lib/services/identity/v3/test_credentials_client.py
+++ b/tempest/tests/lib/services/identity/v3/test_credentials_client.py
@@ -121,14 +121,14 @@
             self.client.create_credential,
             'tempest.lib.common.rest_client.RestClient.post',
             self.FAKE_CREATE_CREDENTIAL,
-            bytes_body, status=201, cr_blob=True)
+            bytes_body, status=201)
 
     def _test_show_credential(self, bytes_body=False):
         self.check_service_client_function(
             self.client.show_credential,
             'tempest.lib.common.rest_client.RestClient.get',
             self.FAKE_INFO_CREDENTIAL,
-            bytes_body, cr_blob=True,
+            bytes_body,
             credential_id="207e9b76935efc03804d3dd6ab52d22e9b22a0711e4ada4f")
 
     def _test_update_credential(self, bytes_body=False):
@@ -136,7 +136,7 @@
             self.client.update_credential,
             'tempest.lib.common.rest_client.RestClient.patch',
             self.FAKE_INFO_CREDENTIAL,
-            bytes_body, cr_blob=True,
+            bytes_body,
             credential_id="207e9b76935efc03804d3dd6ab52d22e9b22a0711e4ada4f")
 
     def _test_list_credentials(self, bytes_body=False):
diff --git a/tools/pretty_tox.sh b/tools/pretty_tox.sh
index fb4e6d5..0b83b91 100755
--- a/tools/pretty_tox.sh
+++ b/tools/pretty_tox.sh
@@ -1,5 +1,7 @@
 #!/usr/bin/env bash
 
+echo "WARNING: This script is deprecated and will be removed in the near future. Please migrate to tempest run or another method of launching a test runner"
+
 set -o pipefail
 
 TESTRARGS=$1
diff --git a/tools/pretty_tox_serial.sh b/tools/pretty_tox_serial.sh
index e0fca0f..1f8204e 100755
--- a/tools/pretty_tox_serial.sh
+++ b/tools/pretty_tox_serial.sh
@@ -1,5 +1,7 @@
 #!/usr/bin/env bash
 
+echo "WARNING: This script is deprecated and will be removed in the near future. Please migrate to tempest run or another method of launching a test runner"
+
 set -o pipefail
 
 TESTRARGS=$@
diff --git a/tox.ini b/tox.ini
index a621492..05fa326 100644
--- a/tox.ini
+++ b/tox.ini
@@ -44,7 +44,7 @@
 deps = {[tempestenv]deps}
 commands =
     find . -type f -name "*.pyc" -delete
-    bash tools/pretty_tox.sh '{posargs}'
+    tempest run --regex {posargs}
 
 [testenv:ostestr]
 sitepackages = {[tempestenv]sitepackages}
@@ -66,7 +66,7 @@
 deps = {[tempestenv]deps}
 commands =
     find . -type f -name "*.pyc" -delete
-    bash tools/pretty_tox.sh '{posargs}'
+    tempest run --regex {posargs}
 
 [testenv:full]
 envdir = .tox/tempest
@@ -77,7 +77,7 @@
 # See the testrepository bug: https://bugs.launchpad.net/testrepository/+bug/1208610
 commands =
     find . -type f -name "*.pyc" -delete
-    bash tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario)) {posargs}'
+    tempest run --regex '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario))' {posargs}
 
 [testenv:full-serial]
 envdir = .tox/tempest
@@ -88,7 +88,7 @@
 # See the testrepository bug: https://bugs.launchpad.net/testrepository/+bug/1208610
 commands =
     find . -type f -name "*.pyc" -delete
-    bash tools/pretty_tox_serial.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario)) {posargs}'
+    tempest run --regex '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario))' {posargs}
 
 [testenv:smoke]
 envdir = .tox/tempest
@@ -97,7 +97,7 @@
 deps = {[tempestenv]deps}
 commands =
     find . -type f -name "*.pyc" -delete
-    bash tools/pretty_tox.sh '\[.*\bsmoke\b.*\] {posargs}'
+    tempest run --regex '\[.*\bsmoke\b.*\]' {posargs}
 
 [testenv:smoke-serial]
 envdir = .tox/tempest
@@ -109,7 +109,7 @@
 # job would fail if we moved it to parallel.
 commands =
     find . -type f -name "*.pyc" -delete
-    bash tools/pretty_tox_serial.sh '\[.*\bsmoke\b.*\] {posargs}'
+    tempest run --serial --regex '\[.*\bsmoke\b.*\]' {posargs}
 
 [testenv:stress]
 envdir = .tox/tempest