Merge "Narrow assertion in attach/delete volume test"
diff --git a/doc/source/conf.py b/doc/source/conf.py
index 127613d..2edaddb 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -14,6 +14,7 @@
import sys
import os
import subprocess
+import warnings
# Build the plugin registry
def build_plugin_registry(app):
@@ -140,9 +141,13 @@
# using the given strftime format.
git_cmd = ["git", "log", "--pretty=format:'%ad, commit %h'", "--date=local",
"-n1"]
-html_last_updated_fmt = subprocess.Popen(git_cmd,
- stdout=subprocess.PIPE).\
- communicate()[0]
+try:
+ html_last_updated_fmt = subprocess.Popen(git_cmd,
+ stdout=subprocess.PIPE).\
+ communicate()[0]
+except Exception:
+ warnings.warn('Cannot get last updated time from git repository. '
+ 'Not setting "html_last_updated_fmt".')
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
diff --git a/releasenotes/notes/add-new-identity-clients-3c3afd674a395bde.yaml b/releasenotes/notes/add-new-identity-clients-3c3afd674a395bde.yaml
index b8dcfce..3ec8b56 100644
--- a/releasenotes/notes/add-new-identity-clients-3c3afd674a395bde.yaml
+++ b/releasenotes/notes/add-new-identity-clients-3c3afd674a395bde.yaml
@@ -1,10 +1,13 @@
---
features:
- |
- Define identity service clients as libraries
+ Define identity service clients as libraries.
The following identity service clients are defined as library interface,
so the other projects can use these modules as stable libraries without
any maintenance changes.
* endpoints_client(v3)
* policies_client (v3)
+ * regions_client(v3)
+ * services_client(v3)
+ * projects_client(v3)
diff --git a/releasenotes/notes/add-new-identity-clients-as-library-3e6559d4bff3e776.yaml b/releasenotes/notes/add-new-identity-clients-as-library-5f7ndha733nwdsn9.yaml
similarity index 73%
rename from releasenotes/notes/add-new-identity-clients-as-library-3e6559d4bff3e776.yaml
rename to releasenotes/notes/add-new-identity-clients-as-library-5f7ndha733nwdsn9.yaml
index 9feb3c3..6673616 100644
--- a/releasenotes/notes/add-new-identity-clients-as-library-3e6559d4bff3e776.yaml
+++ b/releasenotes/notes/add-new-identity-clients-as-library-5f7ndha733nwdsn9.yaml
@@ -5,5 +5,6 @@
Add new service clients to the library interface so the other projects can use these modules as stable libraries without
any maintenance changes.
- * regions_client(v3)
- * services_client(v3)
+ * identity_client(v2)
+ * groups_client(v3)
+ * users_client(v3)
diff --git a/releasenotes/notes/move-call-until-true-to-tempest-lib-c9ea70dd6fe9bd15.yaml b/releasenotes/notes/move-call-until-true-to-tempest-lib-c9ea70dd6fe9bd15.yaml
new file mode 100644
index 0000000..543cf7b
--- /dev/null
+++ b/releasenotes/notes/move-call-until-true-to-tempest-lib-c9ea70dd6fe9bd15.yaml
@@ -0,0 +1,5 @@
+---
+deprecations:
+ - The ``call_until_true`` function is moved from the ``tempest.test`` module
+ to the ``tempest.lib.common.utils.test_utils`` module. Backward
+ compatibilty is preserved until Ocata.
diff --git a/requirements.txt b/requirements.txt
index d698cda..a773d16 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -22,3 +22,4 @@
PrettyTable<0.8,>=0.7 # BSD
os-testr>=0.7.0 # Apache-2.0
urllib3>=1.15.1 # MIT
+debtcollector>=1.2.0 # Apache-2.0
diff --git a/tempest/api/compute/admin/test_aggregates.py b/tempest/api/compute/admin/test_aggregates.py
index ac1bfee..fbcc1d1 100644
--- a/tempest/api/compute/admin/test_aggregates.py
+++ b/tempest/api/compute/admin/test_aggregates.py
@@ -25,8 +25,6 @@
class AggregatesAdminTestJSON(base.BaseV2ComputeAdminTest):
"""Tests Aggregates API that require admin privileges"""
- _host_key = 'OS-EXT-SRV-ATTR:host'
-
@classmethod
def setup_clients(cls):
super(AggregatesAdminTestJSON, cls).setup_clients()
@@ -223,4 +221,4 @@
availability_zone=az_name,
wait_until='ACTIVE')
body = admin_servers_client.show_server(server['id'])['server']
- self.assertEqual(self.host, body[self._host_key])
+ self.assertEqual(self.host, body['OS-EXT-SRV-ATTR:host'])
diff --git a/tempest/api/compute/admin/test_auto_allocate_network.py b/tempest/api/compute/admin/test_auto_allocate_network.py
index 052c17d..ee8ed14 100644
--- a/tempest/api/compute/admin/test_auto_allocate_network.py
+++ b/tempest/api/compute/admin/test_auto_allocate_network.py
@@ -16,6 +16,7 @@
from tempest.api.compute import base
from tempest.common import compute
+from tempest.common import credentials_factory as credentials
from tempest.common import waiters
from tempest import config
from tempest import exceptions
@@ -45,6 +46,11 @@
@classmethod
def skip_checks(cls):
super(AutoAllocateNetworkTest, cls).skip_checks()
+ identity_version = cls.get_identity_version()
+ if not credentials.is_admin_available(
+ identity_version=identity_version):
+ msg = "Missing Identity Admin API credentials in configuration."
+ raise cls.skipException(msg)
if not CONF.service_available.neutron:
raise cls.skipException('Neutron is required')
if not test.is_extension_enabled('auto-allocated-topology', 'network'):
diff --git a/tempest/api/compute/admin/test_live_migration.py b/tempest/api/compute/admin/test_live_migration.py
index dd7beaa..18a6afc 100644
--- a/tempest/api/compute/admin/test_live_migration.py
+++ b/tempest/api/compute/admin/test_live_migration.py
@@ -26,7 +26,6 @@
class LiveBlockMigrationTestJSON(base.BaseV2ComputeAdminTest):
- _host_key = 'OS-EXT-SRV-ATTR:host'
max_microversion = '2.24'
block_migration = None
@@ -63,7 +62,7 @@
return body
def _get_host_for_server(self, server_id):
- return self._get_server_details(server_id)[self._host_key]
+ return self._get_server_details(server_id)['OS-EXT-SRV-ATTR:host']
def _migrate_server_to(self, server_id, dest_host, volume_backed=False):
kwargs = dict()
@@ -157,7 +156,7 @@
target_host = self._get_host_other_than(actual_host)
volume = self.volumes_client.create_volume(
- display_name='test')['volume']
+ size=CONF.volume.volume_size, display_name='test')['volume']
waiters.wait_for_volume_status(self.volumes_client,
volume['id'], 'available')
diff --git a/tempest/api/compute/admin/test_servers.py b/tempest/api/compute/admin/test_servers.py
index dd4a533..aabb40c 100755
--- a/tempest/api/compute/admin/test_servers.py
+++ b/tempest/api/compute/admin/test_servers.py
@@ -24,8 +24,6 @@
class ServersAdminTestJSON(base.BaseV2ComputeAdminTest):
"""Tests Servers API using admin privileges"""
- _host_key = 'OS-EXT-SRV-ATTR:host'
-
@classmethod
def setup_clients(cls):
super(ServersAdminTestJSON, cls).setup_clients()
@@ -47,13 +45,6 @@
wait_until='ACTIVE')
cls.s2_id = server['id']
- @test.idempotent_id('51717b38-bdc1-458b-b636-1cf82d99f62f')
- def test_list_servers_by_admin(self):
- # Listing servers by admin user returns empty list by default
- body = self.client.list_servers(detail=True)
- servers = body['servers']
- self.assertEqual([], servers)
-
@test.idempotent_id('06f960bb-15bb-48dc-873d-f96e89be7870')
def test_list_servers_filter_by_error_status(self):
# Filter the list of servers by server error status
@@ -77,6 +68,19 @@
servers = body['servers']
self.assertEqual([], servers)
+ @test.idempotent_id('51717b38-bdc1-458b-b636-1cf82d99f62f')
+ def test_list_servers_by_admin(self):
+ # Listing servers by admin user returns a list which doesn't
+ # contain the other tenants' server by default
+ body = self.client.list_servers(detail=True)
+ servers = body['servers']
+
+ # This case is for the test environments which contain
+ # the existing servers before testing
+ servers_name = [server['name'] for server in servers]
+ self.assertNotIn(self.s1_name, servers_name)
+ self.assertNotIn(self.s2_name, servers_name)
+
@test.idempotent_id('9f5579ae-19b4-4985-a091-2a5d56106580')
def test_list_servers_by_admin_with_all_tenants(self):
# Listing servers by admin user with all tenants parameter
@@ -121,7 +125,7 @@
self.addCleanup(self.client.delete_server, test_server['id'])
server = self.client.show_server(test_server['id'])['server']
self.assertEqual(server['status'], 'ACTIVE')
- hostname = server[self._host_key]
+ hostname = server['OS-EXT-SRV-ATTR:host']
params = {'host': hostname}
body = self.client.list_servers(**params)
servers = body['servers']
diff --git a/tempest/api/compute/admin/test_simple_tenant_usage.py b/tempest/api/compute/admin/test_simple_tenant_usage.py
index a4ed8dc..dbc22e0 100644
--- a/tempest/api/compute/admin/test_simple_tenant_usage.py
+++ b/tempest/api/compute/admin/test_simple_tenant_usage.py
@@ -16,6 +16,7 @@
import datetime
from tempest.api.compute import base
+from tempest.lib.common.utils import test_utils
from tempest.lib import exceptions as e
from tempest import test
@@ -59,8 +60,8 @@
return True
except e.InvalidHTTPResponseBody:
return False
- self.assertEqual(test.call_until_true(is_valid, duration, 1), True,
- "%s not return valid response in %s secs" % (
+ self.assertEqual(test_utils.call_until_true(is_valid, duration, 1),
+ True, "%s not return valid response in %s secs" % (
func.__name__, duration))
return self.resp
diff --git a/tempest/api/compute/test_live_block_migration_negative.py b/tempest/api/compute/test_live_block_migration_negative.py
index dc57396..ffd274f 100644
--- a/tempest/api/compute/test_live_block_migration_negative.py
+++ b/tempest/api/compute/test_live_block_migration_negative.py
@@ -24,8 +24,6 @@
class LiveBlockMigrationNegativeTestJSON(base.BaseV2ComputeAdminTest):
- _host_key = 'OS-EXT-SRV-ATTR:host'
-
@classmethod
def skip_checks(cls):
super(LiveBlockMigrationNegativeTestJSON, cls).skip_checks()
diff --git a/tempest/api/compute/volumes/test_attach_volume.py b/tempest/api/compute/volumes/test_attach_volume.py
index 9f05a84..7c13ef0 100644
--- a/tempest/api/compute/volumes/test_attach_volume.py
+++ b/tempest/api/compute/volumes/test_attach_volume.py
@@ -64,18 +64,19 @@
self.volumes_client.wait_for_resource_deletion(self.volume['id'])
self.volume = None
- def _create_and_attach(self, shelve_server=False):
+ def _create_server(self):
# Start a server and wait for it to become ready
- self.admin_pass = self.image_ssh_password
- self.server = self.create_test_server(
+ server = self.create_test_server(
validatable=True,
wait_until='ACTIVE',
- adminPass=self.admin_pass)
+ adminPass=self.image_ssh_password)
# Record addresses so that we can ssh later
- self.server['addresses'] = self.servers_client.list_addresses(
- self.server['id'])['addresses']
+ server['addresses'] = self.servers_client.list_addresses(
+ server['id'])['addresses']
+ return server
+ def _create_and_attach_volume(self, server):
# Create a volume and wait for it to become ready
self.volume = self.volumes_client.create_volume(
size=CONF.volume.volume_size, display_name='test')['volume']
@@ -83,78 +84,61 @@
waiters.wait_for_volume_status(self.volumes_client,
self.volume['id'], 'available')
- if shelve_server:
- if CONF.validation.run_validation:
- # NOTE(andreaf) If we are going to shelve a server, we should
- # check first whether the server is ssh-able. Otherwise we
- # won't be able to distinguish failures introduced by shelve
- # from pre-existing ones. Also it's good to wait for cloud-init
- # to be done and sshd server to be running before shelving to
- # avoid breaking the VM
- linux_client = remote_client.RemoteClient(
- self.get_server_ip(self.server),
- self.image_ssh_user,
- self.admin_pass,
- self.validation_resources['keypair']['private_key'])
- linux_client.validate_authentication()
-
- # If validation went ok, or it was skipped, shelve the server
- compute.shelve_server(self.servers_client, self.server['id'])
-
# Attach the volume to the server
self.attachment = self.servers_client.attach_volume(
- self.server['id'],
+ server['id'],
volumeId=self.volume['id'],
device='/dev/%s' % self.device)['volumeAttachment']
waiters.wait_for_volume_status(self.volumes_client,
self.volume['id'], 'in-use')
- self.addCleanup(self._detach, self.server['id'], self.volume['id'])
+ self.addCleanup(self._detach, server['id'], self.volume['id'])
@test.idempotent_id('52e9045a-e90d-4c0d-9087-79d657faffff')
def test_attach_detach_volume(self):
# Stop and Start a server with an attached volume, ensuring that
# the volume remains attached.
- self._create_and_attach()
+ server = self._create_server()
+ self._create_and_attach_volume(server)
- self.servers_client.stop_server(self.server['id'])
- waiters.wait_for_server_status(self.servers_client, self.server['id'],
+ self.servers_client.stop_server(server['id'])
+ waiters.wait_for_server_status(self.servers_client, server['id'],
'SHUTOFF')
- self.servers_client.start_server(self.server['id'])
- waiters.wait_for_server_status(self.servers_client, self.server['id'],
+ self.servers_client.start_server(server['id'])
+ waiters.wait_for_server_status(self.servers_client, server['id'],
'ACTIVE')
if CONF.validation.run_validation:
linux_client = remote_client.RemoteClient(
- self.get_server_ip(self.server),
+ self.get_server_ip(server),
self.image_ssh_user,
- self.admin_pass,
+ self.image_ssh_password,
self.validation_resources['keypair']['private_key'],
- server=self.server,
+ server=server,
servers_client=self.servers_client)
partitions = linux_client.get_partitions()
device_name_to_match = ' ' + self.device + '\n'
self.assertIn(device_name_to_match, partitions)
- self._detach(self.server['id'], self.volume['id'])
+ self._detach(server['id'], self.volume['id'])
self.attachment = None
- self.servers_client.stop_server(self.server['id'])
- waiters.wait_for_server_status(self.servers_client, self.server['id'],
+ self.servers_client.stop_server(server['id'])
+ waiters.wait_for_server_status(self.servers_client, server['id'],
'SHUTOFF')
- self.servers_client.start_server(self.server['id'])
- waiters.wait_for_server_status(self.servers_client, self.server['id'],
+ self.servers_client.start_server(server['id'])
+ waiters.wait_for_server_status(self.servers_client, server['id'],
'ACTIVE')
if CONF.validation.run_validation:
linux_client = remote_client.RemoteClient(
- self.get_server_ip(self.server),
+ self.get_server_ip(server),
self.image_ssh_user,
- self.admin_pass,
+ self.image_ssh_password,
self.validation_resources['keypair']['private_key'],
- server=self.server,
+ server=server,
servers_client=self.servers_client)
partitions = linux_client.get_partitions()
@@ -163,18 +147,20 @@
@test.idempotent_id('7fa563fe-f0f7-43eb-9e22-a1ece036b513')
def test_list_get_volume_attachments(self):
# Create Server, Volume and attach that Volume to Server
- self._create_and_attach()
+ server = self._create_server()
+ self._create_and_attach_volume(server)
+
# List Volume attachment of the server
body = self.servers_client.list_volume_attachments(
- self.server['id'])['volumeAttachments']
+ server['id'])['volumeAttachments']
self.assertEqual(1, len(body))
self.assertIn(self.attachment, body)
# Get Volume attachment of the server
body = self.servers_client.show_volume_attachment(
- self.server['id'],
+ server['id'],
self.attachment['id'])['volumeAttachment']
- self.assertEqual(self.server['id'], body['serverId'])
+ self.assertEqual(server['id'], body['serverId'])
self.assertEqual(self.volume['id'], body['volumeId'])
self.assertEqual(self.attachment['id'], body['id'])
@@ -189,39 +175,71 @@
min_microversion = '2.20'
max_microversion = 'latest'
- def _unshelve_server_and_check_volumes(self, number_of_partition):
- # Unshelve the instance and check that there are expected volumes
- self.servers_client.unshelve_server(self.server['id'])
- waiters.wait_for_server_status(self.servers_client,
- self.server['id'],
- 'ACTIVE')
+ def _count_volumes(self, server):
+ # Count number of volumes on an instance
+ volumes = 0
if CONF.validation.run_validation:
linux_client = remote_client.RemoteClient(
- self.get_server_ip(self.server['id']),
+ self.get_server_ip(server),
self.image_ssh_user,
- self.admin_pass,
+ self.image_ssh_password,
self.validation_resources['keypair']['private_key'],
- server=self.server,
+ server=server,
servers_client=self.servers_client)
- command = 'grep [vs]d /proc/partitions | wc -l'
- nb_partitions = linux_client.exec_command(command).strip()
- self.assertEqual(number_of_partition, nb_partitions)
+ command = 'grep -c -E [vs]d.$ /proc/partitions'
+ volumes = int(linux_client.exec_command(command).strip())
+ return volumes
+
+ def _shelve_server(self, server):
+ # NOTE(andreaf) If we are going to shelve a server, we should
+ # check first whether the server is ssh-able. Otherwise we
+ # won't be able to distinguish failures introduced by shelve
+ # from pre-existing ones. Also it's good to wait for cloud-init
+ # to be done and sshd server to be running before shelving to
+ # avoid breaking the VM
+ if CONF.validation.run_validation:
+ linux_client = remote_client.RemoteClient(
+ self.get_server_ip(server),
+ self.image_ssh_user,
+ self.image_ssh_password,
+ self.validation_resources['keypair']['private_key'],
+ server=server,
+ servers_client=self.servers_client)
+ linux_client.validate_authentication()
+
+ # If validation went ok, or it was skipped, shelve the server
+ compute.shelve_server(self.servers_client, server['id'])
+
+ def _unshelve_server_and_check_volumes(self, server, number_of_volumes):
+ # Unshelve the instance and check that there are expected volumes
+ self.servers_client.unshelve_server(server['id'])
+ waiters.wait_for_server_status(self.servers_client,
+ server['id'],
+ 'ACTIVE')
+ if CONF.validation.run_validation:
+ counted_volumes = self._count_volumes(server)
+ self.assertEqual(number_of_volumes, counted_volumes)
@test.idempotent_id('13a940b6-3474-4c3c-b03f-29b89112bfee')
@testtools.skipUnless(CONF.compute_feature_enabled.shelve,
'Shelve is not available.')
def test_attach_volume_shelved_or_offload_server(self):
- self._create_and_attach(shelve_server=True)
+ # Create server, count number of volumes on it, shelve
+ # server and attach pre-created volume to shelved server
+ server = self._create_server()
+ num_vol = self._count_volumes(server)
+ self._shelve_server(server)
+ self._create_and_attach_volume(server)
- # Unshelve the instance and check that there are two volumes
- self._unshelve_server_and_check_volumes('2')
+ # Unshelve the instance and check that attached volume exists
+ self._unshelve_server_and_check_volumes(server, num_vol + 1)
# Get Volume attachment of the server
volume_attachment = self.servers_client.show_volume_attachment(
- self.server['id'],
+ server['id'],
self.attachment['id'])['volumeAttachment']
- self.assertEqual(self.server['id'], volume_attachment['serverId'])
+ self.assertEqual(server['id'], volume_attachment['serverId'])
self.assertEqual(self.attachment['id'], volume_attachment['id'])
# Check the mountpoint is not None after unshelve server even in
# case of shelved_offloaded.
@@ -231,11 +249,17 @@
@testtools.skipUnless(CONF.compute_feature_enabled.shelve,
'Shelve is not available.')
def test_detach_volume_shelved_or_offload_server(self):
- self._create_and_attach(shelve_server=True)
+ # Create server, count number of volumes on it, shelve
+ # server and attach pre-created volume to shelved server
+ server = self._create_server()
+ num_vol = self._count_volumes(server)
+ self._shelve_server(server)
+ self._create_and_attach_volume(server)
# Detach the volume
- self._detach(self.server['id'], self.volume['id'])
+ self._detach(server['id'], self.volume['id'])
self.attachment = None
- # Unshelve the instance and check that there is only one volume
- self._unshelve_server_and_check_volumes('1')
+ # Unshelve the instance and check that we have the expected number of
+ # volume(s)
+ self._unshelve_server_and_check_volumes(server, num_vol)
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 3616e77..59ffc19 100644
--- a/tempest/api/identity/admin/v3/test_default_project_id.py
+++ b/tempest/api/identity/admin/v3/test_default_project_id.py
@@ -69,7 +69,7 @@
admin_role_id = admin_role['id']
# grant the admin role to the user on his project
- self.roles_client.assign_user_role_on_project(proj_id, user_id,
+ self.roles_client.create_user_role_on_project(proj_id, user_id,
admin_role_id)
# create a new client with user's credentials (NOTE: unscoped token!)
diff --git a/tempest/api/identity/admin/v3/test_roles.py b/tempest/api/identity/admin/v3/test_roles.py
index 4ecf0a5..f5bf923 100644
--- a/tempest/api/identity/admin/v3/test_roles.py
+++ b/tempest/api/identity/admin/v3/test_roles.py
@@ -94,7 +94,7 @@
@test.idempotent_id('c6b80012-fe4a-498b-9ce8-eb391c05169f')
def test_grant_list_revoke_role_to_user_on_project(self):
- self.roles_client.assign_user_role_on_project(self.project['id'],
+ self.roles_client.create_user_role_on_project(self.project['id'],
self.user_body['id'],
self.role['id'])
@@ -115,7 +115,7 @@
@test.idempotent_id('6c9a2940-3625-43a3-ac02-5dcec62ef3bd')
def test_grant_list_revoke_role_to_user_on_domain(self):
- self.roles_client.assign_user_role_on_domain(
+ self.roles_client.create_user_role_on_domain(
self.domain['id'], self.user_body['id'], self.role['id'])
roles = self.roles_client.list_user_roles_on_domain(
@@ -136,7 +136,7 @@
@test.idempotent_id('cbf11737-1904-4690-9613-97bcbb3df1c4')
def test_grant_list_revoke_role_to_group_on_project(self):
# Grant role to group on project
- self.roles_client.assign_group_role_on_project(
+ self.roles_client.create_group_role_on_project(
self.project['id'], self.group_body['id'], self.role['id'])
# List group roles on project
roles = self.roles_client.list_group_roles_on_project(
@@ -170,7 +170,7 @@
@test.idempotent_id('4bf8a70b-e785-413a-ad53-9f91ce02faa7')
def test_grant_list_revoke_role_to_group_on_domain(self):
- self.roles_client.assign_group_role_on_domain(
+ self.roles_client.create_group_role_on_domain(
self.domain['id'], self.group_body['id'], self.role['id'])
roles = self.roles_client.list_group_roles_on_domain(
diff --git a/tempest/api/identity/admin/v3/test_tokens.py b/tempest/api/identity/admin/v3/test_tokens.py
index fcf4772..8706cf7 100644
--- a/tempest/api/identity/admin/v3/test_tokens.py
+++ b/tempest/api/identity/admin/v3/test_tokens.py
@@ -83,11 +83,11 @@
self.addCleanup(self.roles_client.delete_role, role['id'])
# Grant the user the role on both projects.
- self.roles_client.assign_user_role_on_project(project1['id'],
+ self.roles_client.create_user_role_on_project(project1['id'],
user['id'],
role['id'])
- self.roles_client.assign_user_role_on_project(project2['id'],
+ self.roles_client.create_user_role_on_project(project2['id'],
user['id'],
role['id'])
diff --git a/tempest/api/identity/admin/v3/test_trusts.py b/tempest/api/identity/admin/v3/test_trusts.py
index 58e2ab8..4e69de8 100644
--- a/tempest/api/identity/admin/v3/test_trusts.py
+++ b/tempest/api/identity/admin/v3/test_trusts.py
@@ -77,11 +77,11 @@
self.not_delegated_role_id = role['id']
# Assign roles to trustor
- self.roles_client.assign_user_role_on_project(
+ self.roles_client.create_user_role_on_project(
self.trustor_project_id,
self.trustor_user_id,
self.delegated_role_id)
- self.roles_client.assign_user_role_on_project(
+ self.roles_client.create_user_role_on_project(
self.trustor_project_id,
self.trustor_user_id,
self.not_delegated_role_id)
diff --git a/tempest/api/identity/admin/v3/test_users.py b/tempest/api/identity/admin/v3/test_users.py
index 1bcec62..fd2683e 100644
--- a/tempest/api/identity/admin/v3/test_users.py
+++ b/tempest/api/identity/admin/v3/test_users.py
@@ -130,7 +130,7 @@
self.addCleanup(
self.projects_client.delete_project, project_body['id'])
# Assigning roles to user on project
- self.roles_client.assign_user_role_on_project(project['id'],
+ self.roles_client.create_user_role_on_project(project['id'],
user['id'],
role['id'])
assigned_project_ids.append(project['id'])
diff --git a/tempest/api/identity/base.py b/tempest/api/identity/base.py
index deb5413..9e40c42 100644
--- a/tempest/api/identity/base.py
+++ b/tempest/api/identity/base.py
@@ -23,6 +23,12 @@
class BaseIdentityTest(tempest.test.BaseTestCase):
@classmethod
+ def setup_credentials(cls):
+ # Create no network resources for these test.
+ cls.set_network_resources()
+ super(BaseIdentityTest, cls).setup_credentials()
+
+ @classmethod
def disable_user(cls, user_name):
user = cls.get_user_by_name(user_name)
cls.users_client.update_user_enabled(user['id'], enabled=False)
@@ -119,10 +125,6 @@
super(BaseIdentityV2AdminTest, cls).resource_setup()
cls.projects_client = cls.tenants_client
- @classmethod
- def resource_cleanup(cls):
- super(BaseIdentityV2AdminTest, cls).resource_cleanup()
-
def setup_test_user(self, password=None):
"""Set up a test user."""
tenant = self.setup_test_tenant()
@@ -187,14 +189,6 @@
cls.os_adm.auth_provider.scope = 'domain'
@classmethod
- def resource_setup(cls):
- super(BaseIdentityV3AdminTest, cls).resource_setup()
-
- @classmethod
- def resource_cleanup(cls):
- super(BaseIdentityV3AdminTest, cls).resource_cleanup()
-
- @classmethod
def disable_user(cls, user_name, domain_id=None):
user = cls.get_user_by_name(user_name, domain_id)
cls.users_client.update_user(user['id'], name=user_name, enabled=False)
diff --git a/tempest/api/object_storage/test_account_services.py b/tempest/api/object_storage/test_account_services.py
index 723b870..9e9f08b 100644
--- a/tempest/api/object_storage/test_account_services.py
+++ b/tempest/api/object_storage/test_account_services.py
@@ -78,7 +78,16 @@
# container request, the response does not contain 'accept-ranges'
# header. This is a special case, therefore the existence of response
# headers is checked without custom matcher.
- self.assertIn('content-length', resp)
+ #
+ # As the expected response is 204 No Content, Content-Length presence
+ # is not checked here intensionally. According to RFC 7230 a server
+ # MUST NOT send the header in such responses. Thus, clients should not
+ # depend on this header. However, the standard does not require them
+ # to validate the server's behavior. We leverage that to not refuse
+ # any implementation violating it like Swift [1] or some versions of
+ # Ceph RadosGW [2].
+ # [1] https://bugs.launchpad.net/swift/+bug/1537811
+ # [2] http://tracker.ceph.com/issues/13582
self.assertIn('x-timestamp', resp)
self.assertIn('x-account-bytes-used', resp)
self.assertIn('x-account-container-count', resp)
diff --git a/tempest/api/volume/admin/test_multi_backend.py b/tempest/api/volume/admin/test_multi_backend.py
index f665e69..120dbb1 100644
--- a/tempest/api/volume/admin/test_multi_backend.py
+++ b/tempest/api/volume/admin/test_multi_backend.py
@@ -66,8 +66,8 @@
cls.type = cls.create_volume_type(name=type_name,
extra_specs=extra_specs)
- params = {cls.name_field: vol_name, 'volume_type': type_name}
-
+ params = {cls.name_field: vol_name, 'volume_type': type_name,
+ 'size': CONF.volume.volume_size}
cls.volume = cls.admin_volume_client.create_volume(
**params)['volume']
if with_prefix:
diff --git a/tempest/api/volume/admin/test_qos.py b/tempest/api/volume/admin/test_qos.py
index f1101e1..98139e7 100755
--- a/tempest/api/volume/admin/test_qos.py
+++ b/tempest/api/volume/admin/test_qos.py
@@ -119,8 +119,7 @@
self.admin_volume_qos_client.unset_qos_key(self.created_qos['id'],
keys)
operation = 'qos-key-unset'
- self.admin_volume_qos_client.wait_for_qos_operations(
- self.created_qos['id'], operation, keys)
+ self.wait_for_qos_operations(self.created_qos['id'], operation, keys)
body = self.admin_volume_qos_client.show_qos(
self.created_qos['id'])['qos_specs']
self.assertNotIn(keys[0], body['specs'])
@@ -154,8 +153,8 @@
self.admin_volume_qos_client.disassociate_qos(
self.created_qos['id'], vol_type[0]['id'])
operation = 'disassociate'
- self.admin_volume_qos_client.wait_for_qos_operations(
- self.created_qos['id'], operation, vol_type[0]['id'])
+ self.wait_for_qos_operations(self.created_qos['id'],
+ operation, vol_type[0]['id'])
associations = self._test_get_association_qos()
self.assertNotIn(vol_type[0]['id'], associations)
@@ -163,8 +162,7 @@
self.admin_volume_qos_client.disassociate_all_qos(
self.created_qos['id'])
operation = 'disassociate-all'
- self.admin_volume_qos_client.wait_for_qos_operations(
- self.created_qos['id'], operation)
+ self.wait_for_qos_operations(self.created_qos['id'], operation)
associations = self._test_get_association_qos()
self.assertEmpty(associations)
diff --git a/tempest/api/volume/admin/test_volume_quotas_negative.py b/tempest/api/volume/admin/test_volume_quotas_negative.py
index 89e4d18..c19b1c4 100644
--- a/tempest/api/volume/admin/test_volume_quotas_negative.py
+++ b/tempest/api/volume/admin/test_volume_quotas_negative.py
@@ -14,9 +14,12 @@
# under the License.
from tempest.api.volume import base
+from tempest import config
from tempest.lib import exceptions as lib_exc
from tempest import test
+CONF = config.CONF
+
class BaseVolumeQuotasNegativeV2TestJSON(base.BaseVolumeAdminTest):
force_tenant_isolation = True
@@ -29,8 +32,7 @@
@classmethod
def resource_setup(cls):
super(BaseVolumeQuotasNegativeV2TestJSON, cls).resource_setup()
- cls.default_volume_size = cls.volumes_client.default_volume_size
- cls.shared_quota_set = {'gigabytes': 2 * cls.default_volume_size,
+ cls.shared_quota_set = {'gigabytes': 2 * CONF.volume.volume_size,
'volumes': 1}
# NOTE(gfidente): no need to restore original quota set
@@ -47,7 +49,8 @@
@test.idempotent_id('bf544854-d62a-47f2-a681-90f7a47d86b6')
def test_quota_volumes(self):
self.assertRaises(lib_exc.OverLimit,
- self.volumes_client.create_volume)
+ self.volumes_client.create_volume,
+ size=CONF.volume.volume_size)
@test.attr(type='negative')
@test.idempotent_id('2dc27eee-8659-4298-b900-169d71a91374')
@@ -58,13 +61,14 @@
self.addCleanup(self.admin_quotas_client.update_quota_set,
self.demo_tenant_id,
**self.shared_quota_set)
- new_quota_set = {'gigabytes': self.default_volume_size,
+ new_quota_set = {'gigabytes': CONF.volume.volume_size,
'volumes': 2, 'snapshots': 1}
self.admin_quotas_client.update_quota_set(
self.demo_tenant_id,
**new_quota_set)
self.assertRaises(lib_exc.OverLimit,
- self.volumes_client.create_volume)
+ self.volumes_client.create_volume,
+ size=CONF.volume.volume_size)
class VolumeQuotasNegativeV1TestJSON(BaseVolumeQuotasNegativeV2TestJSON):
diff --git a/tempest/api/volume/admin/test_volume_snapshot_quotas_negative.py b/tempest/api/volume/admin/test_volume_snapshot_quotas_negative.py
index 1565a8c..09af7fe 100644
--- a/tempest/api/volume/admin/test_volume_snapshot_quotas_negative.py
+++ b/tempest/api/volume/admin/test_volume_snapshot_quotas_negative.py
@@ -38,7 +38,7 @@
@classmethod
def resource_setup(cls):
super(VolumeSnapshotQuotasNegativeV2TestJSON, cls).resource_setup()
- cls.default_volume_size = cls.volumes_client.default_volume_size
+ cls.default_volume_size = CONF.volume.volume_size
cls.shared_quota_set = {'gigabytes': 3 * cls.default_volume_size,
'volumes': 1, 'snapshots': 1}
diff --git a/tempest/api/volume/admin/test_volume_type_access.py b/tempest/api/volume/admin/test_volume_type_access.py
index fac71a8..91ff5af 100644
--- a/tempest/api/volume/admin/test_volume_type_access.py
+++ b/tempest/api/volume/admin/test_volume_type_access.py
@@ -17,9 +17,12 @@
from tempest.api.volume import base
from tempest.common import waiters
+from tempest import config
from tempest.lib import exceptions as lib_exc
from tempest import test
+CONF = config.CONF
+
class VolumeTypesAccessV2Test(base.BaseVolumeAdminTest):
@@ -38,7 +41,8 @@
# Try creating a volume from volume type in primary tenant
self.assertRaises(lib_exc.NotFound, self.volumes_client.create_volume,
- volume_type=volume_type['id'])
+ volume_type=volume_type['id'],
+ size=CONF.volume.volume_size)
# Adding volume type access for primary tenant
self.admin_volume_types_client.add_type_access(
@@ -49,7 +53,8 @@
# Creating a volume from primary tenant
volume = self.volumes_client.create_volume(
- volume_type=volume_type['id'])['volume']
+ volume_type=volume_type['id'],
+ size=CONF.volume.volume_size)['volume']
self.addCleanup(self.delete_volume, self.volumes_client, volume['id'])
waiters.wait_for_volume_status(self.volumes_client, volume['id'],
'available')
diff --git a/tempest/api/volume/admin/test_volume_types.py b/tempest/api/volume/admin/test_volume_types.py
index 7b4379b..646bc68 100755
--- a/tempest/api/volume/admin/test_volume_types.py
+++ b/tempest/api/volume/admin/test_volume_types.py
@@ -50,7 +50,8 @@
extra_specs=extra_specs)
volume_types.append(vol_type)
params = {self.name_field: vol_name,
- 'volume_type': volume_types[0]['id']}
+ 'volume_type': volume_types[0]['id'],
+ 'size': CONF.volume.volume_size}
# Create volume
volume = self.volumes_client.create_volume(**params)['volume']
@@ -127,7 +128,7 @@
body = self.create_volume_type(name=name)
# Create encryption type
encryption_type = \
- self.admin_volume_types_client.create_encryption_type(
+ self.admin_encryption_types_client.create_encryption_type(
body['id'], provider=provider,
control_location=control_location)['encryption']
self.assertIn('volume_type_id', encryption_type)
@@ -140,7 +141,7 @@
# Get encryption type
fetched_encryption_type = (
- self.admin_volume_types_client.show_encryption_type(
+ self.admin_encryption_types_client.show_encryption_type(
encryption_type['volume_type_id']))
self.assertEqual(provider,
fetched_encryption_type['provider'],
@@ -152,14 +153,11 @@
'different from the created encryption_type')
# Delete encryption type
- self.admin_volume_types_client.delete_encryption_type(
- encryption_type['volume_type_id'])
- resource = {"id": encryption_type['volume_type_id'],
- "type": "encryption-type"}
- self.admin_volume_types_client.wait_for_resource_deletion(resource)
+ type_id = encryption_type['volume_type_id']
+ self.admin_encryption_types_client.delete_encryption_type(type_id)
+ self.admin_encryption_types_client.wait_for_resource_deletion(type_id)
deleted_encryption_type = (
- self.admin_volume_types_client.show_encryption_type(
- encryption_type['volume_type_id']))
+ self.admin_encryption_types_client.show_encryption_type(type_id))
self.assertEmpty(deleted_encryption_type)
@test.idempotent_id('cf9f07c6-db9e-4462-a243-5933ad65e9c8')
diff --git a/tempest/api/volume/admin/test_volumes_actions.py b/tempest/api/volume/admin/test_volumes_actions.py
index 03927e6..9686473 100755
--- a/tempest/api/volume/admin/test_volumes_actions.py
+++ b/tempest/api/volume/admin/test_volumes_actions.py
@@ -16,8 +16,11 @@
from tempest.api.volume import base
from tempest.common.utils import data_utils as utils
from tempest.common import waiters
+from tempest import config
from tempest import test
+CONF = config.CONF
+
class VolumesActionsV2Test(base.BaseVolumeAdminTest):
@@ -33,7 +36,7 @@
# Create a test shared volume for tests
vol_name = utils.rand_name(cls.__name__ + '-Volume')
cls.name_field = cls.special_fields['name_field']
- params = {cls.name_field: vol_name}
+ params = {cls.name_field: vol_name, 'size': CONF.volume.volume_size}
cls.volume = cls.client.create_volume(**params)['volume']
waiters.wait_for_volume_status(cls.client,
@@ -60,7 +63,7 @@
def _create_temp_volume(self):
# Create a temp volume for force delete tests
vol_name = utils.rand_name(self.__class__.__name__ + '-Volume')
- params = {self.name_field: vol_name}
+ params = {self.name_field: vol_name, 'size': CONF.volume.volume_size}
temp_volume = self.client.create_volume(**params)['volume']
waiters.wait_for_volume_status(self.client,
temp_volume['id'], 'available')
diff --git a/tempest/api/volume/admin/test_volumes_list.py b/tempest/api/volume/admin/test_volumes_list.py
index 70c16f3..4437803 100644
--- a/tempest/api/volume/admin/test_volumes_list.py
+++ b/tempest/api/volume/admin/test_volumes_list.py
@@ -17,8 +17,11 @@
from tempest.api.volume import base
from tempest.common import waiters
+from tempest import config
from tempest import test
+CONF = config.CONF
+
class VolumesListAdminV2TestJSON(base.BaseVolumeAdminTest):
@@ -38,7 +41,8 @@
def test_volume_list_param_tenant(self):
# Test to list volumes from single tenant
# Create a volume in admin tenant
- adm_vol = self.admin_volume_client.create_volume()['volume']
+ adm_vol = self.admin_volume_client.create_volume(
+ size=CONF.volume.volume_size)['volume']
waiters.wait_for_volume_status(self.admin_volume_client,
adm_vol['id'], 'available')
self.addCleanup(self.admin_volume_client.delete_volume, adm_vol['id'])
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index ef28add..183452c 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -13,12 +13,15 @@
# License for the specific language governing permissions and limitations
# under the License.
+import time
+
from tempest.common import compute
from tempest.common.utils import data_utils
from tempest.common import waiters
from tempest import config
from tempest import exceptions
from tempest.lib.common.utils import test_utils
+from tempest.lib import exceptions as lib_exc
import tempest.test
CONF = config.CONF
@@ -110,6 +113,9 @@
@classmethod
def create_volume(cls, **kwargs):
"""Wrapper utility that returns a test volume."""
+ if 'size' not in kwargs:
+ kwargs['size'] = CONF.volume.volume_size
+
name = data_utils.rand_name(cls.__name__ + '-Volume')
name_field = cls.special_fields['name_field']
@@ -198,6 +204,8 @@
cls.admin_hosts_client = cls.os_adm.volume_hosts_client
cls.admin_snapshots_client = cls.os_adm.snapshots_client
cls.admin_backups_client = cls.os_adm.backups_client
+ cls.admin_encryption_types_client = \
+ cls.os_adm.encryption_types_client
cls.admin_quotas_client = cls.os_adm.volume_quotas_client
elif cls._api_version == 2:
cls.admin_volume_qos_client = cls.os_adm.volume_qos_v2_client
@@ -208,6 +216,8 @@
cls.admin_hosts_client = cls.os_adm.volume_hosts_v2_client
cls.admin_snapshots_client = cls.os_adm.snapshots_v2_client
cls.admin_backups_client = cls.os_adm.backups_v2_client
+ cls.admin_encryption_types_client = \
+ cls.os_adm.encryption_types_v2_client
cls.admin_quotas_client = cls.os_adm.volume_quotas_v2_client
@classmethod
@@ -259,9 +269,38 @@
cls.admin_volume_types_client.delete_volume_type, vol_type)
for vol_type in cls.volume_types:
- # Resource dictionary uses for is_resource_deleted method,
- # to distinguish between volume-type to encryption-type.
- resource = {'id': vol_type, 'type': 'volume-type'}
test_utils.call_and_ignore_notfound_exc(
cls.admin_volume_types_client.wait_for_resource_deletion,
- resource)
+ vol_type)
+
+ def wait_for_qos_operations(self, qos_id, operation, args=None):
+ """Waits for a qos operations to be completed.
+
+ NOTE : operation value is required for wait_for_qos_operations()
+ operation = 'qos-key' / 'disassociate' / 'disassociate-all'
+ args = keys[] when operation = 'qos-key'
+ args = volume-type-id disassociated when operation = 'disassociate'
+ args = None when operation = 'disassociate-all'
+ """
+ start_time = int(time.time())
+ client = self.admin_volume_qos_client
+ while True:
+ if operation == 'qos-key-unset':
+ body = client.show_qos(qos_id)['qos_specs']
+ if not any(key in body['specs'] for key in args):
+ return
+ elif operation == 'disassociate':
+ body = client.show_association_qos(qos_id)['qos_associations']
+ if not any(args in body[i]['id'] for i in range(0, len(body))):
+ return
+ elif operation == 'disassociate-all':
+ body = client.show_association_qos(qos_id)['qos_associations']
+ if not body:
+ return
+ else:
+ msg = (" operation value is either not defined or incorrect.")
+ raise lib_exc.UnprocessableEntity(msg)
+
+ if int(time.time()) - start_time >= self.build_timeout:
+ raise exceptions.TimeoutException
+ time.sleep(self.build_interval)
diff --git a/tempest/api/volume/test_volumes_actions.py b/tempest/api/volume/test_volumes_actions.py
index d5e1e6b..7783c18 100755
--- a/tempest/api/volume/test_volumes_actions.py
+++ b/tempest/api/volume/test_volumes_actions.py
@@ -114,7 +114,8 @@
self.addCleanup(self.client.detach_volume, self.volume['id'])
volume = self.client.show_volume(self.volume['id'])['volume']
self.assertIn('attachments', volume)
- attachment = self.client.get_attachment_from_volume(volume)
+ attachment = volume['attachments'][0]
+
self.assertEqual('/dev/%s' %
CONF.compute.volume_device_name,
attachment['device'])
diff --git a/tempest/api/volume/test_volumes_get.py b/tempest/api/volume/test_volumes_get.py
index 7a1c0a1..07f799b 100755
--- a/tempest/api/volume/test_volumes_get.py
+++ b/tempest/api/volume/test_volumes_get.py
@@ -105,7 +105,8 @@
# then test volume update if display_name is duplicated
new_v_desc = data_utils.rand_name('@#$%^* description')
params = {self.descrip_field: new_v_desc,
- 'availability_zone': volume['availability_zone']}
+ 'availability_zone': volume['availability_zone'],
+ 'size': CONF.volume.volume_size}
new_volume = self.client.create_volume(**params)['volume']
self.assertIn('id', new_volume)
self.addCleanup(self.delete_volume, self.client, new_volume['id'])
@@ -124,7 +125,7 @@
@test.attr(type='smoke')
@test.idempotent_id('27fb0e9f-fb64-41dd-8bdb-1ffa762f0d51')
def test_volume_create_get_update_delete(self):
- self._volume_create_get_update_delete()
+ self._volume_create_get_update_delete(size=CONF.volume.volume_size)
@test.attr(type='smoke')
@test.idempotent_id('54a01030-c7fc-447c-86ee-c1182beae638')
@@ -142,7 +143,8 @@
'Cinder volume clones are disabled')
def test_volume_create_get_update_delete_as_clone(self):
origin = self.create_volume()
- self._volume_create_get_update_delete(source_volid=origin['id'])
+ self._volume_create_get_update_delete(source_volid=origin['id'],
+ size=CONF.volume.volume_size)
class VolumesV1GetTest(VolumesV2GetTest):
diff --git a/tempest/api/volume/test_volumes_negative.py b/tempest/api/volume/test_volumes_negative.py
index d2c05ae..16c8571 100755
--- a/tempest/api/volume/test_volumes_negative.py
+++ b/tempest/api/volume/test_volumes_negative.py
@@ -299,4 +299,3 @@
class VolumesV1NegativeTest(VolumesV2NegativeTest):
_api_version = 1
- _name = 'display_name'
diff --git a/tempest/api/volume/v3/admin/test_user_messages.py b/tempest/api/volume/v3/admin/test_user_messages.py
index 517c8d7..39a5dfa 100755
--- a/tempest/api/volume/v3/admin/test_user_messages.py
+++ b/tempest/api/volume/v3/admin/test_user_messages.py
@@ -16,9 +16,12 @@
from tempest.api.volume.v3 import base
from tempest.common.utils import data_utils
from tempest.common import waiters
+from tempest import config
from tempest import exceptions
from tempest import test
+CONF = config.CONF
+
MESSAGE_KEYS = [
'created_at',
'event_id',
@@ -49,7 +52,8 @@
extra_specs=extra_specs)['volume_type']
self.addCleanup(self.admin_volume_types_client.delete_volume_type,
bogus_type['id'])
- params = {'volume_type': bogus_type['id']}
+ params = {'volume_type': bogus_type['id'],
+ 'size': CONF.volume.volume_size}
volume = self.volumes_client.create_volume(**params)['volume']
self.addCleanup(self.delete_volume, self.volumes_client, volume['id'])
try:
diff --git a/tempest/clients.py b/tempest/clients.py
index e14f6f8..f8c276a 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -293,16 +293,18 @@
**params)
self.backups_v2_client = volume.v2.BackupsClient(self.auth_provider,
**params)
+ self.encryption_types_client = volume.v1.EncryptionTypesClient(
+ self.auth_provider, **params)
+ self.encryption_types_v2_client = volume.v2.EncryptionTypesClient(
+ self.auth_provider, **params)
self.snapshots_client = volume.v1.SnapshotsClient(self.auth_provider,
**params)
self.snapshots_v2_client = volume.v2.SnapshotsClient(
self.auth_provider, **params)
- self.volumes_client = volume.v1.VolumesClient(
- self.auth_provider, default_volume_size=CONF.volume.volume_size,
- **params)
- self.volumes_v2_client = volume.v2.VolumesClient(
- self.auth_provider, default_volume_size=CONF.volume.volume_size,
- **params)
+ self.volumes_client = volume.v1.VolumesClient(self.auth_provider,
+ **params)
+ self.volumes_v2_client = volume.v2.VolumesClient(self.auth_provider,
+ **params)
self.volume_messages_client = volume.v3.MessagesClient(
self.auth_provider, **params)
self.volume_types_client = volume.v1.TypesClient(self.auth_provider,
diff --git a/tempest/common/compute.py b/tempest/common/compute.py
index 194b9e9..8e9f0b0 100644
--- a/tempest/common/compute.py
+++ b/tempest/common/compute.py
@@ -107,7 +107,8 @@
volumes_client = clients.volumes_client
volume = volumes_client.create_volume(
display_name=volume_name,
- imageRef=image_id)
+ imageRef=image_id,
+ size=CONF.volume.volume_size)
waiters.wait_for_volume_status(volumes_client,
volume['volume']['id'], 'available')
diff --git a/tempest/common/cred_client.py b/tempest/common/cred_client.py
index 4e3c395..ad968f1 100644
--- a/tempest/common/cred_client.py
+++ b/tempest/common/cred_client.py
@@ -17,7 +17,7 @@
from tempest.lib import auth
from tempest.lib import exceptions as lib_exc
-from tempest.services.identity.v2.json import identity_client as v2_identity
+from tempest.lib.services.identity.v2 import identity_client as v2_identity
LOG = logging.getLogger(__name__)
@@ -74,7 +74,9 @@
msg = 'No "%s" role found' % role_name
raise lib_exc.NotFound(msg)
try:
- self._assign_user_role(project, user, role)
+ self.roles_client.create_user_role_on_project(project['id'],
+ user['id'],
+ role['id'])
except lib_exc.Conflict:
LOG.debug("Role %s already assigned on project %s for user %s" % (
role['id'], project['id'], user['id']))
@@ -124,11 +126,6 @@
tenant_name=project['name'], tenant_id=project['id'],
password=password)
- def _assign_user_role(self, project, user, role):
- self.roles_client.create_user_role_on_project(project['id'],
- user['id'],
- role['id'])
-
class V3CredsClient(CredsClient):
project_id_param = 'project_id'
@@ -176,11 +173,6 @@
domain_id=self.creds_domain['id'],
domain_name=self.creds_domain['name'])
- def _assign_user_role(self, project, user, role):
- self.roles_client.assign_user_role_on_project(project['id'],
- user['id'],
- role['id'])
-
def assign_user_role_on_domain(self, user, role_name, domain=None):
"""Assign the specified role on a domain
@@ -198,7 +190,7 @@
msg = 'No "%s" role found' % role_name
raise lib_exc.NotFound(msg)
try:
- self.roles_client.assign_user_role_on_domain(
+ self.roles_client.create_user_role_on_domain(
domain['id'], user['id'], role['id'])
except lib_exc.Conflict:
LOG.debug("Role %s already assigned on domain %s for user %s",
diff --git a/tempest/common/custom_matchers.py b/tempest/common/custom_matchers.py
index 8ba33ed..998612b 100644
--- a/tempest/common/custom_matchers.py
+++ b/tempest/common/custom_matchers.py
@@ -37,13 +37,32 @@
self.target = target
self.method = method
+ def _content_length_required(self, resp):
+ # Verify whether given HTTP response must contain content-length.
+ # Take into account the exceptions defined in RFC 7230.
+ if resp.status in range(100, 200) or resp.status == 204:
+ return False
+
+ return True
+
def match(self, actual):
"""Check headers
- param: actual HTTP response headers
+ param: actual HTTP response object containing headers and status
"""
- # Check common headers for all HTTP methods
- if 'content-length' not in actual:
+ # Check common headers for all HTTP methods.
+ #
+ # Please note that for 1xx and 204 responses Content-Length presence
+ # is not checked intensionally. According to RFC 7230 a server MUST
+ # NOT send the header in such responses. Thus, clients should not
+ # depend on this header. However, the standard does not require them
+ # to validate the server's behavior. We leverage that to not refuse
+ # any implementation violating it like Swift [1] or some versions of
+ # Ceph RadosGW [2].
+ # [1] https://bugs.launchpad.net/swift/+bug/1537811
+ # [2] http://tracker.ceph.com/issues/13582
+ if ('content-length' not in actual and
+ self._content_length_required(actual)):
return NonExistentHeader('content-length')
if 'content-type' not in actual:
return NonExistentHeader('content-type')
diff --git a/tempest/lib/common/ssh.py b/tempest/lib/common/ssh.py
index 8e83775..c13f41a 100644
--- a/tempest/lib/common/ssh.py
+++ b/tempest/lib/common/ssh.py
@@ -77,7 +77,7 @@
self.username, self.host)
return ssh
except (EOFError,
- socket.error,
+ socket.error, socket.timeout,
paramiko.SSHException) as e:
if self._is_timed_out(_start_time):
LOG.exception("Failed to establish authenticated ssh"
diff --git a/tempest/lib/common/utils/test_utils.py b/tempest/lib/common/utils/test_utils.py
index 50a1a7d..3b28701 100644
--- a/tempest/lib/common/utils/test_utils.py
+++ b/tempest/lib/common/utils/test_utils.py
@@ -14,6 +14,7 @@
# under the License.
import inspect
import re
+import time
from oslo_log import log as logging
@@ -83,3 +84,24 @@
return func(*args, **kwargs)
except exceptions.NotFound:
pass
+
+
+def call_until_true(func, duration, sleep_for):
+ """Call the given function until it returns True (and return True)
+
+ or until the specified duration (in seconds) elapses (and return False).
+
+ :param func: A zero argument callable that returns True on success.
+ :param duration: The number of seconds for which to attempt a
+ successful call of the function.
+ :param sleep_for: The number of seconds to sleep after an unsuccessful
+ invocation of the function.
+ """
+ now = time.time()
+ timeout = now + duration
+ while now < timeout:
+ if func():
+ return True
+ time.sleep(sleep_for)
+ now = time.time()
+ return False
diff --git a/tempest/services/identity/v2/json/identity_client.py b/tempest/lib/services/identity/v2/identity_client.py
similarity index 100%
rename from tempest/services/identity/v2/json/identity_client.py
rename to tempest/lib/services/identity/v2/identity_client.py
diff --git a/tempest/lib/services/identity/v2/tenants_client.py b/tempest/lib/services/identity/v2/tenants_client.py
index 77ddaa5..f92c703 100644
--- a/tempest/lib/services/identity/v2/tenants_client.py
+++ b/tempest/lib/services/identity/v2/tenants_client.py
@@ -25,7 +25,8 @@
"""Create a tenant
Available params: see http://developer.openstack.org/
- api-ref-identity-v2-ext.html#createTenant
+ api-ref/identity/v2-admin/index.html#
+ create-tenant
"""
post_body = json.dumps({'tenant': kwargs})
resp, body = self.post('tenants', post_body)
@@ -59,7 +60,8 @@
"""Returns tenants.
Available params: see http://developer.openstack.org/
- api-ref-identity-v2-ext.html#admin-listTenants
+ api-ref/identity/v2-admin/index.html#
+ list-tenants-admin-endpoint
"""
url = 'tenants'
if params:
@@ -73,7 +75,8 @@
"""Updates a tenant.
Available params: see http://developer.openstack.org/
- api-ref-identity-v2-ext.html#updateTenant
+ api-ref/identity/v2-admin/index.html#
+ update-tenant
"""
if 'id' not in kwargs:
kwargs['id'] = tenant_id
@@ -87,7 +90,8 @@
"""List users for a Tenant.
Available params: see http://developer.openstack.org/
- api-ref-identity-v2-ext.html#listUsersForTenant
+ api-ref/identity/v2-admin/index.html#
+ list-users-on-a-tenant
"""
url = '/tenants/%s/users' % tenant_id
if params:
diff --git a/tempest/lib/services/identity/v2/users_client.py b/tempest/lib/services/identity/v2/users_client.py
index 4ea17f9..2a266d9 100644
--- a/tempest/lib/services/identity/v2/users_client.py
+++ b/tempest/lib/services/identity/v2/users_client.py
@@ -23,7 +23,8 @@
"""Create a user.
Available params: see http://developer.openstack.org/
- api-ref-identity-admin-v2.html#admin-createUser
+ api-ref/identity/v2-admin/index.html#
+ create-user-admin-endpoint
"""
post_body = json.dumps({'user': kwargs})
resp, body = self.post('users', post_body)
@@ -35,7 +36,8 @@
"""Updates a user.
Available params: see http://developer.openstack.org/
- api-ref-identity-admin-v2.html#admin-updateUser
+ api-ref/identity/v2-admin/index.html#
+ update-user-admin-endpoint
"""
put_body = json.dumps({'user': kwargs})
resp, body = self.put('users/%s' % user_id, put_body)
@@ -68,7 +70,8 @@
"""Get the list of users.
Available params: see http://developer.openstack.org/
- api-ref-identity-admin-v2.html#admin-listUsers
+ api-ref/identity/v2-admin/index.html#
+ list-users-admin-endpoint
"""
url = "users"
if params:
diff --git a/tempest/services/identity/v3/json/groups_client.py b/tempest/lib/services/identity/v3/groups_client.py
similarity index 100%
rename from tempest/services/identity/v3/json/groups_client.py
rename to tempest/lib/services/identity/v3/groups_client.py
diff --git a/tempest/services/identity/v3/json/projects_client.py b/tempest/lib/services/identity/v3/projects_client.py
similarity index 100%
rename from tempest/services/identity/v3/json/projects_client.py
rename to tempest/lib/services/identity/v3/projects_client.py
diff --git a/tempest/services/identity/v3/json/users_clients.py b/tempest/lib/services/identity/v3/users_client.py
similarity index 100%
rename from tempest/services/identity/v3/json/users_clients.py
rename to tempest/lib/services/identity/v3/users_client.py
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index fdccfc3..233d747 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -213,14 +213,15 @@
def create_volume(self, size=None, name=None, snapshot_id=None,
imageRef=None, volume_type=None):
+ if size is None:
+ size = CONF.volume.volume_size
if name is None:
name = data_utils.rand_name(self.__class__.__name__)
kwargs = {'display_name': name,
'snapshot_id': snapshot_id,
'imageRef': imageRef,
- 'volume_type': volume_type}
- if size is not None:
- kwargs.update({'size': size})
+ 'volume_type': volume_type,
+ 'size': size}
volume = self.volumes_client.create_volume(**kwargs)['volume']
self.addCleanup(self.volumes_client.wait_for_resource_deletion,
@@ -513,7 +514,7 @@
'should_succeed':
'reachable' if should_succeed else 'unreachable'
})
- result = tempest.test.call_until_true(ping, timeout, 1)
+ result = test_utils.call_until_true(ping, timeout, 1)
LOG.debug('%(caller)s finishes ping %(ip)s in %(timeout)s sec and the '
'ping result is %(result)s' % {
'caller': caller, 'ip': ip_address, 'timeout': timeout,
@@ -857,9 +858,9 @@
show_floatingip(floatingip_id)['floatingip'])
return status == result['status']
- tempest.test.call_until_true(refresh,
- CONF.network.build_timeout,
- CONF.network.build_interval)
+ test_utils.call_until_true(refresh,
+ CONF.network.build_timeout,
+ CONF.network.build_interval)
floating_ip = self.floating_ips_client.show_floatingip(
floatingip_id)['floatingip']
self.assertEqual(status, floating_ip['status'],
@@ -914,9 +915,9 @@
return not should_succeed
return should_succeed
- return tempest.test.call_until_true(ping_remote,
- CONF.validation.ping_timeout,
- 1)
+ return test_utils.call_until_true(ping_remote,
+ CONF.validation.ping_timeout,
+ 1)
def _create_security_group(self, security_group_rules_client=None,
tenant_id=None,
@@ -1249,7 +1250,7 @@
return True
return False
- if not tempest.test.call_until_true(
+ if not test_utils.call_until_true(
check_state, timeout, interval):
msg = ("Timed out waiting for node %s to reach %s state(s) %s" %
(node_id, state_attr, target_states))
@@ -1273,7 +1274,7 @@
self.get_node, instance_id=instance_id)
return node is not None
- if not tempest.test.call_until_true(
+ if not test_utils.call_until_true(
_get_node, CONF.baremetal.association_timeout, 1):
msg = ('Timed out waiting to get Ironic node by instance id %s'
% instance_id)
@@ -1345,8 +1346,12 @@
super(EncryptionScenarioTest, cls).setup_clients()
if CONF.volume_feature_enabled.api_v1:
cls.admin_volume_types_client = cls.os_adm.volume_types_client
+ cls.admin_encryption_types_client =\
+ cls.os_adm.encryption_types_client
else:
cls.admin_volume_types_client = cls.os_adm.volume_types_v2_client
+ cls.admin_encryption_types_client =\
+ cls.os_adm.encryption_types_v2_client
def create_volume_type(self, client=None, name=None):
if not client:
@@ -1365,7 +1370,7 @@
key_size=None, cipher=None,
control_location=None):
if not client:
- client = self.admin_volume_types_client
+ client = self.admin_encryption_types_client
if not type_id:
volume_type = self.create_volume_type()
type_id = volume_type['id']
diff --git a/tempest/scenario/test_minimum_basic.py b/tempest/scenario/test_minimum_basic.py
index f7c7434..dba1c92 100644
--- a/tempest/scenario/test_minimum_basic.py
+++ b/tempest/scenario/test_minimum_basic.py
@@ -17,6 +17,7 @@
from tempest.common import waiters
from tempest import config
from tempest import exceptions
+from tempest.lib.common.utils import test_utils
from tempest.scenario import manager
from tempest import test
@@ -88,9 +89,9 @@
['server'])
return {'name': secgroup['name']} in body['security_groups']
- if not test.call_until_true(wait_for_secgroup_add,
- CONF.compute.build_timeout,
- CONF.compute.build_interval):
+ if not test_utils.call_until_true(wait_for_secgroup_add,
+ CONF.compute.build_timeout,
+ CONF.compute.build_interval):
msg = ('Timed out waiting for adding security group %s to server '
'%s' % (secgroup['id'], server['id']))
raise exceptions.TimeoutException(msg)
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index e0e1204..519dbec 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -263,8 +263,9 @@
if port['id'] != old_port['id']]
return len(self.new_port_list) == 1
- if not test.call_until_true(check_ports, CONF.network.build_timeout,
- CONF.network.build_interval):
+ if not test_utils.call_until_true(
+ check_ports, CONF.network.build_timeout,
+ CONF.network.build_interval):
raise exceptions.TimeoutException(
"No new port attached to the server in time (%s sec)! "
"Old port: %s. Number of new ports: %d" % (
@@ -277,8 +278,9 @@
self.diff_list = [n for n in new_nic_list if n not in old_nic_list]
return len(self.diff_list) == 1
- if not test.call_until_true(check_new_nic, CONF.network.build_timeout,
- CONF.network.build_interval):
+ if not test_utils.call_until_true(
+ check_new_nic, CONF.network.build_timeout,
+ CONF.network.build_interval):
raise exceptions.TimeoutException("Interface not visible on the "
"guest after %s sec"
% CONF.network.build_timeout)
@@ -593,9 +595,9 @@
return False
return True
- self.assertTrue(test.call_until_true(check_new_dns_server,
- renew_timeout,
- renew_delay),
+ self.assertTrue(test_utils.call_until_true(check_new_dns_server,
+ renew_timeout,
+ renew_delay),
msg="DHCP renewal failed to fetch "
"new DNS nameservers")
diff --git a/tempest/scenario/test_network_v6.py b/tempest/scenario/test_network_v6.py
index 364b6f5..dd86d90 100644
--- a/tempest/scenario/test_network_v6.py
+++ b/tempest/scenario/test_network_v6.py
@@ -187,10 +187,10 @@
srv2_v6_addr_assigned = functools.partial(
guest_has_address, sshv4_2, ips_from_api_2['6'][i])
- self.assertTrue(test.call_until_true(srv1_v6_addr_assigned,
+ self.assertTrue(test_utils.call_until_true(srv1_v6_addr_assigned,
CONF.validation.ping_timeout, 1))
- self.assertTrue(test.call_until_true(srv2_v6_addr_assigned,
+ self.assertTrue(test_utils.call_until_true(srv2_v6_addr_assigned,
CONF.validation.ping_timeout, 1))
self._check_connectivity(sshv4_1, ips_from_api_2['4'])
diff --git a/tempest/scenario/test_server_basic_ops.py b/tempest/scenario/test_server_basic_ops.py
index 60dca3d..e031ff7 100644
--- a/tempest/scenario/test_server_basic_ops.py
+++ b/tempest/scenario/test_server_basic_ops.py
@@ -18,6 +18,7 @@
from tempest import config
from tempest import exceptions
+from tempest.lib.common.utils import test_utils
from tempest.scenario import manager
from tempest import test
@@ -70,9 +71,9 @@
self.assertEqual(self.fip, result, msg)
return 'Verification is successful!'
- if not test.call_until_true(exec_cmd_and_verify_output,
- CONF.compute.build_timeout,
- CONF.compute.build_interval):
+ if not test_utils.call_until_true(exec_cmd_and_verify_output,
+ CONF.compute.build_timeout,
+ CONF.compute.build_interval):
raise exceptions.TimeoutException('Timed out while waiting to '
'verify metadata on server. '
'%s is empty.' % md_url)
diff --git a/tempest/scenario/test_stamp_pattern.py b/tempest/scenario/test_stamp_pattern.py
index e7223c7..5fd934c 100644
--- a/tempest/scenario/test_stamp_pattern.py
+++ b/tempest/scenario/test_stamp_pattern.py
@@ -22,6 +22,7 @@
from tempest.common import waiters
from tempest import config
from tempest import exceptions
+from tempest.lib.common.utils import test_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
from tempest.scenario import manager
@@ -89,9 +90,9 @@
LOG.debug("Partitions:%s" % part)
return CONF.compute.volume_device_name in part
- if not test.call_until_true(_func,
- CONF.compute.build_timeout,
- CONF.compute.build_interval):
+ if not test_utils.call_until_true(_func,
+ CONF.compute.build_timeout,
+ CONF.compute.build_interval):
raise exceptions.TimeoutException
@decorators.skip_because(bug="1205344")
diff --git a/tempest/services/identity/v2/__init__.py b/tempest/services/identity/v2/__init__.py
index ac2a874..b7d3c74 100644
--- a/tempest/services/identity/v2/__init__.py
+++ b/tempest/services/identity/v2/__init__.py
@@ -13,12 +13,12 @@
# the License.
from tempest.lib.services.identity.v2.endpoints_client import EndpointsClient
+from tempest.lib.services.identity.v2.identity_client import IdentityClient
from tempest.lib.services.identity.v2.roles_client import RolesClient
from tempest.lib.services.identity.v2.services_client import ServicesClient
from tempest.lib.services.identity.v2.tenants_client import TenantsClient
from tempest.lib.services.identity.v2.token_client import TokenClient
from tempest.lib.services.identity.v2.users_client import UsersClient
-from tempest.services.identity.v2.json.identity_client import IdentityClient
-__all__ = ['EndpointsClient', 'TokenClient', 'IdentityClient', 'RolesClient',
- 'ServicesClient', 'TenantsClient', 'UsersClient']
+__all__ = ['EndpointsClient', 'IdentityClient', 'RolesClient',
+ 'ServicesClient', 'TenantsClient', 'TokenClient', 'UsersClient']
diff --git a/tempest/services/identity/v3/__init__.py b/tempest/services/identity/v3/__init__.py
index a4e55d4..b4a1bb8 100644
--- a/tempest/services/identity/v3/__init__.py
+++ b/tempest/services/identity/v3/__init__.py
@@ -13,21 +13,22 @@
# the License.
from tempest.lib.services.identity.v3.endpoints_client import EndPointsClient
+from tempest.lib.services.identity.v3.groups_client import GroupsClient
from tempest.lib.services.identity.v3.policies_client import PoliciesClient
+from tempest.lib.services.identity.v3.projects_client import ProjectsClient
from tempest.lib.services.identity.v3.regions_client import RegionsClient
from tempest.lib.services.identity.v3.services_client import ServicesClient
from tempest.lib.services.identity.v3.token_client import V3TokenClient
+from tempest.lib.services.identity.v3.users_client import UsersClient
from tempest.services.identity.v3.json.credentials_client import \
CredentialsClient
from tempest.services.identity.v3.json.domains_client import DomainsClient
-from tempest.services.identity.v3.json.groups_client import GroupsClient
from tempest.services.identity.v3.json.identity_client import IdentityClient
-from tempest.services.identity.v3.json.projects_client import ProjectsClient
from tempest.services.identity.v3.json.roles_client import RolesClient
from tempest.services.identity.v3.json.trusts_client import TrustsClient
-from tempest.services.identity.v3.json.users_clients import UsersClient
-__all__ = ['EndPointsClient', 'PoliciesClient', 'RegionsClient',
- 'ServicesClient', 'V3TokenClient', 'CredentialsClient',
- 'DomainsClient', 'GroupsClient', 'IdentityClient', 'ProjectsClient',
- 'RolesClient', 'TrustsClient', 'UsersClient', ]
+
+__all__ = ['EndPointsClient', 'GroupsClient', 'PoliciesClient',
+ 'ProjectsClient', 'RegionsClient', 'ServicesClient',
+ 'V3TokenClient', 'UsersClient', 'CredentialsClient',
+ 'DomainsClient', 'IdentityClient', 'RolesClient', 'TrustsClient', ]
diff --git a/tempest/services/identity/v3/json/roles_client.py b/tempest/services/identity/v3/json/roles_client.py
index aab203f..3f165fa 100644
--- a/tempest/services/identity/v3/json/roles_client.py
+++ b/tempest/services/identity/v3/json/roles_client.py
@@ -13,6 +13,7 @@
# limitations under the License.
from oslo_serialization import jsonutils as json
+from six.moves.urllib import parse as urllib
from tempest.lib.common import rest_client
@@ -39,9 +40,13 @@
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
- def list_roles(self):
+ def list_roles(self, **params):
"""Get the list of Roles."""
- resp, body = self.get("roles")
+
+ url = 'roles'
+ if params:
+ url += '?%s' % urllib.urlencode(params)
+ resp, body = self.get(url)
self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
@@ -64,14 +69,14 @@
self.expected_success(204, resp.status)
return rest_client.ResponseBody(resp, body)
- def assign_user_role_on_project(self, project_id, user_id, role_id):
+ def create_user_role_on_project(self, project_id, user_id, role_id):
"""Add roles to a user on a project."""
resp, body = self.put('projects/%s/users/%s/roles/%s' %
(project_id, user_id, role_id), None)
self.expected_success(204, resp.status)
return rest_client.ResponseBody(resp, body)
- def assign_user_role_on_domain(self, domain_id, user_id, role_id):
+ def create_user_role_on_domain(self, domain_id, user_id, role_id):
"""Add roles to a user on a domain."""
resp, body = self.put('domains/%s/users/%s/roles/%s' %
(domain_id, user_id, role_id), None)
@@ -124,22 +129,22 @@
self.expected_success(204, resp.status)
return rest_client.ResponseBody(resp)
- def assign_group_role_on_project(self, project_id, group_id, role_id):
- """Add roles to a user on a project."""
+ def create_group_role_on_project(self, project_id, group_id, role_id):
+ """Add roles to a group on a project."""
resp, body = self.put('projects/%s/groups/%s/roles/%s' %
(project_id, group_id, role_id), None)
self.expected_success(204, resp.status)
return rest_client.ResponseBody(resp, body)
- def assign_group_role_on_domain(self, domain_id, group_id, role_id):
- """Add roles to a user on a domain."""
+ def create_group_role_on_domain(self, domain_id, group_id, role_id):
+ """Add roles to a group on a domain."""
resp, body = self.put('domains/%s/groups/%s/roles/%s' %
(domain_id, group_id, role_id), None)
self.expected_success(204, resp.status)
return rest_client.ResponseBody(resp, body)
def list_group_roles_on_project(self, project_id, group_id):
- """list roles of a user on a project."""
+ """list roles of a group on a project."""
resp, body = self.get('projects/%s/groups/%s/roles' %
(project_id, group_id))
self.expected_success(200, resp.status)
@@ -147,7 +152,7 @@
return rest_client.ResponseBody(resp, body)
def list_group_roles_on_domain(self, domain_id, group_id):
- """list roles of a user on a domain."""
+ """list roles of a group on a domain."""
resp, body = self.get('domains/%s/groups/%s/roles' %
(domain_id, group_id))
self.expected_success(200, resp.status)
@@ -155,14 +160,14 @@
return rest_client.ResponseBody(resp, body)
def delete_role_from_group_on_project(self, project_id, group_id, role_id):
- """Delete role of a user on a project."""
+ """Delete role of a group on a project."""
resp, body = self.delete('projects/%s/groups/%s/roles/%s' %
(project_id, group_id, role_id))
self.expected_success(204, resp.status)
return rest_client.ResponseBody(resp, body)
def delete_role_from_group_on_domain(self, domain_id, group_id, role_id):
- """Delete role of a user on a domain."""
+ """Delete role of a group on a domain."""
resp, body = self.delete('domains/%s/groups/%s/roles/%s' %
(domain_id, group_id, role_id))
self.expected_success(204, resp.status)
@@ -170,7 +175,7 @@
def check_role_from_group_on_project_existence(self, project_id,
group_id, role_id):
- """Check role of a user on a project."""
+ """Check role of a group on a project."""
resp, body = self.head('projects/%s/groups/%s/roles/%s' %
(project_id, group_id, role_id))
self.expected_success(204, resp.status)
@@ -178,7 +183,7 @@
def check_role_from_group_on_domain_existence(self, domain_id,
group_id, role_id):
- """Check role of a user on a domain."""
+ """Check role of a group on a domain."""
resp, body = self.head('domains/%s/groups/%s/roles/%s' %
(domain_id, group_id, role_id))
self.expected_success(204, resp.status)
diff --git a/tempest/services/volume/base/admin/base_types_client.py b/tempest/services/volume/base/admin/base_types_client.py
index 83870ae..fe70c1a 100755
--- a/tempest/services/volume/base/admin/base_types_client.py
+++ b/tempest/services/volume/base/admin/base_types_client.py
@@ -23,21 +23,9 @@
class BaseTypesClient(rest_client.RestClient):
"""Client class to send CRUD Volume Types API requests"""
- def is_resource_deleted(self, resource):
- # to use this method self.resource must be defined to respective value
- # Resource is a dictionary containing resource id and type
- # Resource : {"id" : resource_id
- # "type": resource_type}
+ def is_resource_deleted(self, id):
try:
- if resource['type'] == "volume-type":
- self.show_volume_type(resource['id'])
- elif resource['type'] == "encryption-type":
- body = self.show_encryption_type(resource['id'])
- if not body:
- return True
- else:
- msg = (" resource value is either not defined or incorrect.")
- raise lib_exc.UnprocessableEntity(msg)
+ self.show_volume_type(id)
except lib_exc.NotFound:
return True
return False
@@ -45,7 +33,7 @@
@property
def resource_type(self):
"""Returns the primary type of resource this client works with."""
- return 'volume-type/encryption-type'
+ return 'volume-type'
def list_volume_types(self, **params):
"""List all the volume_types created.
@@ -170,35 +158,3 @@
body = json.loads(body)
self.expected_success(200, resp.status)
return rest_client.ResponseBody(resp, body)
-
- def show_encryption_type(self, volume_type_id):
- """Get the volume encryption type for the specified volume type.
-
- volume_type_id: Id of volume_type.
- """
- url = "/types/%s/encryption" % volume_type_id
- resp, body = self.get(url)
- body = json.loads(body)
- self.expected_success(200, resp.status)
- return rest_client.ResponseBody(resp, body)
-
- def create_encryption_type(self, volume_type_id, **kwargs):
- """Create encryption type.
-
- TODO: Current api-site doesn't contain this API description.
- After fixing the api-site, we need to fix here also for putting
- the link to api-site.
- """
- url = "/types/%s/encryption" % volume_type_id
- post_body = json.dumps({'encryption': kwargs})
- resp, body = self.post(url, post_body)
- body = json.loads(body)
- self.expected_success(200, resp.status)
- return rest_client.ResponseBody(resp, body)
-
- def delete_encryption_type(self, volume_type_id):
- """Delete the encryption type for the specified volume-type."""
- resp, body = self.delete(
- "/types/%s/encryption/provider" % volume_type_id)
- self.expected_success(202, resp.status)
- return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/volume/base/base_qos_client.py b/tempest/services/volume/base/base_qos_client.py
index e00ac68..0ce76a7 100644
--- a/tempest/services/volume/base/base_qos_client.py
+++ b/tempest/services/volume/base/base_qos_client.py
@@ -12,11 +12,8 @@
# License for the specific language governing permissions and limitations
# under the License.
-import time
-
from oslo_serialization import jsonutils as json
-from tempest import exceptions
from tempest.lib.common import rest_client
from tempest.lib import exceptions as lib_exc
@@ -36,37 +33,6 @@
"""Returns the primary type of resource this client works with."""
return 'qos'
- def wait_for_qos_operations(self, qos_id, operation, args=None):
- """Waits for a qos operations to be completed.
-
- NOTE : operation value is required for wait_for_qos_operations()
- operation = 'qos-key' / 'disassociate' / 'disassociate-all'
- args = keys[] when operation = 'qos-key'
- args = volume-type-id disassociated when operation = 'disassociate'
- args = None when operation = 'disassociate-all'
- """
- start_time = int(time.time())
- while True:
- if operation == 'qos-key-unset':
- body = self.show_qos(qos_id)['qos_specs']
- if not any(key in body['specs'] for key in args):
- return
- elif operation == 'disassociate':
- body = self.show_association_qos(qos_id)['qos_associations']
- if not any(args in body[i]['id'] for i in range(0, len(body))):
- return
- elif operation == 'disassociate-all':
- body = self.show_association_qos(qos_id)['qos_associations']
- if not body:
- return
- else:
- msg = (" operation value is either not defined or incorrect.")
- raise lib_exc.UnprocessableEntity(msg)
-
- if int(time.time()) - start_time >= self.build_timeout:
- raise exceptions.TimeoutException
- time.sleep(self.build_interval)
-
def create_qos(self, **kwargs):
"""Create a QoS Specification.
diff --git a/tempest/services/volume/base/base_volumes_client.py b/tempest/services/volume/base/base_volumes_client.py
index 8130089..308f818 100755
--- a/tempest/services/volume/base/base_volumes_client.py
+++ b/tempest/services/volume/base/base_volumes_client.py
@@ -26,16 +26,6 @@
create_resp = 200
- def __init__(self, auth_provider, service, region,
- default_volume_size=1, **kwargs):
- super(BaseVolumesClient, self).__init__(
- auth_provider, service, region, **kwargs)
- self.default_volume_size = default_volume_size
-
- def get_attachment_from_volume(self, volume):
- """Return the element 'attachment' from input volumes."""
- return volume['attachments'][0]
-
def _prepare_params(self, params):
"""Prepares params for use in get or _ext_get methods.
@@ -104,8 +94,6 @@
Available params: see http://developer.openstack.org/
api-ref-blockstorage-v2.html#createVolume
"""
- if 'size' not in kwargs:
- kwargs['size'] = self.default_volume_size
post_body = json.dumps({'volume': kwargs})
resp, body = self.post('volumes', post_body)
body = json.loads(body)
diff --git a/tempest/services/volume/v1/__init__.py b/tempest/services/volume/v1/__init__.py
index 945d2f2..72868bc 100644
--- a/tempest/services/volume/v1/__init__.py
+++ b/tempest/services/volume/v1/__init__.py
@@ -20,10 +20,13 @@
from tempest.lib.services.volume.v1.services_client import ServicesClient
from tempest.services.volume.v1.json.admin.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']
+ 'QosSpecsClient', 'SnapshotsClient', 'VolumesClient',
+ 'EncryptionTypesClient']
diff --git a/tempest/services/volume/v1/json/encryption_types_client.py b/tempest/services/volume/v1/json/encryption_types_client.py
new file mode 100755
index 0000000..067b4e8
--- /dev/null
+++ b/tempest/services/volume/v1/json/encryption_types_client.py
@@ -0,0 +1,68 @@
+# Copyright 2012 OpenStack Foundation
+# 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
+from tempest.lib import exceptions as lib_exc
+
+
+class EncryptionTypesClient(rest_client.RestClient):
+
+ def is_resource_deleted(self, id):
+ try:
+ body = self.show_encryption_type(id)
+ if not body:
+ return True
+ except lib_exc.NotFound:
+ return True
+ return False
+
+ @property
+ def resource_type(self):
+ """Returns the primary type of resource this client works with."""
+ return 'encryption-type'
+
+ def show_encryption_type(self, volume_type_id):
+ """Get the volume encryption type for the specified volume type.
+
+ volume_type_id: Id of volume_type.
+ """
+ url = "/types/%s/encryption" % volume_type_id
+ resp, body = self.get(url)
+ body = json.loads(body)
+ self.expected_success(200, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
+ def create_encryption_type(self, volume_type_id, **kwargs):
+ """Create encryption type.
+
+ TODO: Current api-site doesn't contain this API description.
+ After fixing the api-site, we need to fix here also for putting
+ the link to api-site.
+ """
+ url = "/types/%s/encryption" % volume_type_id
+ post_body = json.dumps({'encryption': kwargs})
+ resp, body = self.post(url, post_body)
+ body = json.loads(body)
+ self.expected_success(200, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
+ def delete_encryption_type(self, volume_type_id):
+ """Delete the encryption type for the specified volume-type."""
+ resp, body = self.delete(
+ "/types/%s/encryption/provider" % volume_type_id)
+ self.expected_success(202, resp.status)
+ return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/volume/v2/__init__.py b/tempest/services/volume/v2/__init__.py
index 80f7a94..4afcc29 100644
--- a/tempest/services/volume/v2/__init__.py
+++ b/tempest/services/volume/v2/__init__.py
@@ -20,10 +20,13 @@
from tempest.lib.services.volume.v2.services_client import ServicesClient
from tempest.services.volume.v2.json.admin.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
from tempest.services.volume.v2.json.qos_client import QosSpecsClient
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']
+ 'QosSpecsClient', 'SnapshotsClient', 'VolumesClient',
+ 'EncryptionTypesClient']
diff --git a/tempest/services/volume/v2/json/encryption_types_client.py b/tempest/services/volume/v2/json/encryption_types_client.py
new file mode 100755
index 0000000..8b01f11
--- /dev/null
+++ b/tempest/services/volume/v2/json/encryption_types_client.py
@@ -0,0 +1,69 @@
+# Copyright 2012 OpenStack Foundation
+# 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
+from tempest.lib import exceptions as lib_exc
+
+
+class EncryptionTypesClient(rest_client.RestClient):
+ api_version = "v2"
+
+ def is_resource_deleted(self, id):
+ try:
+ body = self.show_encryption_type(id)
+ if not body:
+ return True
+ except lib_exc.NotFound:
+ return True
+ return False
+
+ @property
+ def resource_type(self):
+ """Returns the primary type of resource this client works with."""
+ return 'encryption-type'
+
+ def show_encryption_type(self, volume_type_id):
+ """Get the volume encryption type for the specified volume type.
+
+ volume_type_id: Id of volume_type.
+ """
+ url = "/types/%s/encryption" % volume_type_id
+ resp, body = self.get(url)
+ body = json.loads(body)
+ self.expected_success(200, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
+ def create_encryption_type(self, volume_type_id, **kwargs):
+ """Create encryption type.
+
+ TODO: Current api-site doesn't contain this API description.
+ After fixing the api-site, we need to fix here also for putting
+ the link to api-site.
+ """
+ url = "/types/%s/encryption" % volume_type_id
+ post_body = json.dumps({'encryption': kwargs})
+ resp, body = self.post(url, post_body)
+ body = json.loads(body)
+ self.expected_success(200, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
+ def delete_encryption_type(self, volume_type_id):
+ """Delete the encryption type for the specified volume-type."""
+ resp, body = self.delete(
+ "/types/%s/encryption/provider" % volume_type_id)
+ self.expected_success(202, resp.status)
+ return rest_client.ResponseBody(resp, body)
diff --git a/tempest/stress/actions/ssh_floating.py b/tempest/stress/actions/ssh_floating.py
index 4f8c6bd..c9a4d38 100644
--- a/tempest/stress/actions/ssh_floating.py
+++ b/tempest/stress/actions/ssh_floating.py
@@ -16,8 +16,8 @@
from tempest.common.utils import data_utils
from tempest.common import waiters
from tempest import config
+from tempest.lib.common.utils import test_utils
import tempest.stress.stressaction as stressaction
-import tempest.test
CONF = config.CONF
@@ -52,8 +52,8 @@
def check_port_ssh(self):
def func():
return self.tcp_connect_scan(self.floating['ip'], 22)
- if not tempest.test.call_until_true(func, self.check_timeout,
- self.check_interval):
+ if not test_utils.call_until_true(func, self.check_timeout,
+ self.check_interval):
raise RuntimeError("Cannot connect to the ssh port.")
def check_icmp_echo(self):
@@ -62,8 +62,8 @@
def func():
return self.ping_ip_address(self.floating['ip'])
- if not tempest.test.call_until_true(func, self.check_timeout,
- self.check_interval):
+ if not test_utils.call_until_true(func, self.check_timeout,
+ self.check_interval):
raise RuntimeError("%s(%s): Cannot ping the machine.",
self.server_id, self.floating['ip'])
self.logger.info("%s(%s): pong :)",
@@ -153,8 +153,8 @@
['floating_ip'])
return floating['instance_id'] is None
- if not tempest.test.call_until_true(func, self.check_timeout,
- self.check_interval):
+ if not test_utils.call_until_true(func, self.check_timeout,
+ self.check_interval):
raise RuntimeError("IP disassociate timeout!")
def run_core(self):
diff --git a/tempest/stress/actions/volume_attach_delete.py b/tempest/stress/actions/volume_attach_delete.py
index 847f342..e06c364 100644
--- a/tempest/stress/actions/volume_attach_delete.py
+++ b/tempest/stress/actions/volume_attach_delete.py
@@ -30,7 +30,7 @@
name = data_utils.rand_name("volume")
self.logger.info("creating volume: %s" % name)
volume = self.manager.volumes_client.create_volume(
- display_name=name)['volume']
+ display_name=name, size=CONF.volume.volume_size)['volume']
self.manager.volumes_client.wait_for_volume_status(volume['id'],
'available')
self.logger.info("created volume: %s" % volume['id'])
diff --git a/tempest/stress/actions/volume_attach_verify.py b/tempest/stress/actions/volume_attach_verify.py
index 8bbbfc4..743cb11 100644
--- a/tempest/stress/actions/volume_attach_verify.py
+++ b/tempest/stress/actions/volume_attach_verify.py
@@ -16,8 +16,8 @@
from tempest.common.utils.linux import remote_client
from tempest.common import waiters
from tempest import config
+from tempest.lib.common.utils import test_utils
import tempest.stress.stressaction as stressaction
-import tempest.test
CONF = config.CONF
@@ -85,7 +85,7 @@
self.logger.info("creating volume: %s" % name)
volumes_client = self.manager.volumes_client
self.volume = volumes_client.create_volume(
- display_name=name)['volume']
+ display_name=name, size=CONF.volume.volume_size)['volume']
volumes_client.wait_for_volume_status(self.volume['id'],
'available')
self.logger.info("created volume: %s" % self.volume['id'])
@@ -105,8 +105,8 @@
['floating_ip'])
return floating['instance_id'] is None
- if not tempest.test.call_until_true(func, CONF.compute.build_timeout,
- CONF.compute.build_interval):
+ if not test_utils.call_until_true(func, CONF.compute.build_timeout,
+ CONF.compute.build_interval):
raise RuntimeError("IP disassociate timeout!")
def new_server_ops(self):
@@ -179,9 +179,9 @@
if self.part_line_re.match(part_line):
matching += 1
return matching == num_match
- if tempest.test.call_until_true(_part_state,
- CONF.compute.build_timeout,
- CONF.compute.build_interval):
+ if test_utils.call_until_true(_part_state,
+ CONF.compute.build_timeout,
+ CONF.compute.build_interval):
return
else:
raise RuntimeError("Unexpected partitions: %s",
diff --git a/tempest/stress/actions/volume_create_delete.py b/tempest/stress/actions/volume_create_delete.py
index 3986748..66971ea 100644
--- a/tempest/stress/actions/volume_create_delete.py
+++ b/tempest/stress/actions/volume_create_delete.py
@@ -11,8 +11,11 @@
# limitations under the License.
from tempest.common.utils import data_utils
+from tempest import config
import tempest.stress.stressaction as stressaction
+CONF = config.CONF
+
class VolumeCreateDeleteTest(stressaction.StressAction):
@@ -20,7 +23,8 @@
name = data_utils.rand_name("volume")
self.logger.info("creating %s" % name)
volumes_client = self.manager.volumes_client
- volume = volumes_client.create_volume(display_name=name)['volume']
+ volume = volumes_client.create_volume(
+ display_name=name, size=CONF.volume.volume_size)['volume']
vol_id = volume['id']
volumes_client.wait_for_volume_status(vol_id, 'available')
self.logger.info("created %s" % volume['id'])
diff --git a/tempest/test.py b/tempest/test.py
index 97ab25c..609f1f6 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -18,8 +18,8 @@
import os
import re
import sys
-import time
+import debtcollector.moves
import fixtures
from oslo_log import log as logging
from oslo_serialization import jsonutils as json
@@ -38,6 +38,7 @@
from tempest import config
from tempest import exceptions
from tempest.lib.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
@@ -866,22 +867,6 @@
return klass
-def call_until_true(func, duration, sleep_for):
- """Call the given function until it returns True (and return True)
-
- or until the specified duration (in seconds) elapses (and return False).
-
- :param func: A zero argument callable that returns True on success.
- :param duration: The number of seconds for which to attempt a
- successful call of the function.
- :param sleep_for: The number of seconds to sleep after an unsuccessful
- invocation of the function.
- """
- now = time.time()
- timeout = now + duration
- while now < timeout:
- if func():
- return True
- time.sleep(sleep_for)
- now = time.time()
- return False
+call_until_true = debtcollector.moves.moved_function(
+ test_utils.call_until_true, 'call_until_true', __name__,
+ version='Newton', removal_version='Ocata')
diff --git a/tempest/tests/common/test_dynamic_creds.py b/tempest/tests/common/test_dynamic_creds.py
index b7cc05d..f9f4100 100644
--- a/tempest/tests/common/test_dynamic_creds.py
+++ b/tempest/tests/common/test_dynamic_creds.py
@@ -22,20 +22,21 @@
from tempest import exceptions
from tempest.lib.common import rest_client
from tempest.lib import exceptions as lib_exc
+from tempest.lib.services.identity.v2 import identity_client as v2_iden_client
from tempest.lib.services.identity.v2 import roles_client as v2_roles_client
from tempest.lib.services.identity.v2 import tenants_client as \
v2_tenants_client
from tempest.lib.services.identity.v2 import token_client as v2_token_client
from tempest.lib.services.identity.v2 import users_client as v2_users_client
+from tempest.lib.services.identity.v3 import projects_client as \
+ v3_projects_client
from tempest.lib.services.identity.v3 import token_client as v3_token_client
+from tempest.lib.services.identity.v3 import users_client as \
+ v3_users_client
from tempest.lib.services.network import routers_client
-from tempest.services.identity.v2.json import identity_client as v2_iden_client
from tempest.services.identity.v3.json import domains_client
from tempest.services.identity.v3.json import identity_client as v3_iden_client
-from tempest.services.identity.v3.json import projects_client as \
- v3_projects_client
from tempest.services.identity.v3.json import roles_client as v3_roles_client
-from tempest.services.identity.v3.json import users_clients as v3_users_client
from tempest.tests import base
from tempest.tests import fake_config
from tempest.tests.lib import fake_http
@@ -55,7 +56,6 @@
users_client = v2_users_client
token_client_class = token_client.TokenClient
fake_response = fake_identity._fake_v2_response
- assign_role_on_project = 'create_user_role_on_project'
tenants_client_class = tenants_client.TenantsClient
delete_tenant = 'delete_tenant'
@@ -125,7 +125,7 @@
def _mock_assign_user_role(self):
tenant_fix = self.useFixture(mockpatch.PatchObject(
self.roles_client.RolesClient,
- self.assign_role_on_project,
+ 'create_user_role_on_project',
return_value=(rest_client.ResponseBody
(200, {}))))
return tenant_fix
@@ -198,11 +198,11 @@
self._mock_tenant_create('1234', 'fake_admin_tenant')
user_mock = mock.patch.object(self.roles_client.RolesClient,
- self.assign_role_on_project)
+ 'create_user_role_on_project')
user_mock.start()
self.addCleanup(user_mock.stop)
with mock.patch.object(self.roles_client.RolesClient,
- self.assign_role_on_project) as user_mock:
+ 'create_user_role_on_project') as user_mock:
admin_creds = creds.get_admin_creds()
user_mock.assert_has_calls([
mock.call('1234', '1234', '1234')])
@@ -221,11 +221,11 @@
self._mock_tenant_create('1234', 'fake_role_tenant')
user_mock = mock.patch.object(self.roles_client.RolesClient,
- self.assign_role_on_project)
+ 'create_user_role_on_project')
user_mock.start()
self.addCleanup(user_mock.stop)
with mock.patch.object(self.roles_client.RolesClient,
- self.assign_role_on_project) as user_mock:
+ 'create_user_role_on_project') as user_mock:
role_creds = creds.get_creds_by_roles(
roles=['role1', 'role2'])
calls = user_mock.mock_calls
@@ -612,7 +612,6 @@
users_client = v3_users_client
token_client_class = token_client.V3TokenClient
fake_response = fake_identity._fake_v3_response
- assign_role_on_project = 'assign_user_role_on_project'
tenants_client_class = tenants_client.ProjectsClient
delete_tenant = 'delete_project'
@@ -624,7 +623,7 @@
return_value=dict(domains=[dict(id='default',
name='Default')])))
self.patchobject(self.roles_client.RolesClient,
- 'assign_user_role_on_domain')
+ 'create_user_role_on_domain')
def _mock_list_ec2_credentials(self, user_id, tenant_id):
pass
diff --git a/tempest/tests/lib/common/utils/test_test_utils.py b/tempest/tests/lib/common/utils/test_test_utils.py
index 919e219..29c5684 100644
--- a/tempest/tests/lib/common/utils/test_test_utils.py
+++ b/tempest/tests/lib/common/utils/test_test_utils.py
@@ -17,6 +17,7 @@
from tempest.lib.common.utils import test_utils
from tempest.lib import exceptions
from tempest.tests import base
+from tempest.tests import utils
class TestTestUtils(base.TestCase):
@@ -76,3 +77,27 @@
self.assertEqual(
42, test_utils.call_and_ignore_notfound_exc(m, *args, **kwargs))
m.assert_called_once_with(*args, **kwargs)
+
+ @mock.patch('time.sleep')
+ @mock.patch('time.time')
+ def test_call_until_true_when_f_never_returns_true(self, m_time, m_sleep):
+ timeout = 42 # The value doesn't matter as we mock time.time()
+ sleep = 60 # The value doesn't matter as we mock time.sleep()
+ m_time.side_effect = utils.generate_timeout_series(timeout)
+ self.assertEqual(
+ False, test_utils.call_until_true(lambda: False, timeout, sleep)
+ )
+ m_sleep.call_args_list = [mock.call(sleep)] * 2
+ m_time.call_args_list = [mock.call()] * 2
+
+ @mock.patch('time.sleep')
+ @mock.patch('time.time')
+ def test_call_until_true_when_f_returns_true(self, m_time, m_sleep):
+ timeout = 42 # The value doesn't matter as we mock time.time()
+ sleep = 60 # The value doesn't matter as we mock time.sleep()
+ m_time.return_value = 0
+ self.assertEqual(
+ True, test_utils.call_until_true(lambda: True, timeout, sleep)
+ )
+ self.assertEqual(0, m_sleep.call_count)
+ self.assertEqual(1, m_time.call_count)
diff --git a/tempest/tests/lib/services/identity/v2/test_identity_client.py b/tempest/tests/lib/services/identity/v2/test_identity_client.py
new file mode 100644
index 0000000..96d50d7
--- /dev/null
+++ b/tempest/tests/lib/services/identity/v2/test_identity_client.py
@@ -0,0 +1,175 @@
+# Copyright 2016 NEC Corporation. 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 tempest.lib.services.identity.v2 import identity_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestIdentityClient(base.BaseServiceTest):
+ FAKE_TOKEN = {
+ "tokens": {
+ "id": "cbc36478b0bd8e67e89",
+ "name": "FakeToken",
+ "type": "token",
+ }
+ }
+
+ FAKE_API_INFO = {
+ "name": "API_info",
+ "type": "API",
+ "description": "test_description"
+ }
+
+ FAKE_LIST_EXTENSIONS = {
+ "extensions": {
+ "values": [
+ {
+ "updated": "2013-07-07T12:00:0-00:00",
+ "name": "OpenStack S3 API",
+ "links": [
+ {
+ "href": "https://github.com/openstack/" +
+ "identity-api",
+ "type": "text/html",
+ "rel": "describedby"
+ }
+ ],
+ "namespace": "http://docs.openstack.org/identity/" +
+ "api/ext/s3tokens/v1.0",
+ "alias": "s3tokens",
+ "description": "OpenStack S3 API."
+ },
+ {
+ "updated": "2013-12-17T12:00:0-00:00",
+ "name": "OpenStack Federation APIs",
+ "links": [
+ {
+ "href": "https://github.com/openstack/" +
+ "identity-api",
+ "type": "text/html",
+ "rel": "describedby"
+ }
+ ],
+ "namespace": "http://docs.openstack.org/identity/" +
+ "api/ext/OS-FEDERATION/v1.0",
+ "alias": "OS-FEDERATION",
+ "description": "OpenStack Identity Providers Mechanism."
+ },
+ {
+ "updated": "2014-01-20T12:00:0-00:00",
+ "name": "OpenStack Simple Certificate API",
+ "links": [
+ {
+ "href": "https://github.com/openstack/" +
+ "identity-api",
+ "type": "text/html",
+ "rel": "describedby"
+ }
+ ],
+ "namespace": "http://docs.openstack.org/identity/api/" +
+ "ext/OS-SIMPLE-CERT/v1.0",
+ "alias": "OS-SIMPLE-CERT",
+ "description": "OpenStack simple certificate extension"
+ },
+ {
+ "updated": "2013-07-07T12:00:0-00:00",
+ "name": "OpenStack OAUTH1 API",
+ "links": [
+ {
+ "href": "https://github.com/openstack/" +
+ "identity-api",
+ "type": "text/html",
+ "rel": "describedby"
+ }
+ ],
+ "namespace": "http://docs.openstack.org/identity/" +
+ "api/ext/OS-OAUTH1/v1.0",
+ "alias": "OS-OAUTH1",
+ "description": "OpenStack OAuth Delegated Auth Mechanism."
+ },
+ {
+ "updated": "2013-07-07T12:00:0-00:00",
+ "name": "OpenStack EC2 API",
+ "links": [
+ {
+ "href": "https://github.com/openstack/" +
+ "identity-api",
+ "type": "text/html",
+ "rel": "describedby"
+ }
+ ],
+ "namespace": "http://docs.openstack.org/identity/api/" +
+ "ext/OS-EC2/v1.0",
+ "alias": "OS-EC2",
+ "description": "OpenStack EC2 Credentials backend."
+ }
+ ]
+ }
+ }
+
+ def setUp(self):
+ super(TestIdentityClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = identity_client.IdentityClient(fake_auth,
+ 'identity',
+ 'regionOne')
+
+ def _test_show_api_description(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_api_description,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_API_INFO,
+ bytes_body)
+
+ def _test_list_extensions(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_extensions,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_LIST_EXTENSIONS,
+ bytes_body)
+
+ def _test_show_token(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_token,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_TOKEN,
+ bytes_body,
+ token_id="cbc36478b0bd8e67e89")
+
+ def test_show_api_description_with_str_body(self):
+ self._test_show_api_description()
+
+ def test_show_api_description_with_bytes_body(self):
+ self._test_show_api_description(bytes_body=True)
+
+ def test_show_list_extensions_with_str_body(self):
+ self._test_list_extensions()
+
+ def test_show_list_extensions_with_bytes_body(self):
+ self._test_list_extensions(bytes_body=True)
+
+ def test_show_token_with_str_body(self):
+ self._test_show_token()
+
+ def test_show_token_with_bytes_body(self):
+ self._test_show_token(bytes_body=True)
+
+ def test_delete_token(self):
+ self.check_service_client_function(
+ self.client.delete_token,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ token_id="cbc36478b0bd8e67e89",
+ status=204)
diff --git a/tempest/tests/lib/services/identity/v3/test_groups_client.py b/tempest/tests/lib/services/identity/v3/test_groups_client.py
new file mode 100644
index 0000000..38cf3ae
--- /dev/null
+++ b/tempest/tests/lib/services/identity/v3/test_groups_client.py
@@ -0,0 +1,213 @@
+# Copyright 2016 Red Hat, Inc.
+#
+# 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.identity.v3 import groups_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestGroupsClient(base.BaseServiceTest):
+ FAKE_CREATE_GROUP = {
+ 'group': {
+ 'description': 'Tempest Group Description',
+ 'domain_id': 'TempestDomain',
+ 'name': 'Tempest Group',
+ }
+ }
+
+ FAKE_GROUP_INFO = {
+ 'group': {
+ 'description': 'Tempest Group Description',
+ 'domain_id': 'TempestDomain',
+ 'id': '6e13e2068cf9466e98950595baf6bb35',
+ 'links': {
+ 'self': 'http://example.com/identity/v3/groups/' +
+ '6e13e2068cf9466e98950595baf6bb35'
+ },
+ 'name': 'Tempest Group',
+ }
+ }
+
+ FAKE_GROUP_LIST = {
+ 'links': {
+ 'self': 'http://example.com/identity/v3/groups',
+ 'previous': None,
+ 'next': None,
+ },
+ 'groups': [
+ {
+ 'description': 'Tempest Group One Description',
+ 'domain_id': 'TempestDomain',
+ 'id': '1c92f3453ed34291a074b87493455b8f',
+ 'links': {
+ 'self': 'http://example.com/identity/v3/groups/' +
+ '1c92f3453ed34291a074b87493455b8f'
+ },
+ 'name': 'Tempest Group One',
+ },
+ {
+ 'description': 'Tempest Group Two Description',
+ 'domain_id': 'TempestDomain',
+ 'id': 'ce9e7dafed3b4877a7d4466ed730a9ee',
+ 'links': {
+ 'self': 'http://example.com/identity/v3/groups/' +
+ 'ce9e7dafed3b4877a7d4466ed730a9ee'
+ },
+ 'name': 'Tempest Group Two',
+ },
+ ]
+ }
+
+ FAKE_USER_LIST = {
+ 'links': {
+ 'self': 'http://example.com/identity/v3/groups/' +
+ '6e13e2068cf9466e98950595baf6bb35/users',
+ 'previous': None,
+ 'next': None,
+ },
+ 'users': [
+ {
+ 'domain_id': 'TempestDomain',
+ 'description': 'Tempest Test User One Description',
+ 'enabled': True,
+ 'id': '642688fa65a84217b86cef3c063de2b9',
+ 'name': 'TempestUserOne',
+ 'links': {
+ 'self': 'http://example.com/identity/v3/users/' +
+ '642688fa65a84217b86cef3c063de2b9'
+ }
+ },
+ {
+ 'domain_id': 'TempestDomain',
+ 'description': 'Tempest Test User Two Description',
+ 'enabled': True,
+ 'id': '1048ead6f8ef4a859b44ffbce3ac0b52',
+ 'name': 'TempestUserTwo',
+ 'links': {
+ 'self': 'http://example.com/identity/v3/users/' +
+ '1048ead6f8ef4a859b44ffbce3ac0b52'
+ }
+ },
+ ]
+ }
+
+ def setUp(self):
+ super(TestGroupsClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = groups_client.GroupsClient(fake_auth, 'identity',
+ 'regionOne')
+
+ def _test_create_group(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.create_group,
+ 'tempest.lib.common.rest_client.RestClient.post',
+ self.FAKE_CREATE_GROUP,
+ bytes_body,
+ status=201,
+ )
+
+ def _test_show_group(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_group,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_GROUP_INFO,
+ bytes_body,
+ group_id='6e13e2068cf9466e98950595baf6bb35',
+ )
+
+ def _test_list_groups(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_groups,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_GROUP_LIST,
+ bytes_body,
+ )
+
+ def _test_update_group(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.update_group,
+ 'tempest.lib.common.rest_client.RestClient.patch',
+ self.FAKE_GROUP_INFO,
+ bytes_body,
+ group_id='6e13e2068cf9466e98950595baf6bb35',
+ name='NewName',
+ )
+
+ def _test_list_users_in_group(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_group_users,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_USER_LIST,
+ bytes_body,
+ group_id='6e13e2068cf9466e98950595baf6bb35',
+ )
+
+ def test_create_group_with_string_body(self):
+ self._test_create_group()
+
+ def test_create_group_with_bytes_body(self):
+ self._test_create_group(bytes_body=True)
+
+ def test_show_group_with_string_body(self):
+ self._test_show_group()
+
+ def test_show_group_with_bytes_body(self):
+ self._test_show_group(bytes_body=True)
+
+ def test_list_groups_with_string_body(self):
+ self._test_list_groups()
+
+ def test_list_groups_with_bytes_body(self):
+ self._test_list_groups(bytes_body=True)
+
+ def test_update_group_with_string_body(self):
+ self._test_update_group()
+
+ def test_update_group_with_bytes_body(self):
+ self._test_update_group(bytes_body=True)
+
+ def test_list_users_in_group_with_string_body(self):
+ self._test_list_users_in_group()
+
+ def test_list_users_in_group_with_bytes_body(self):
+ self._test_list_users_in_group(bytes_body=True)
+
+ def test_delete_group(self):
+ self.check_service_client_function(
+ self.client.delete_group,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ group_id='6e13e2068cf9466e98950595baf6bb35',
+ status=204,
+ )
+
+ def test_add_user_to_group(self):
+ self.check_service_client_function(
+ self.client.add_group_user,
+ 'tempest.lib.common.rest_client.RestClient.put',
+ {},
+ status=204,
+ group_id='6e13e2068cf9466e98950595baf6bb35',
+ user_id='642688fa65a84217b86cef3c063de2b9',
+ )
+
+ def test_check_user_in_group(self):
+ self.check_service_client_function(
+ self.client.check_group_user_existence,
+ 'tempest.lib.common.rest_client.RestClient.head',
+ {},
+ status=204,
+ group_id='6e13e2068cf9466e98950595baf6bb35',
+ user_id='642688fa65a84217b86cef3c063de2b9',
+ )
diff --git a/tempest/tests/lib/services/identity/v3/test_projects_client.py b/tempest/tests/lib/services/identity/v3/test_projects_client.py
new file mode 100644
index 0000000..6ffbcde
--- /dev/null
+++ b/tempest/tests/lib/services/identity/v3/test_projects_client.py
@@ -0,0 +1,178 @@
+# Copyright 2016 Red Hat, Inc.
+#
+# 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.identity.v3 import projects_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestProjectsClient(base.BaseServiceTest):
+ FAKE_CREATE_PROJECT = {
+ "project": {
+ "description": "My new project",
+ "domain_id": "default",
+ "enabled": True,
+ "is_domain": False,
+ "name": "myNewProject"
+ }
+ }
+
+ FAKE_PROJECT_INFO = {
+ "project": {
+ "is_domain": False,
+ "description": None,
+ "domain_id": "default",
+ "enabled": True,
+ "id": "0c4e939acacf4376bdcd1129f1a054ad",
+ "links": {
+ "self": "http://example.com/identity/v3/projects/0c4e" +
+ "939acacf4376bdcd1129f1a054ad"
+ },
+ "name": "admin",
+ "parent_id": "default"
+ }
+ }
+
+ FAKE_LIST_PROJECTS = {
+ "links": {
+ "next": None,
+ "previous": None,
+ "self": "http://example.com/identity/v3/projects"
+ },
+ "projects": [
+ {
+ "is_domain": False,
+ "description": None,
+ "domain_id": "default",
+ "enabled": True,
+ "id": "0c4e939acacf4376bdcd1129f1a054ad",
+ "links": {
+ "self": "http://example.com/identity/v3/projects" +
+ "/0c4e939acacf4376bdcd1129f1a054ad"
+ },
+ "name": "admin",
+ "parent_id": None
+ },
+ {
+ "is_domain": False,
+ "description": None,
+ "domain_id": "default",
+ "enabled": True,
+ "id": "0cbd49cbf76d405d9c86562e1d579bd3",
+ "links": {
+ "self": "http://example.com/identity/v3/projects" +
+ "/0cbd49cbf76d405d9c86562e1d579bd3"
+ },
+ "name": "demo",
+ "parent_id": None
+ },
+ {
+ "is_domain": False,
+ "description": None,
+ "domain_id": "default",
+ "enabled": True,
+ "id": "2db68fed84324f29bb73130c6c2094fb",
+ "links": {
+ "self": "http://example.com/identity/v3/projects" +
+ "/2db68fed84324f29bb73130c6c2094fb"
+ },
+ "name": "swifttenanttest2",
+ "parent_id": None
+ },
+ {
+ "is_domain": False,
+ "description": None,
+ "domain_id": "default",
+ "enabled": True,
+ "id": "3d594eb0f04741069dbbb521635b21c7",
+ "links": {
+ "self": "http://example.com/identity/v3/projects" +
+ "/3d594eb0f04741069dbbb521635b21c7"
+ },
+ "name": "service",
+ "parent_id": None
+ }
+ ]
+ }
+
+ def setUp(self):
+ super(TestProjectsClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = projects_client.ProjectsClient(fake_auth,
+ 'identity',
+ 'regionOne')
+
+ def _test_create_project(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.create_project,
+ 'tempest.lib.common.rest_client.RestClient.post',
+ self.FAKE_CREATE_PROJECT,
+ bytes_body,
+ name=self.FAKE_CREATE_PROJECT["project"]["name"],
+ status=201)
+
+ def _test_show_project(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_project,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_PROJECT_INFO,
+ bytes_body,
+ project_id="0c4e939acacf4376bdcd1129f1a054ad")
+
+ def _test_list_projects(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_projects,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_LIST_PROJECTS,
+ bytes_body)
+
+ def _test_update_project(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.update_project,
+ 'tempest.lib.common.rest_client.RestClient.patch',
+ self.FAKE_PROJECT_INFO,
+ bytes_body,
+ project_id="0c4e939acacf4376bdcd1129f1a054ad")
+
+ def test_create_project_with_str_body(self):
+ self._test_create_project()
+
+ def test_create_project_with_bytes_body(self):
+ self._test_create_project(bytes_body=True)
+
+ def test_show_project_with_str_body(self):
+ self._test_show_project()
+
+ def test_show_project_with_bytes_body(self):
+ self._test_show_project(bytes_body=True)
+
+ def test_list_projects_with_str_body(self):
+ self._test_list_projects()
+
+ def test_list_projects_with_bytes_body(self):
+ self._test_list_projects(bytes_body=True)
+
+ def test_update_project_with_str_body(self):
+ self._test_update_project()
+
+ def test_update_project_with_bytes_body(self):
+ self._test_update_project(bytes_body=True)
+
+ def test_delete_project(self):
+ self.check_service_client_function(
+ self.client.delete_project,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ project_id="0c4e939acacf4376bdcd1129f1a054ad",
+ status=204)
diff --git a/tempest/tests/lib/services/identity/v3/test_users_client.py b/tempest/tests/lib/services/identity/v3/test_users_client.py
new file mode 100644
index 0000000..5b572f5
--- /dev/null
+++ b/tempest/tests/lib/services/identity/v3/test_users_client.py
@@ -0,0 +1,205 @@
+# Copyright 2016 Red Hat, Inc.
+#
+# 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.identity.v3 import users_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestUsersClient(base.BaseServiceTest):
+ FAKE_CREATE_USER = {
+ 'user': {
+ 'default_project_id': '95f8c3f8e7b54409a418fc30717f9ae0',
+ 'domain_id': '8347b31afc3545c4b311cb4cce788a08',
+ 'enabled': True,
+ 'name': 'Tempest User',
+ 'password': 'TempestPassword',
+ }
+ }
+
+ FAKE_USER_INFO = {
+ 'user': {
+ 'default_project_id': '95f8c3f8e7b54409a418fc30717f9ae0',
+ 'domain_id': '8347b31afc3545c4b311cb4cce788a08',
+ 'enabled': True,
+ 'id': '817fb3c23fd7465ba6d7fe1b1320121d',
+ 'links': {
+ 'self': 'http://example.com/identity',
+ },
+ 'name': 'Tempest User',
+ 'password_expires_at': '2016-11-06T15:32:17.000000',
+ }
+ }
+
+ FAKE_USER_LIST = {
+ 'links': {
+ 'next': None,
+ 'previous': None,
+ 'self': 'http://example.com/identity/v3/users',
+ },
+ 'users': [
+ {
+ 'domain_id': 'TempestDomain',
+ 'enabled': True,
+ 'id': '817fb3c23fd7465ba6d7fe1b1320121d',
+ 'links': {
+ 'self': 'http://example.com/identity/v3/users/' +
+ '817fb3c23fd7465ba6d7fe1b1320121d',
+ },
+ 'name': 'Tempest User',
+ 'password_expires_at': '2016-11-06T15:32:17.000000',
+ },
+ {
+ 'domain_id': 'TempestDomain',
+ 'enabled': True,
+ 'id': 'bdbfb1e2f1344be197e90a778379cca1',
+ 'links': {
+ 'self': 'http://example.com/identity/v3/users/' +
+ 'bdbfb1e2f1344be197e90a778379cca1',
+ },
+ 'name': 'Tempest User',
+ 'password_expires_at': None,
+ },
+ ]
+ }
+
+ FAKE_GROUP_LIST = {
+ 'links': {
+ 'self': 'http://example.com/identity/v3/groups',
+ 'previous': None,
+ 'next': None,
+ },
+ 'groups': [
+ {
+ 'description': 'Tempest Group One Description',
+ 'domain_id': 'TempestDomain',
+ 'id': '1c92f3453ed34291a074b87493455b8f',
+ 'links': {
+ 'self': 'http://example.com/identity/v3/groups/' +
+ '1c92f3453ed34291a074b87493455b8f'
+ },
+ 'name': 'Tempest Group One',
+ },
+ {
+ 'description': 'Tempest Group Two Description',
+ 'domain_id': 'TempestDomain',
+ 'id': 'ce9e7dafed3b4877a7d4466ed730a9ee',
+ 'links': {
+ 'self': 'http://example.com/identity/v3/groups/' +
+ 'ce9e7dafed3b4877a7d4466ed730a9ee'
+ },
+ 'name': 'Tempest Group Two',
+ },
+ ]
+ }
+
+ def setUp(self):
+ super(TestUsersClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = users_client.UsersClient(fake_auth, 'identity',
+ 'regionOne')
+
+ def _test_create_user(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.create_user,
+ 'tempest.lib.common.rest_client.RestClient.post',
+ self.FAKE_CREATE_USER,
+ bytes_body,
+ status=201,
+ )
+
+ def _test_show_user(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_user,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_USER_INFO,
+ bytes_body,
+ user_id='817fb3c23fd7465ba6d7fe1b1320121d',
+ )
+
+ def _test_list_users(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_users,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_USER_LIST,
+ bytes_body,
+ )
+
+ def _test_update_user(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.update_user,
+ 'tempest.lib.common.rest_client.RestClient.patch',
+ self.FAKE_USER_INFO,
+ bytes_body,
+ user_id='817fb3c23fd7465ba6d7fe1b1320121d',
+ name='NewName',
+ )
+
+ def _test_list_user_groups(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_user_groups,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_GROUP_LIST,
+ bytes_body,
+ user_id='817fb3c23fd7465ba6d7fe1b1320121d',
+ )
+
+ def test_create_user_with_string_body(self):
+ self._test_create_user()
+
+ def test_create_user_with_bytes_body(self):
+ self._test_create_user(bytes_body=True)
+
+ def test_show_user_with_string_body(self):
+ self._test_show_user()
+
+ def test_show_user_with_bytes_body(self):
+ self._test_show_user(bytes_body=True)
+
+ def test_list_users_with_string_body(self):
+ self._test_list_users()
+
+ def test_list_users_with_bytes_body(self):
+ self._test_list_users(bytes_body=True)
+
+ def test_update_user_with_string_body(self):
+ self._test_update_user()
+
+ def test_update_user_with_bytes_body(self):
+ self._test_update_user(bytes_body=True)
+
+ def test_list_user_groups_with_string_body(self):
+ self._test_list_user_groups()
+
+ def test_list_user_groups_with_bytes_body(self):
+ self._test_list_user_groups(bytes_body=True)
+
+ def test_delete_user(self):
+ self.check_service_client_function(
+ self.client.delete_user,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ user_id='817fb3c23fd7465ba6d7fe1b1320121d',
+ status=204,
+ )
+
+ def test_change_user_password(self):
+ self.check_service_client_function(
+ self.client.update_user_password,
+ 'tempest.lib.common.rest_client.RestClient.post',
+ {},
+ status=204,
+ user_id='817fb3c23fd7465ba6d7fe1b1320121d',
+ password='NewTempestPassword',
+ original_password='OldTempestPassword')