Merge "Fix a few Python 3.x issues"
diff --git a/README.rst b/README.rst
index bc58cc0..281516b 100644
--- a/README.rst
+++ b/README.rst
@@ -4,6 +4,7 @@
.. image:: http://governance.openstack.org/badges/tempest.svg
:target: http://governance.openstack.org/reference/tags/index.html
+ :remote:
.. Change things from this point on
diff --git a/bindep.txt b/bindep.txt
new file mode 100644
index 0000000..6a28348
--- /dev/null
+++ b/bindep.txt
@@ -0,0 +1,11 @@
+# This file contains runtime (non-python) dependencies
+# More info at: http://docs.openstack.org/infra/bindep/readme.html
+
+libffi-dev [platform:dpkg]
+libffi-devel [platform:rpm]
+gcc [platform:rpm]
+gcc [platform:dpkg]
+python-dev [platform:dpkg]
+python-devel [platform:rpm]
+openssl-devel [platform:rpm]
+libssl-dev [platform:dpkg]
diff --git a/releasenotes/notes/13.1.0-volume-clients-as-library-309030c7a16e62ab.yaml b/releasenotes/notes/13.1.0-volume-clients-as-library-309030c7a16e62ab.yaml
index 056e199..6babd93 100644
--- a/releasenotes/notes/13.1.0-volume-clients-as-library-309030c7a16e62ab.yaml
+++ b/releasenotes/notes/13.1.0-volume-clients-as-library-309030c7a16e62ab.yaml
@@ -8,3 +8,5 @@
* volumes_client(v1)
* volumes_client(v2)
+ * capabilities_client(v2)
+ * scheduler_stats_client(v2)
diff --git a/releasenotes/notes/add-service-provider-client-cbba77d424a30dd3.yaml b/releasenotes/notes/add-service-provider-client-cbba77d424a30dd3.yaml
new file mode 100644
index 0000000..b504c78
--- /dev/null
+++ b/releasenotes/notes/add-service-provider-client-cbba77d424a30dd3.yaml
@@ -0,0 +1,4 @@
+---
+features:
+ - A Neutron Service Providers client is added to deal with resources
+ of the '/service-providers' route.
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 173ee83..f6a6040 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -381,18 +381,21 @@
self.request_microversion))
@classmethod
- def create_volume(cls, image_ref=None):
+ def create_volume(cls, image_ref=None, **kwargs):
"""Create a volume and wait for it to become 'available'.
:param image_ref: Specify an image id to create a bootable volume.
+ :**kwargs: other parameters to create volume.
:returns: The available volume.
"""
- vol_name = data_utils.rand_name(cls.__name__ + '-volume')
- create_params = dict(size=CONF.volume.volume_size,
- display_name=vol_name)
+ if 'size' not in kwargs:
+ kwargs['size'] = CONF.volume.volume_size
+ if 'display_name' not in kwargs:
+ vol_name = data_utils.rand_name(cls.__name__ + '-volume')
+ kwargs['display_name'] = vol_name
if image_ref is not None:
- create_params['imageRef'] = image_ref
- volume = cls.volumes_client.create_volume(**create_params)['volume']
+ kwargs['imageRef'] = image_ref
+ volume = cls.volumes_client.create_volume(**kwargs)['volume']
cls.volumes.append(volume)
waiters.wait_for_volume_status(cls.volumes_client,
volume['id'], 'available')
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 fdf1e93..dcb2d2c 100644
--- a/tempest/api/compute/floating_ips/test_floating_ips_actions.py
+++ b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
@@ -14,7 +14,6 @@
# under the License.
from tempest.api.compute.floating_ips import base
-from tempest.common import waiters
from tempest import config
from tempest.lib.common.utils import test_utils
from tempest.lib import exceptions as lib_exc
@@ -111,9 +110,7 @@
# positive test:Association of an already associated floating IP
# to specific server should change the association of the Floating IP
# Create server so as to use for Multiple association
- body = self.create_test_server()
- waiters.wait_for_server_status(self.servers_client,
- body['id'], 'ACTIVE')
+ body = self.create_test_server(wait_until='ACTIVE')
self.new_server_id = body['id']
self.addCleanup(self.servers_client.delete_server, self.new_server_id)
diff --git a/tempest/api/compute/images/test_images_negative.py b/tempest/api/compute/images/test_images_negative.py
index c48367f..549262e 100644
--- a/tempest/api/compute/images/test_images_negative.py
+++ b/tempest/api/compute/images/test_images_negative.py
@@ -46,7 +46,7 @@
# An image should not be created if the server instance is removed
server = self.create_test_server(wait_until='ACTIVE')
- # Delete server before trying to create server
+ # Delete server before trying to create image
self.servers_client.delete_server(server['id'])
waiters.wait_for_server_termination(self.servers_client, server['id'])
# Create a new image after server is deleted
diff --git a/tempest/api/compute/images/test_images_oneserver_negative.py b/tempest/api/compute/images/test_images_oneserver_negative.py
index 039283a..1c9b3f1 100644
--- a/tempest/api/compute/images/test_images_oneserver_negative.py
+++ b/tempest/api/compute/images/test_images_oneserver_negative.py
@@ -93,9 +93,9 @@
@test.attr(type=['negative'])
@test.idempotent_id('3d24d11f-5366-4536-bd28-cff32b748eca')
def test_create_image_specify_metadata_over_limits(self):
- # Return an error when creating image with meta data over 256 chars
+ # Return an error when creating image with meta data over 255 chars
snapshot_name = data_utils.rand_name('test-snap')
- meta = {'a' * 260: 'b' * 260}
+ meta = {'a' * 256: 'b' * 256}
self.assertRaises(lib_exc.BadRequest, self.client.create_image,
self.server_id, name=snapshot_name, metadata=meta)
@@ -118,10 +118,10 @@
@test.attr(type=['negative'])
@test.idempotent_id('084f0cbc-500a-4963-8a4e-312905862581')
- def test_create_image_specify_name_over_256_chars(self):
- # Return an error if snapshot name over 256 characters is passed
+ def test_create_image_specify_name_over_character_limit(self):
+ # Return an error if snapshot name over 255 characters is passed
- snapshot_name = data_utils.rand_name('a' * 260)
+ snapshot_name = ('a' * 256)
self.assertRaises(lib_exc.BadRequest, self.client.create_image,
self.server_id, name=snapshot_name)
diff --git a/tempest/api/compute/security_groups/test_security_groups.py b/tempest/api/compute/security_groups/test_security_groups.py
index 755336f..4184afa 100644
--- a/tempest/api/compute/security_groups/test_security_groups.py
+++ b/tempest/api/compute/security_groups/test_security_groups.py
@@ -94,10 +94,8 @@
# Create server and add the security group created
# above to the server we just created
- server = self.create_test_server()
+ server = self.create_test_server(wait_until='ACTIVE')
server_id = server['id']
- waiters.wait_for_server_status(self.servers_client, server_id,
- 'ACTIVE')
self.servers_client.add_security_group(server_id, name=sg['name'])
# Check that we are not able to delete the security
diff --git a/tempest/api/compute/servers/test_attach_interfaces.py b/tempest/api/compute/servers/test_attach_interfaces.py
index 8342a3e..a21ce94 100644
--- a/tempest/api/compute/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/servers/test_attach_interfaces.py
@@ -46,7 +46,6 @@
@classmethod
def setup_clients(cls):
super(AttachInterfacesTestJSON, cls).setup_clients()
- cls.networks_client = cls.os.networks_client
cls.subnets_client = cls.os.subnets_client
cls.ports_client = cls.os.ports_client
diff --git a/tempest/api/compute/test_quotas.py b/tempest/api/compute/test_quotas.py
index 122e7cc..b9e0c35 100644
--- a/tempest/api/compute/test_quotas.py
+++ b/tempest/api/compute/test_quotas.py
@@ -48,7 +48,8 @@
'fixed_ips', 'key_pairs',
'injected_file_path_bytes',
'instances', 'security_group_rules',
- 'cores', 'security_groups'))
+ 'cores', 'security_groups',
+ 'server_group_members', 'server_groups'))
@test.idempotent_id('f1ef0a97-dbbb-4cca-adc5-c9fbc4f76107')
def test_get_quotas(self):
diff --git a/tempest/api/compute/volumes/test_volumes_list.py b/tempest/api/compute/volumes/test_volumes_list.py
index 7d76731..e4e625b 100644
--- a/tempest/api/compute/volumes/test_volumes_list.py
+++ b/tempest/api/compute/volumes/test_volumes_list.py
@@ -16,8 +16,6 @@
from oslo_log import log as logging
from tempest.api.compute import base
-from tempest.common.utils import data_utils
-from tempest.common import waiters
from tempest import config
from tempest import test
@@ -51,34 +49,11 @@
cls.volume_list = []
cls.volume_id_list = []
for i in range(3):
- v_name = data_utils.rand_name(cls.__name__ + '-volume')
metadata = {'Type': 'work'}
- try:
- volume = cls.client.create_volume(size=CONF.volume.volume_size,
- display_name=v_name,
- metadata=metadata)['volume']
- waiters.wait_for_volume_status(cls.client,
- volume['id'], 'available')
- volume = cls.client.show_volume(volume['id'])['volume']
- cls.volume_list.append(volume)
- cls.volume_id_list.append(volume['id'])
- except Exception as exc:
- LOG.exception(exc)
- if cls.volume_list:
- # We could not create all the volumes, though we were able
- # to create *some* of the volumes. This is typically
- # because the backing file size of the volume group is
- # too small.
- for volume in cls.volume_list:
- cls.delete_volume(volume['id'])
- raise exc
-
- @classmethod
- def resource_cleanup(cls):
- # Delete the created Volumes
- for volume in cls.volume_list:
- cls.delete_volume(volume['id'])
- super(VolumesTestJSON, cls).resource_cleanup()
+ volume = cls.create_volume(metadata=metadata)
+ volume = cls.client.show_volume(volume['id'])['volume']
+ cls.volume_list.append(volume)
+ cls.volume_id_list.append(volume['id'])
@test.idempotent_id('bc2dd1a0-15af-48e5-9990-f2e75a48325d')
def test_volume_list(self):
diff --git a/tempest/api/identity/admin/v3/test_default_project_id.py b/tempest/api/identity/admin/v3/test_default_project_id.py
index 59ffc19..361ff31 100644
--- a/tempest/api/identity/admin/v3/test_default_project_id.py
+++ b/tempest/api/identity/admin/v3/test_default_project_id.py
@@ -36,7 +36,8 @@
def test_default_project_id(self):
# create a domain
dom_name = data_utils.rand_name('dom')
- domain_body = self.domains_client.create_domain(dom_name)['domain']
+ domain_body = self.domains_client.create_domain(
+ name=dom_name)['domain']
dom_id = domain_body['id']
self.addCleanup(self._delete_domain, dom_id)
diff --git a/tempest/api/identity/admin/v3/test_domains.py b/tempest/api/identity/admin/v3/test_domains.py
index cbf1439..e71341f 100644
--- a/tempest/api/identity/admin/v3/test_domains.py
+++ b/tempest/api/identity/admin/v3/test_domains.py
@@ -32,7 +32,7 @@
cls.setup_domains = list()
for i in range(3):
domain = cls.domains_client.create_domain(
- data_utils.rand_name('domain'),
+ name=data_utils.rand_name('domain'),
description=data_utils.rand_name('domain-desc'),
enabled=i < 2)['domain']
cls.setup_domains.append(domain)
@@ -67,7 +67,7 @@
# List domains filtering by name
params = {'name': self.setup_domains[0]['name']}
fetched_domains = self.domains_client.list_domains(
- params=params)['domains']
+ **params)['domains']
# Verify the filtered list is correct, domain names are unique
# so exactly one domain should be found with the provided name
self.assertEqual(1, len(fetched_domains))
@@ -79,7 +79,7 @@
# List domains filtering by enabled domains
params = {'enabled': True}
fetched_domains = self.domains_client.list_domains(
- params=params)['domains']
+ **params)['domains']
# Verify the filtered list is correct
self.assertIn(self.setup_domains[0], fetched_domains)
self.assertIn(self.setup_domains[1], fetched_domains)
@@ -93,7 +93,7 @@
d_name = data_utils.rand_name('domain')
d_desc = data_utils.rand_name('domain-desc')
domain = self.domains_client.create_domain(
- d_name, description=d_desc)['domain']
+ name=d_name, description=d_desc)['domain']
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
self._delete_domain, domain['id'])
self.assertIn('id', domain)
@@ -138,7 +138,7 @@
d_name = data_utils.rand_name('domain')
d_desc = data_utils.rand_name('domain-desc')
domain = self.domains_client.create_domain(
- d_name, description=d_desc, enabled=False)['domain']
+ name=d_name, description=d_desc, enabled=False)['domain']
self.addCleanup(self.domains_client.delete_domain, domain['id'])
self.assertEqual(d_name, domain['name'])
self.assertFalse(domain['enabled'])
@@ -148,11 +148,15 @@
def test_create_domain_without_description(self):
# Create domain only with name
d_name = data_utils.rand_name('domain')
- domain = self.domains_client.create_domain(d_name)['domain']
+ domain = self.domains_client.create_domain(name=d_name)['domain']
self.addCleanup(self._delete_domain, domain['id'])
self.assertIn('id', domain)
expected_data = {'name': d_name, 'enabled': True}
- self.assertIsNone(domain['description'])
+ # TODO(gmann): there is bug in keystone liberty version where
+ # description is not being returned if it is not being passed in
+ # request. Bug#1649245. Once bug is fixed then we can enable the below
+ # check.
+ # self.assertEqual('', domain['description'])
self.assertDictContainsSubset(expected_data, domain)
diff --git a/tempest/api/identity/admin/v3/test_domains_negative.py b/tempest/api/identity/admin/v3/test_domains_negative.py
index 4330cab..100a121 100644
--- a/tempest/api/identity/admin/v3/test_domains_negative.py
+++ b/tempest/api/identity/admin/v3/test_domains_negative.py
@@ -28,7 +28,7 @@
d_name = data_utils.rand_name('domain')
d_desc = data_utils.rand_name('domain-desc')
domain = self.domains_client.create_domain(
- d_name,
+ name=d_name,
description=d_desc)['domain']
domain_id = domain['id']
@@ -51,7 +51,8 @@
# Domain name length should not ne greater than 64 characters
d_name = 'a' * 65
self.assertRaises(lib_exc.BadRequest,
- self.domains_client.create_domain, d_name)
+ self.domains_client.create_domain,
+ name=d_name)
@test.attr(type=['negative'])
@test.idempotent_id('43781c07-764f-4cf2-a405-953c1916f605')
@@ -64,9 +65,10 @@
@test.idempotent_id('e6f9e4a2-4f36-4be8-bdbc-4e199ae29427')
def test_domain_create_duplicate(self):
domain_name = data_utils.rand_name('domain-dup')
- domain = self.domains_client.create_domain(domain_name)['domain']
+ domain = self.domains_client.create_domain(name=domain_name)['domain']
domain_id = domain['id']
self.addCleanup(self.delete_domain, domain_id)
# Domain name should be unique
self.assertRaises(
- lib_exc.Conflict, self.domains_client.create_domain, domain_name)
+ lib_exc.Conflict, self.domains_client.create_domain,
+ name=domain_name)
diff --git a/tempest/api/identity/admin/v3/test_inherits.py b/tempest/api/identity/admin/v3/test_inherits.py
index c7e8411..33fce8d 100644
--- a/tempest/api/identity/admin/v3/test_inherits.py
+++ b/tempest/api/identity/admin/v3/test_inherits.py
@@ -31,7 +31,7 @@
u_email = '%s@testmail.tm' % u_name
u_password = data_utils.rand_name('pass-')
cls.domain = cls.domains_client.create_domain(
- data_utils.rand_name('domain-'),
+ name=data_utils.rand_name('domain-'),
description=data_utils.rand_name('domain-desc-'))['domain']
cls.project = cls.projects_client.create_project(
data_utils.rand_name('project-'),
diff --git a/tempest/api/identity/admin/v3/test_roles.py b/tempest/api/identity/admin/v3/test_roles.py
index f5bf923..670cb2f 100644
--- a/tempest/api/identity/admin/v3/test_roles.py
+++ b/tempest/api/identity/admin/v3/test_roles.py
@@ -34,7 +34,7 @@
u_email = '%s@testmail.tm' % u_name
cls.u_password = data_utils.rand_password()
cls.domain = cls.domains_client.create_domain(
- data_utils.rand_name('domain'),
+ name=data_utils.rand_name('domain'),
description=data_utils.rand_name('domain-desc'))['domain']
cls.project = cls.projects_client.create_project(
data_utils.rand_name('project'),
diff --git a/tempest/api/identity/v3/test_tokens.py b/tempest/api/identity/v3/test_tokens.py
index d5bed96..b410da6 100644
--- a/tempest/api/identity/v3/test_tokens.py
+++ b/tempest/api/identity/v3/test_tokens.py
@@ -34,6 +34,7 @@
# it to be 'default'
token_id, resp = self.non_admin_token.get_token(
user_id=user_id,
+ username=username,
user_domain_id=user_domain_id,
password=password,
auth_data=True)
@@ -49,9 +50,19 @@
self.assertGreater(expires_at, now)
subject_id = resp['user']['id']
- self.assertEqual(subject_id, user_id)
+ if user_id:
+ self.assertEqual(subject_id, user_id)
+ else:
+ # Expect a user ID, but don't know what it will be.
+ self.assertGreaterEqual(len(subject_id), 0,
+ 'Expected user ID in token.')
subject_name = resp['user']['name']
- self.assertEqual(subject_name, username)
+ if username:
+ self.assertEqual(subject_name, username)
+ else:
+ # Expect a user name, but don't know what it will be.
+ self.assertGreaterEqual(len(subject_name), 0,
+ 'Expected user name in token.')
self.assertEqual(resp['methods'][0], 'password')
diff --git a/tempest/api/network/admin/test_negative_quotas.py b/tempest/api/network/admin/test_negative_quotas.py
index 7b037d5..c256b5b 100644
--- a/tempest/api/network/admin/test_negative_quotas.py
+++ b/tempest/api/network/admin/test_negative_quotas.py
@@ -38,11 +38,6 @@
msg = "quotas extension not enabled."
raise cls.skipException(msg)
- @classmethod
- def setup_clients(cls):
- super(QuotasNegativeTest, cls).setup_clients()
- cls.identity_admin_client = cls.os_adm.identity_client
-
@test.idempotent_id('644f4e1b-1bf9-4af0-9fd8-eb56ac0f51cf')
def test_network_quota_exceeding(self):
# Set the network quota to two
diff --git a/tempest/api/network/admin/test_quotas.py b/tempest/api/network/admin/test_quotas.py
index 3a264ff..978fb8f 100644
--- a/tempest/api/network/admin/test_quotas.py
+++ b/tempest/api/network/admin/test_quotas.py
@@ -43,11 +43,6 @@
msg = "quotas extension not enabled."
raise cls.skipException(msg)
- @classmethod
- def setup_clients(cls):
- super(QuotasTest, cls).setup_clients()
- cls.identity_admin_client = cls.os_adm.identity_client
-
def _check_quotas(self, new_quotas):
# Add a project to conduct the test
project = data_utils.rand_name('test_project_')
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index deefbeb..c2c42bb 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -81,6 +81,7 @@
cls.security_group_rules_client = (
cls.os.security_group_rules_client)
cls.network_versions_client = cls.os.network_versions_client
+ cls.service_providers_client = cls.os.service_providers_client
@classmethod
def resource_setup(cls):
diff --git a/tempest/api/network/test_ports.py b/tempest/api/network/test_ports.py
index 15d289d..5b46088 100644
--- a/tempest/api/network/test_ports.py
+++ b/tempest/api/network/test_ports.py
@@ -360,11 +360,6 @@
class PortsAdminExtendedAttrsTestJSON(base.BaseAdminNetworkTest):
@classmethod
- def setup_clients(cls):
- super(PortsAdminExtendedAttrsTestJSON, cls).setup_clients()
- cls.identity_client = cls.os_adm.identity_client
-
- @classmethod
def resource_setup(cls):
super(PortsAdminExtendedAttrsTestJSON, cls).resource_setup()
cls.network = cls.create_network()
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index e989b69..f2170ad 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -34,11 +34,6 @@
raise cls.skipException(msg)
@classmethod
- def setup_clients(cls):
- super(RoutersTest, cls).setup_clients()
- cls.identity_admin_client = cls.os_adm.identity_client
-
- @classmethod
def resource_setup(cls):
super(RoutersTest, cls).resource_setup()
cls.tenant_cidr = (CONF.network.project_network_cidr
diff --git a/tempest/api/network/test_service_providers.py b/tempest/api/network/test_service_providers.py
new file mode 100644
index 0000000..09fb5fe
--- /dev/null
+++ b/tempest/api/network/test_service_providers.py
@@ -0,0 +1,23 @@
+# 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.api.network import base
+from tempest import test
+
+
+class ServiceProvidersTest(base.BaseNetworkTest):
+
+ @test.idempotent_id('2cbbeea9-f010-40f6-8df5-4eaa0c918ea6')
+ def test_service_providers_list(self):
+ body = self.service_providers_client.list_service_providers()
+ self.assertIn('service_providers', body)
+ self.assertIsInstance(body['service_providers'], list)
diff --git a/tempest/api/network/test_service_type_management.py b/tempest/api/network/test_service_type_management.py
deleted file mode 100644
index f49f082..0000000
--- a/tempest/api/network/test_service_type_management.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# 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.api.network import base
-from tempest.lib import decorators
-from tempest import test
-
-
-class ServiceTypeManagementTestJSON(base.BaseNetworkTest):
-
- @classmethod
- def skip_checks(cls):
- super(ServiceTypeManagementTestJSON, cls).skip_checks()
- if not test.is_extension_enabled('service-type', 'network'):
- msg = "Neutron Service Type Management not enabled."
- raise cls.skipException(msg)
-
- @decorators.skip_because(bug="1400370")
- @test.idempotent_id('2cbbeea9-f010-40f6-8df5-4eaa0c918ea6')
- def test_service_provider_list(self):
- body = self.client.list_service_providers()
- self.assertIsInstance(body['service_providers'], list)
diff --git a/tempest/api/volume/admin/test_backends_capabilities.py b/tempest/api/volume/admin/v2/test_backends_capabilities.py
similarity index 90%
rename from tempest/api/volume/admin/test_backends_capabilities.py
rename to tempest/api/volume/admin/v2/test_backends_capabilities.py
index 8a21853..fc9066c 100644
--- a/tempest/api/volume/admin/test_backends_capabilities.py
+++ b/tempest/api/volume/admin/v2/test_backends_capabilities.py
@@ -38,13 +38,13 @@
# Get host list, formation: host@backend-name
cls.hosts = [
pool['name'] for pool in
- cls.admin_volume_client.show_pools()['pools']
+ cls.admin_scheduler_stats_client.list_pools()['pools']
]
@test.idempotent_id('3750af44-5ea2-4cd4-bc3e-56e7e6caf854')
def test_get_capabilities_backend(self):
# Test backend properties
- backend = self.admin_volume_client.show_backend_capabilities(
+ backend = self.admin_capabilities_client.show_backend_capabilities(
self.hosts[0])
# Verify getting capabilities parameters from a backend
@@ -62,12 +62,12 @@
# Get list backend capabilities using show_pools
cinder_pools = [
pool['capabilities'] for pool in
- self.admin_volume_client.show_pools(detail=True)['pools']
+ self.admin_scheduler_stats_client.list_pools(detail=True)['pools']
]
# Get list backends capabilities using show_backend_capabilities
capabilities = [
- self.admin_volume_client.show_backend_capabilities(
+ self.admin_capabilities_client.show_backend_capabilities(
host=host) for host in self.hosts
]
diff --git a/tempest/api/volume/admin/v2/test_volume_pools.py b/tempest/api/volume/admin/v2/test_volume_pools.py
index c662e8c..e460278 100644
--- a/tempest/api/volume/admin/v2/test_volume_pools.py
+++ b/tempest/api/volume/admin/v2/test_volume_pools.py
@@ -29,7 +29,7 @@
def test_get_pools_without_details(self):
volume_info = self.admin_volume_client. \
show_volume(self.volume['id'])['volume']
- cinder_pools = self.admin_volume_client.show_pools()['pools']
+ cinder_pools = self.admin_scheduler_stats_client.list_pools()['pools']
self.assertIn(volume_info['os-vol-host-attr:host'],
[pool['name'] for pool in cinder_pools])
@@ -37,7 +37,7 @@
def test_get_pools_with_details(self):
volume_info = self.admin_volume_client. \
show_volume(self.volume['id'])['volume']
- cinder_pools = self.admin_volume_client.\
- show_pools(detail=True)['pools']
+ cinder_pools = self.admin_scheduler_stats_client.\
+ list_pools(detail=True)['pools']
self.assertIn(volume_info['os-vol-host-attr:host'],
[pool['name'] for pool in cinder_pools])
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index 01e2c82..7cd72e1 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -266,6 +266,10 @@
cls.os_adm.encryption_types_v2_client
cls.admin_quotas_client = cls.os_adm.volume_quotas_v2_client
cls.admin_volume_limits_client = cls.os_adm.volume_v2_limits_client
+ cls.admin_capabilities_client = \
+ cls.os_adm.volume_capabilities_v2_client
+ cls.admin_scheduler_stats_client = \
+ cls.os_adm.volume_scheduler_stats_v2_client
@classmethod
def resource_setup(cls):
diff --git a/tempest/clients.py b/tempest/clients.py
index b3290ac..78a93d1 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -127,6 +127,7 @@
self.network.SecurityGroupRulesClient())
self.security_groups_client = self.network.SecurityGroupsClient()
self.network_versions_client = self.network.NetworkVersionsClient()
+ self.service_providers_client = self.network.ServiceProvidersClient()
def _set_image_clients(self):
if CONF.service_available.glance:
@@ -303,6 +304,10 @@
self.volume_v2.AvailabilityZoneClient()
self.volume_limits_client = self.volume_v1.LimitsClient()
self.volume_v2_limits_client = self.volume_v2.LimitsClient()
+ self.volume_capabilities_v2_client = \
+ self.volume_v2.CapabilitiesClient()
+ self.volume_scheduler_stats_v2_client = \
+ self.volume_v2.SchedulerStatsClient()
def _set_object_storage_clients(self):
# Mandatory parameters (always defined)
diff --git a/tempest/lib/common/cred_client.py b/tempest/lib/common/cred_client.py
index ad968f1..3f10dee 100644
--- a/tempest/lib/common/cred_client.py
+++ b/tempest/lib/common/cred_client.py
@@ -140,7 +140,7 @@
# Domain names must be unique, in any case a list is returned,
# selecting the first (and only) element
self.creds_domain = self.domains_client.list_domains(
- params={'name': domain_name})['domains'][0]
+ name=domain_name)['domains'][0]
except lib_exc.NotFound:
# TODO(andrea) we could probably create the domain on the fly
msg = "Requested domain %s could not be found" % domain_name
diff --git a/tempest/lib/services/network/__init__.py b/tempest/lib/services/network/__init__.py
index c466f07..19e5463 100644
--- a/tempest/lib/services/network/__init__.py
+++ b/tempest/lib/services/network/__init__.py
@@ -27,6 +27,8 @@
SecurityGroupRulesClient
from tempest.lib.services.network.security_groups_client import \
SecurityGroupsClient
+from tempest.lib.services.network.service_providers_client import \
+ ServiceProvidersClient
from tempest.lib.services.network.subnetpools_client import SubnetpoolsClient
from tempest.lib.services.network.subnets_client import SubnetsClient
from tempest.lib.services.network.versions_client import NetworkVersionsClient
@@ -35,4 +37,5 @@
'MeteringLabelRulesClient', 'MeteringLabelsClient',
'NetworksClient', 'PortsClient', 'QuotasClient', 'RoutersClient',
'SecurityGroupRulesClient', 'SecurityGroupsClient',
- 'SubnetpoolsClient', 'SubnetsClient', 'NetworkVersionsClient']
+ 'ServiceProvidersClient', 'SubnetpoolsClient', 'SubnetsClient',
+ 'NetworkVersionsClient']
diff --git a/tempest/lib/services/network/service_providers_client.py b/tempest/lib/services/network/service_providers_client.py
new file mode 100644
index 0000000..0ee9bc3
--- /dev/null
+++ b/tempest/lib/services/network/service_providers_client.py
@@ -0,0 +1,21 @@
+# 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.network import base
+
+
+class ServiceProvidersClient(base.BaseNetworkClient):
+
+ def list_service_providers(self, **filters):
+ """Lists service providers."""
+ uri = '/service-providers'
+ return self.list_resources(uri, **filters)
diff --git a/tempest/lib/services/volume/v2/__init__.py b/tempest/lib/services/volume/v2/__init__.py
index eaaafa5..837b4f6 100644
--- a/tempest/lib/services/volume/v2/__init__.py
+++ b/tempest/lib/services/volume/v2/__init__.py
@@ -15,6 +15,8 @@
from tempest.lib.services.volume.v2.availability_zone_client \
import AvailabilityZoneClient
from tempest.lib.services.volume.v2.backups_client import BackupsClient
+from tempest.lib.services.volume.v2.capabilities_client import \
+ CapabilitiesClient
from tempest.lib.services.volume.v2.encryption_types_client import \
EncryptionTypesClient
from tempest.lib.services.volume.v2.extensions_client import ExtensionsClient
@@ -22,6 +24,8 @@
from tempest.lib.services.volume.v2.limits_client import LimitsClient
from tempest.lib.services.volume.v2.qos_client import QosSpecsClient
from tempest.lib.services.volume.v2.quotas_client import QuotasClient
+from tempest.lib.services.volume.v2.scheduler_stats_client import \
+ SchedulerStatsClient
from tempest.lib.services.volume.v2.services_client import ServicesClient
from tempest.lib.services.volume.v2.snapshots_client import SnapshotsClient
from tempest.lib.services.volume.v2.types_client import TypesClient
@@ -30,4 +34,4 @@
__all__ = ['AvailabilityZoneClient', 'BackupsClient', 'EncryptionTypesClient',
'ExtensionsClient', 'HostsClient', 'QosSpecsClient', 'QuotasClient',
'ServicesClient', 'SnapshotsClient', 'TypesClient', 'VolumesClient',
- 'LimitsClient']
+ 'LimitsClient', 'CapabilitiesClient', 'SchedulerStatsClient']
diff --git a/tempest/lib/services/volume/v2/capabilities_client.py b/tempest/lib/services/volume/v2/capabilities_client.py
new file mode 100644
index 0000000..b6de5b9
--- /dev/null
+++ b/tempest/lib/services/volume/v2/capabilities_client.py
@@ -0,0 +1,34 @@
+# Copyright 2016 Red Hat, Inc.
+# 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.
+
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.common import rest_client
+
+
+class CapabilitiesClient(rest_client.RestClient):
+
+ def show_backend_capabilities(self, host):
+ """Shows capabilities for a storage back end.
+
+ Output params: see http://developer.openstack.org/
+ api-ref-blockstorage-v2.html
+ #showBackendCapabilities
+ """
+ url = 'capabilities/%s' % host
+ resp, body = self.get(url)
+ body = json.loads(body)
+ self.expected_success(200, resp.status)
+ return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/volume/v2/scheduler_stats_client.py b/tempest/lib/services/volume/v2/scheduler_stats_client.py
new file mode 100644
index 0000000..637254b
--- /dev/null
+++ b/tempest/lib/services/volume/v2/scheduler_stats_client.py
@@ -0,0 +1,35 @@
+# Copyright 2016 Red Hat, Inc.
+# 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.
+
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.common import rest_client
+
+
+class SchedulerStatsClient(rest_client.RestClient):
+
+ def list_pools(self, detail=False):
+ """List all the volumes pools (hosts).
+
+ Output params: see http://developer.openstack.org/
+ api-ref-blockstorage-v2.html#listPools
+ """
+ url = 'scheduler-stats/get_pools'
+ if detail:
+ url += '?detail=True'
+ resp, body = self.get(url)
+ body = json.loads(body)
+ self.expected_success(200, resp.status)
+ return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/volume/v2/volumes_client.py b/tempest/lib/services/volume/v2/volumes_client.py
index ce97adb..8b8e249 100644
--- a/tempest/lib/services/volume/v2/volumes_client.py
+++ b/tempest/lib/services/volume/v2/volumes_client.py
@@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+from debtcollector import removals
from oslo_serialization import jsonutils as json
import six
from six.moves.urllib import parse as urllib
@@ -323,6 +324,8 @@
self.expected_success(200, resp.status)
return rest_client.ResponseBody(resp, body)
+ @removals.remove(message="use show_pools from tempest.lib.services."
+ "volume.v2.scheduler_stats_client")
def show_pools(self, detail=False):
# List all the volumes pools (hosts)
url = 'scheduler-stats/get_pools'
@@ -334,6 +337,8 @@
self.expected_success(200, resp.status)
return rest_client.ResponseBody(resp, body)
+ @removals.remove(message="use show_backend_capabilities from tempest.lib."
+ "services.volume.v2.capabilities_client")
def show_backend_capabilities(self, host):
"""Shows capabilities for a storage back end.
diff --git a/tempest/services/identity/v3/json/domains_client.py b/tempest/services/identity/v3/json/domains_client.py
index fe929a5..43cb62c 100644
--- a/tempest/services/identity/v3/json/domains_client.py
+++ b/tempest/services/identity/v3/json/domains_client.py
@@ -21,29 +21,36 @@
class DomainsClient(rest_client.RestClient):
api_version = "v3"
- def create_domain(self, name, **kwargs):
- """Creates a domain."""
- description = kwargs.get('description', None)
- en = kwargs.get('enabled', True)
- post_body = {
- 'description': description,
- 'enabled': en,
- 'name': name
- }
- post_body = json.dumps({'domain': post_body})
+ def create_domain(self, **kwargs):
+ """Creates a domain.
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v3/index.html#create-domain
+ """
+ post_body = json.dumps({'domain': kwargs})
resp, body = self.post('domains', post_body)
self.expected_success(201, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
def delete_domain(self, domain_id):
- """Deletes a domain."""
+ """Deletes a domain.
+
+ For APi details, please refer to the official API reference:
+ http://developer.openstack.org/api-ref/identity/v3/index.html#delete-domain
+ """
resp, body = self.delete('domains/%s' % domain_id)
self.expected_success(204, resp.status)
return rest_client.ResponseBody(resp, body)
- def list_domains(self, params=None):
- """List Domains."""
+ def list_domains(self, **params):
+ """List Domains.
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v3/index.html#list-domains
+ """
url = 'domains'
if params:
url += '?%s' % urllib.urlencode(params)
@@ -53,24 +60,24 @@
return rest_client.ResponseBody(resp, body)
def update_domain(self, domain_id, **kwargs):
- """Updates a domain."""
- body = self.show_domain(domain_id)['domain']
- description = kwargs.get('description', body['description'])
- en = kwargs.get('enabled', body['enabled'])
- name = kwargs.get('name', body['name'])
- post_body = {
- 'description': description,
- 'enabled': en,
- 'name': name
- }
- post_body = json.dumps({'domain': post_body})
+ """Updates a domain.
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/identity/v3/index.html#update-domain
+ """
+ post_body = json.dumps({'domain': kwargs})
resp, body = self.patch('domains/%s' % domain_id, post_body)
self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
def show_domain(self, domain_id):
- """Get Domain details."""
+ """Get Domain details.
+
+ For API details, please refer to the official API reference:
+ http://developer.openstack.org/api-ref/identity/v3/index.html#show-domain-details
+ """
resp, body = self.get('domains/%s' % domain_id)
self.expected_success(200, resp.status)
body = json.loads(body)
diff --git a/tempest/test.py b/tempest/test.py
index 451b876..057e278 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -536,18 +536,17 @@
"""
if not CONF.validation.run_validation:
return
+
if keypair is None:
- if CONF.validation.auth_method.lower() == "keypair":
- keypair = True
- else:
- keypair = False
+ keypair = (CONF.validation.auth_method.lower() == "keypair")
+
if floating_ip is None:
- if CONF.validation.connect_method.lower() == "floating":
- floating_ip = True
- else:
- floating_ip = False
+ floating_ip = (CONF.validation.connect_method.lower() ==
+ "floating")
+
if security_group is None:
security_group = CONF.validation.security_group
+
if security_group_rules is None:
security_group_rules = CONF.validation.security_group_rules
diff --git a/tempest/tests/lib/services/network/test_service_providers_client.py b/tempest/tests/lib/services/network/test_service_providers_client.py
new file mode 100644
index 0000000..ae11ef0
--- /dev/null
+++ b/tempest/tests/lib/services/network/test_service_providers_client.py
@@ -0,0 +1,37 @@
+# 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.network import service_providers_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestServiceProvidersClient(base.BaseServiceTest):
+ def setUp(self):
+ super(TestServiceProvidersClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = service_providers_client.ServiceProvidersClient(
+ fake_auth, 'network', 'regionOne')
+
+ def _test_list_service_providers(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_service_providers,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ {"service_providers": []},
+ bytes_body)
+
+ def test_list_service_providers_with_str_body(self):
+ self._test_list_service_providers()
+
+ def test_list_service_providers_with_bytes_body(self):
+ self._test_list_service_providers(bytes_body=True)
diff --git a/tempest/tests/lib/test_auth.py b/tempest/tests/lib/test_auth.py
index 6da7e41..2f975d2 100644
--- a/tempest/tests/lib/test_auth.py
+++ b/tempest/tests/lib/test_auth.py
@@ -458,6 +458,56 @@
expected = 'http://fake_url/v2.0'
self._test_base_url_helper(expected, filters, ('token', auth_data))
+ def test_base_url_with_extra_path_endpoint(self):
+ auth_data = {
+ 'serviceCatalog': [
+ {
+ 'type': 'compute',
+ 'endpoints': [
+ {
+ 'region': 'FakeRegion',
+ 'publicURL': 'http://fake_url/some_path/v2.0'
+ }
+ ]
+ }
+ ]
+ }
+
+ filters = {
+ 'service': 'compute',
+ 'endpoint_type': 'publicURL',
+ 'region': 'FakeRegion',
+ 'api_version': 'v2.0'
+ }
+
+ expected = 'http://fake_url/some_path/v2.0'
+ self._test_base_url_helper(expected, filters, ('token', auth_data))
+
+ def test_base_url_with_unversioned_extra_path_endpoint(self):
+ auth_data = {
+ 'serviceCatalog': [
+ {
+ 'type': 'compute',
+ 'endpoints': [
+ {
+ 'region': 'FakeRegion',
+ 'publicURL': 'http://fake_url/some_path'
+ }
+ ]
+ }
+ ]
+ }
+
+ filters = {
+ 'service': 'compute',
+ 'endpoint_type': 'publicURL',
+ 'region': 'FakeRegion',
+ 'api_version': 'v2.0'
+ }
+
+ expected = 'http://fake_url/some_path/v2.0'
+ self._test_base_url_helper(expected, filters, ('token', auth_data))
+
def test_token_not_expired(self):
expiry_data = datetime.datetime.utcnow() + datetime.timedelta(days=1)
self._verify_expiry(expiry_data=expiry_data, should_be_expired=False)
@@ -592,6 +642,58 @@
expected = 'http://fake_url/v3'
self._test_base_url_helper(expected, filters, ('token', auth_data))
+ def test_base_url_with_extra_path_endpoint(self):
+ auth_data = {
+ 'catalog': [
+ {
+ 'type': 'compute',
+ 'endpoints': [
+ {
+ 'region': 'FakeRegion',
+ 'url': 'http://fake_url/some_path/v2.0',
+ 'interface': 'public'
+ }
+ ]
+ }
+ ]
+ }
+
+ filters = {
+ 'service': 'compute',
+ 'endpoint_type': 'publicURL',
+ 'region': 'FakeRegion',
+ 'api_version': 'v2.0'
+ }
+
+ expected = 'http://fake_url/some_path/v2.0'
+ self._test_base_url_helper(expected, filters, ('token', auth_data))
+
+ def test_base_url_with_unversioned_extra_path_endpoint(self):
+ auth_data = {
+ 'catalog': [
+ {
+ 'type': 'compute',
+ 'endpoints': [
+ {
+ 'region': 'FakeRegion',
+ 'url': 'http://fake_url/some_path',
+ 'interface': 'public'
+ }
+ ]
+ }
+ ]
+ }
+
+ filters = {
+ 'service': 'compute',
+ 'endpoint_type': 'publicURL',
+ 'region': 'FakeRegion',
+ 'api_version': 'v2.0'
+ }
+
+ expected = 'http://fake_url/some_path/v2.0'
+ self._test_base_url_helper(expected, filters, ('token', auth_data))
+
# Base URL test with scope only for V3
def test_base_url_scope_project(self):
self.auth_provider.scope = 'project'
diff --git a/tox.ini b/tox.ini
index 8e3cfcc..7a36e84 100644
--- a/tox.ini
+++ b/tox.ini
@@ -161,3 +161,12 @@
commands=
pip-extra-reqs -d --ignore-file=tempest/tests/* tempest
pip-missing-reqs -d --ignore-file=tempest/tests/* tempest
+
+
+[testenv:bindep]
+# Do not install any requirements. We want this to be fast and work even if
+# system dependencies are missing, since it's used to tell you what system
+# dependencies are missing! This also means that bindep must be installed
+# separately, outside of the requirements files.
+deps = bindep
+commands = bindep test