Merge "allow non '/' root for dashboard"
diff --git a/HACKING.rst b/HACKING.rst
index 45c35df..6ddb8ac 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -275,7 +275,7 @@
Test Documentation
------------------
For tests being added we need to require inline documentation in the form of
-docstings to explain what is being tested. In API tests for a new API a class
+docstrings to explain what is being tested. In API tests for a new API a class
level docstring should be added to an API reference doc. If one doesn't exist
a TODO comment should be put indicating that the reference needs to be added.
For individual API test cases a method level docstring should be used to
diff --git a/requirements.txt b/requirements.txt
index f00de0d..cc2a187 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,8 +1,8 @@
# The order of packages is significant, because pip processes them in the order
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
-pbr<2.0,>=1.3
-cliff>=1.13.0 # Apache-2.0
+pbr<2.0,>=1.4
+cliff>=1.14.0 # Apache-2.0
anyjson>=0.3.3
httplib2>=0.7.5
jsonschema!=2.5.0,<3.0.0,>=2.0.0
@@ -13,11 +13,11 @@
testrepository>=0.0.18
pyOpenSSL>=0.14
oslo.concurrency>=2.3.0 # Apache-2.0
-oslo.config>=1.11.0 # Apache-2.0
+oslo.config>=2.1.0 # Apache-2.0
oslo.i18n>=1.5.0 # Apache-2.0
oslo.log>=1.8.0 # Apache-2.0
oslo.serialization>=1.4.0 # Apache-2.0
-oslo.utils>=1.9.0 # Apache-2.0
+oslo.utils>=2.0.0 # Apache-2.0
six>=1.9.0
iso8601>=0.1.9
fixtures>=1.3.1
diff --git a/tempest/api/baremetal/admin/test_nodes.py b/tempest/api/baremetal/admin/test_nodes.py
index 4830dcd..b6dee18 100644
--- a/tempest/api/baremetal/admin/test_nodes.py
+++ b/tempest/api/baremetal/admin/test_nodes.py
@@ -20,7 +20,7 @@
class TestNodes(base.BaseBaremetalTest):
- '''Tests for baremetal nodes.'''
+ """Tests for baremetal nodes."""
def setUp(self):
super(TestNodes, self).setUp()
diff --git a/tempest/api/compute/admin/test_live_migration.py b/tempest/api/compute/admin/test_live_migration.py
index 6ffa4e9..79c2ac9 100644
--- a/tempest/api/compute/admin/test_live_migration.py
+++ b/tempest/api/compute/admin/test_live_migration.py
@@ -32,6 +32,7 @@
super(LiveBlockMigrationTestJSON, cls).setup_clients()
cls.admin_hosts_client = cls.os_adm.hosts_client
cls.admin_servers_client = cls.os_adm.servers_client
+ cls.admin_migration_client = cls.os_adm.migrations_client
@classmethod
def resource_setup(cls):
@@ -55,9 +56,10 @@
return self._get_server_details(server_id)[self._host_key]
def _migrate_server_to(self, server_id, dest_host):
+ bmflm = CONF.compute_feature_enabled.block_migration_for_live_migration
body = self.admin_servers_client.live_migrate_server(
- server_id, dest_host,
- CONF.compute_feature_enabled.block_migration_for_live_migration)
+ server_id, host=dest_host, block_migration=bmflm,
+ disk_over_commit=False)
return body
def _get_host_other_than(self, host):
@@ -109,7 +111,16 @@
self._migrate_server_to(server_id, target_host)
waiters.wait_for_server_status(self.servers_client, server_id, state)
- self.assertEqual(target_host, self._get_host_for_server(server_id))
+ migration_list = self.admin_migration_client.list_migrations()
+
+ msg = ("Live Migration failed. Migrations list for Instance "
+ "%s: [" % server_id)
+ for live_migration in migration_list:
+ if (live_migration['instance_uuid'] == server_id):
+ msg += "\n%s" % live_migration
+ msg += "]"
+ self.assertEqual(target_host, self._get_host_for_server(server_id),
+ msg)
@test.idempotent_id('1dce86b8-eb04-4c03-a9d8-9c1dc3ee0c7b')
@testtools.skipUnless(CONF.compute_feature_enabled.live_migration,
@@ -153,7 +164,7 @@
self.addCleanup(self._volume_clean_up, server_id, volume['id'])
# Attach the volume to the server
- self.servers_client.attach_volume(server_id, volume['id'],
+ self.servers_client.attach_volume(server_id, volumeId=volume['id'],
device='/dev/xvdb')
self.volumes_client.wait_for_volume_status(volume['id'], 'in-use')
diff --git a/tempest/api/compute/images/test_image_metadata.py b/tempest/api/compute/images/test_image_metadata.py
index ab82d91..d16c020 100644
--- a/tempest/api/compute/images/test_image_metadata.py
+++ b/tempest/api/compute/images/test_image_metadata.py
@@ -48,7 +48,7 @@
body = cls.glance_client.create_image(name=name,
container_format='bare',
disk_format='raw',
- is_public=False)
+ is_public=False)['image']
cls.image_id = body['id']
cls.images.append(cls.image_id)
image_file = six.StringIO(('*' * 1024))
diff --git a/tempest/api/compute/images/test_list_image_filters.py b/tempest/api/compute/images/test_list_image_filters.py
index 2c0ce59..247a57b 100644
--- a/tempest/api/compute/images/test_list_image_filters.py
+++ b/tempest/api/compute/images/test_list_image_filters.py
@@ -54,7 +54,7 @@
body = cls.glance_client.create_image(name=name,
container_format='bare',
disk_format='raw',
- is_public=False)
+ is_public=False)['image']
image_id = body['id']
cls.images.append(image_id)
# Wait 1 second between creation and upload to ensure a delta
diff --git a/tempest/api/compute/servers/test_delete_server.py b/tempest/api/compute/servers/test_delete_server.py
index b2acd34..673a401 100644
--- a/tempest/api/compute/servers/test_delete_server.py
+++ b/tempest/api/compute/servers/test_delete_server.py
@@ -122,7 +122,7 @@
waiters.wait_for_volume_status(volumes_client,
volume['id'], 'available')
self.client.attach_volume(server['id'],
- volume['id'],
+ volumeId=volume['id'],
device=device)
waiters.wait_for_volume_status(volumes_client,
volume['id'], 'in-use')
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index f0f6b8c..a20f7f5 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -323,7 +323,7 @@
properties=properties,
status='active',
sort_key='created_at',
- sort_dir='asc')
+ sort_dir='asc')['images']
self.assertEqual(2, len(image_list))
self.assertEqual((backup1, backup2),
(image_list[0]['name'], image_list[1]['name']))
@@ -347,7 +347,7 @@
properties=properties,
status='active',
sort_key='created_at',
- sort_dir='asc')
+ sort_dir='asc')['images']
self.assertEqual(2, len(image_list),
'Unexpected number of images for '
'v2:test_create_backup; was the oldest backup not '
@@ -474,6 +474,7 @@
def test_lock_unlock_server(self):
# Lock the server,try server stop(exceptions throw),unlock it and retry
self.client.lock_server(self.server_id)
+ self.addCleanup(self.client.unlock_server, self.server_id)
server = self.client.show_server(self.server_id)
self.assertEqual(server['status'], 'ACTIVE')
# Locked server is not allowed to be stopped by non-admin user
diff --git a/tempest/api/compute/servers/test_server_rescue_negative.py b/tempest/api/compute/servers/test_server_rescue_negative.py
index 2fe63ed..7a25526 100644
--- a/tempest/api/compute/servers/test_server_rescue_negative.py
+++ b/tempest/api/compute/servers/test_server_rescue_negative.py
@@ -137,7 +137,7 @@
self.assertRaises(lib_exc.Conflict,
self.servers_client.attach_volume,
self.server_id,
- volume['id'],
+ volumeId=volume['id'],
device='/dev/%s' % self.device)
@test.idempotent_id('f56e465b-fe10-48bf-b75d-646cda3a8bc9')
@@ -148,7 +148,7 @@
# Attach the volume to the server
self.servers_client.attach_volume(self.server_id,
- volume['id'],
+ volumeId=volume['id'],
device='/dev/%s' % self.device)
waiters.wait_for_volume_status(self.volumes_extensions_client,
volume['id'], 'in-use')
diff --git a/tempest/api/compute/test_authorization.py b/tempest/api/compute/test_authorization.py
index e7111b0..b542d7f 100644
--- a/tempest/api/compute/test_authorization.py
+++ b/tempest/api/compute/test_authorization.py
@@ -70,10 +70,11 @@
body = cls.glance_client.create_image(name=name,
container_format='bare',
disk_format='raw',
- is_public=False)
+ is_public=False)['image']
image_id = body['id']
image_file = six.StringIO(('*' * 1024))
- body = cls.glance_client.update_image(image_id, data=image_file)
+ body = cls.glance_client.update_image(image_id,
+ data=image_file)['image']
cls.glance_client.wait_for_image_status(image_id, 'active')
cls.image = cls.images_client.show_image(image_id)
diff --git a/tempest/api/compute/test_live_block_migration_negative.py b/tempest/api/compute/test_live_block_migration_negative.py
index fabe55d..2cd85f2 100644
--- a/tempest/api/compute/test_live_block_migration_negative.py
+++ b/tempest/api/compute/test_live_block_migration_negative.py
@@ -40,10 +40,10 @@
cls.admin_servers_client = cls.os_adm.servers_client
def _migrate_server_to(self, server_id, dest_host):
+ bmflm = CONF.compute_feature_enabled.block_migration_for_live_migration
body = self.admin_servers_client.live_migrate_server(
- server_id, dest_host,
- CONF.compute_feature_enabled.
- block_migration_for_live_migration)
+ server_id, host=dest_host, block_migration=bmflm,
+ disk_over_commit=False)
return body
@test.attr(type=['negative'])
diff --git a/tempest/api/compute/volumes/test_attach_volume.py b/tempest/api/compute/volumes/test_attach_volume.py
index 8e4278a..6496854 100644
--- a/tempest/api/compute/volumes/test_attach_volume.py
+++ b/tempest/api/compute/volumes/test_attach_volume.py
@@ -83,7 +83,7 @@
# Attach the volume to the server
self.attachment = self.servers_client.attach_volume(
self.server['id'],
- self.volume['id'],
+ volumeId=self.volume['id'],
device='/dev/%s' % self.device)
self.volumes_client.wait_for_volume_status(self.volume['id'], 'in-use')
diff --git a/tempest/api/identity/admin/v3/test_trusts.py b/tempest/api/identity/admin/v3/test_trusts.py
index 1ac34eb..8fe24c7 100644
--- a/tempest/api/identity/admin/v3/test_trusts.py
+++ b/tempest/api/identity/admin/v3/test_trusts.py
@@ -245,7 +245,7 @@
@test.idempotent_id('3e48f95d-e660-4fa9-85e0-5a3d85594384')
def test_trust_expire_invalid(self):
- # Test case to check we can check an invlaid expiry time
+ # Test case to check we can check an invalid expiry time
# is rejected with the correct error
# with an expiry specified
expires_str = 'bad.123Z'
diff --git a/tempest/api/image/base.py b/tempest/api/image/base.py
index 87013db..4572310 100644
--- a/tempest/api/image/base.py
+++ b/tempest/api/image/base.py
@@ -90,6 +90,26 @@
super(BaseV1ImageTest, cls).setup_clients()
cls.client = cls.os.image_client
+ # TODO(jswarren) Remove this method once the v2 client also returns the
+ # full response object, not just the ['image'] value. At that
+ # point BaseImageTest.create_image will need to retrieve the
+ # ['image'] value.
+ @classmethod
+ def create_image(cls, **kwargs):
+ """Wrapper that returns a test image."""
+ name = data_utils.rand_name(cls.__name__ + "-instance")
+
+ if 'name' in kwargs:
+ name = kwargs.pop('name')
+
+ container_format = kwargs.pop('container_format')
+ disk_format = kwargs.pop('disk_format')
+
+ image = cls.client.create_image(name, container_format,
+ disk_format, **kwargs)['image']
+ cls.created_images.append(image['id'])
+ return image
+
class BaseV1ImageMembersTest(BaseV1ImageTest):
diff --git a/tempest/api/image/v1/test_images.py b/tempest/api/image/v1/test_images.py
index 8beed32..7739d16 100644
--- a/tempest/api/image/v1/test_images.py
+++ b/tempest/api/image/v1/test_images.py
@@ -45,7 +45,7 @@
# Now try uploading an image file
image_file = moves.cStringIO(data_utils.random_bytes())
- body = self.client.update_image(image_id, data=image_file)
+ body = self.client.update_image(image_id, data=image_file)['image']
self.assertIn('size', body)
self.assertEqual(1024, body.get('size'))
@@ -168,14 +168,14 @@
@test.idempotent_id('246178ab-3b33-4212-9a4b-a7fe8261794d')
def test_index_no_params(self):
# Simple test to see all fixture images returned
- images_list = self.client.list_images()
+ images_list = self.client.list_images()['images']
image_list = map(lambda x: x['id'], images_list)
for image_id in self.created_images:
self.assertIn(image_id, image_list)
@test.idempotent_id('f1755589-63d6-4468-b098-589820eb4031')
def test_index_disk_format(self):
- images_list = self.client.list_images(disk_format='ami')
+ images_list = self.client.list_images(disk_format='ami')['images']
for image in images_list:
self.assertEqual(image['disk_format'], 'ami')
result_set = set(map(lambda x: x['id'], images_list))
@@ -184,7 +184,8 @@
@test.idempotent_id('2143655d-96d9-4bec-9188-8674206b4b3b')
def test_index_container_format(self):
- images_list = self.client.list_images(container_format='bare')
+ images_list = (self.client.list_images(container_format='bare')
+ ['images'])
for image in images_list:
self.assertEqual(image['container_format'], 'bare')
result_set = set(map(lambda x: x['id'], images_list))
@@ -193,7 +194,7 @@
@test.idempotent_id('feb32ac6-22bb-4a16-afd8-9454bb714b14')
def test_index_max_size(self):
- images_list = self.client.list_images(size_max=42)
+ images_list = self.client.list_images(size_max=42)['images']
for image in images_list:
self.assertTrue(image['size'] <= 42)
result_set = set(map(lambda x: x['id'], images_list))
@@ -202,7 +203,7 @@
@test.idempotent_id('6ffc16d0-4cbf-4401-95c8-4ac63eac34d8')
def test_index_min_size(self):
- images_list = self.client.list_images(size_min=142)
+ images_list = self.client.list_images(size_min=142)['images']
for image in images_list:
self.assertTrue(image['size'] >= 142)
result_set = set(map(lambda x: x['id'], images_list))
@@ -214,7 +215,7 @@
images_list = self.client.list_images(detail=True,
status='active',
sort_key='size',
- sort_dir='desc')
+ sort_dir='desc')['images']
top_size = images_list[0]['size'] # We have non-zero sized images
for image in images_list:
size = image['size']
@@ -226,7 +227,7 @@
def test_index_name(self):
images_list = self.client.list_images(
detail=True,
- name='New Remote Image dup')
+ name='New Remote Image dup')['images']
result_set = set(map(lambda x: x['id'], images_list))
for image in images_list:
self.assertEqual(image['name'], 'New Remote Image dup')
@@ -272,7 +273,7 @@
self.assertEqual(metadata['properties'], {'key1': 'value1'})
metadata['properties'].update(req_metadata)
metadata = self.client.update_image(
- self.image_id, properties=metadata['properties'])
+ self.image_id, properties=metadata['properties'])['image']
resp_metadata = self.client.get_image_meta(self.image_id)
expected = {'key1': 'alt1', 'key2': 'value2'}
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index 78b51c8..1308414 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -277,11 +277,11 @@
test_routes = []
routes_num = 5
# Create a router
- self.router = self._create_router(
+ router = self._create_router(
data_utils.rand_name('router-'), True)
self.addCleanup(
self._delete_extra_routes,
- self.router['id'])
+ router['id'])
# Update router extra route, second ip of the range is
# used as next hop
for i in range(routes_num):
@@ -290,7 +290,7 @@
next_cidr = next_cidr.next()
# Add router interface with subnet id
- self.create_router_interface(self.router['id'], subnet['id'])
+ self.create_router_interface(router['id'], subnet['id'])
cidr = netaddr.IPNetwork(subnet['cidr'])
next_hop = str(cidr[2])
@@ -300,9 +300,9 @@
)
test_routes.sort(key=lambda x: x['destination'])
- extra_route = self.client.update_extra_routes(self.router['id'],
+ extra_route = self.client.update_extra_routes(router['id'],
test_routes)
- show_body = self.client.show_router(self.router['id'])
+ show_body = self.client.show_router(router['id'])
# Assert the number of routes
self.assertEqual(routes_num, len(extra_route['router']['routes']))
self.assertEqual(routes_num, len(show_body['router']['routes']))
@@ -327,13 +327,13 @@
@test.idempotent_id('a8902683-c788-4246-95c7-ad9c6d63a4d9')
def test_update_router_admin_state(self):
- self.router = self._create_router(data_utils.rand_name('router-'))
- self.assertFalse(self.router['admin_state_up'])
+ router = self._create_router(data_utils.rand_name('router-'))
+ self.assertFalse(router['admin_state_up'])
# Update router admin state
- update_body = self.client.update_router(self.router['id'],
+ update_body = self.client.update_router(router['id'],
admin_state_up=True)
self.assertTrue(update_body['router']['admin_state_up'])
- show_body = self.client.show_router(self.router['id'])
+ show_body = self.client.show_router(router['id'])
self.assertTrue(show_body['router']['admin_state_up'])
@test.attr(type='smoke')
diff --git a/tempest/api/telemetry/base.py b/tempest/api/telemetry/base.py
index 0f9b7dd..5d1784f 100644
--- a/tempest/api/telemetry/base.py
+++ b/tempest/api/telemetry/base.py
@@ -85,6 +85,11 @@
body = client.create_image(
data_utils.rand_name('image'), container_format='bare',
disk_format='raw', visibility='private')
+ # TODO(jswarren) Move ['image'] up to initial body value assignment
+ # once both v1 and v2 glance clients include the full response
+ # object.
+ if 'image' in body:
+ body = body['image']
cls.image_ids.append(body['id'])
return body
diff --git a/tempest/api/volume/test_extensions.py b/tempest/api/volume/test_extensions.py
index 17db45f..cce9ace 100644
--- a/tempest/api/volume/test_extensions.py
+++ b/tempest/api/volume/test_extensions.py
@@ -30,7 +30,8 @@
@test.idempotent_id('94607eb0-43a5-47ca-82aa-736b41bd2e2c')
def test_list_extensions(self):
# List of all extensions
- extensions = self.volumes_extension_client.list_extensions()
+ extensions = (self.volumes_extension_client.list_extensions()
+ ['extensions'])
if len(CONF.volume_feature_enabled.api_extensions) == 0:
raise self.skipException('There are not any extensions configured')
extension_list = [extension.get('alias') for extension in extensions]
diff --git a/tempest/api/volume/test_volumes_snapshots.py b/tempest/api/volume/test_volumes_snapshots.py
index 1df1896..5860501 100644
--- a/tempest/api/volume/test_volumes_snapshots.py
+++ b/tempest/api/volume/test_volumes_snapshots.py
@@ -75,7 +75,8 @@
'ACTIVE')
mountpoint = '/dev/%s' % CONF.compute.volume_device_name
self.servers_client.attach_volume(
- server['id'], self.volume_origin['id'], mountpoint)
+ server['id'], volumeId=self.volume_origin['id'],
+ device=mountpoint)
self.volumes_client.wait_for_volume_status(self.volume_origin['id'],
'in-use')
self.addCleanup(self.volumes_client.wait_for_volume_status,
diff --git a/tempest/clients.py b/tempest/clients.py
index b3fb8a8..7cb4347 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -243,8 +243,8 @@
# with identity v2
if CONF.identity_feature_enabled.api_v2 and \
CONF.identity.auth_version == 'v2':
- # EC2 and S3 clients, if used, will check onfigured AWS credentials
- # and generate new ones if needed
+ # EC2 and S3 clients, if used, will check configured AWS
+ # credentials and generate new ones if needed
self.ec2api_client = botoclients.APIClientEC2(self.identity_client)
self.s3_client = botoclients.ObjectClientS3(self.identity_client)
diff --git a/tempest/cmd/javelin.py b/tempest/cmd/javelin.py
index 30fb38c..aef42be 100755
--- a/tempest/cmd/javelin.py
+++ b/tempest/cmd/javelin.py
@@ -503,7 +503,7 @@
def check_telemetry(self):
"""Check that ceilometer provides a sane sample.
- Confirm that there are more than one sample and that they have the
+ Confirm that there is more than one sample and that they have the
expected metadata.
If in check mode confirm that the oldest sample available is from
@@ -680,7 +680,7 @@
response = _get_image_by_name(client, image['name'])
if not response:
- LOG.info("Image '%s' does not exists" % image['name'])
+ LOG.info("Image '%s' does not exist" % image['name'])
continue
client.images.delete_image(response['id'])
@@ -729,7 +729,7 @@
# only create a network if the name isn't here
body = client.networks.list_networks()
if any(item['name'] == network['name'] for item in body['networks']):
- LOG.warning("Dupplicated network name: %s" % network['name'])
+ LOG.warning("Duplicated network name: %s" % network['name'])
continue
client.networks.create_network(name=network['name'])
@@ -781,7 +781,7 @@
# only create a router if the name isn't here
body = client.networks.list_routers()
if any(item['name'] == router['name'] for item in body['routers']):
- LOG.warning("Dupplicated router name: %s" % router['name'])
+ LOG.warning("Duplicated router name: %s" % router['name'])
continue
client.networks.create_router(router['name'])
@@ -813,7 +813,7 @@
# connect routers to their subnets
client.networks.add_router_interface_with_subnet_id(router_id,
subnet_id)
- # connect routers to exteral network if set to "gateway"
+ # connect routers to external network if set to "gateway"
if router['gateway']:
if CONF.network.public_network_id:
ext_net = CONF.network.public_network_id
@@ -871,7 +871,7 @@
server['name'], image_id, flavor_id, **kwargs)
server_id = body['id']
client.servers.wait_for_server_status(server_id, 'ACTIVE')
- # create to security group(s) after server spawning
+ # create security group(s) after server spawning
for secgroup in server['secgroups']:
client.servers.add_security_group(server_id, secgroup)
if CONF.compute.use_floatingip_for_ssh:
@@ -995,7 +995,7 @@
def create_resources():
LOG.info("Creating Resources")
# first create keystone level resources, and we need to be admin
- # for those.
+ # for this.
create_tenants(RES['tenants'])
create_users(RES['users'])
collect_users(RES['users'])
@@ -1015,7 +1015,7 @@
create_volumes(RES['volumes'])
# Only attempt attaching the volumes if servers are defined in the
- # resourcefile
+ # resource file
if 'servers' in RES:
create_servers(RES['servers'])
attach_volumes(RES['volumes'])
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index 93c2c10..a567c6a 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -106,7 +106,8 @@
def get_nic_name(self, address):
cmd = "ip -o addr | awk '/%s/ {print $2}'" % address
- return self.exec_command(cmd)
+ nic = self.exec_command(cmd)
+ return nic.strip().strip(":").lower()
def get_ip_list(self):
cmd = "ip address"
@@ -144,7 +145,6 @@
"""Renews DHCP lease via udhcpc client. """
file_path = '/var/run/udhcpc.'
nic_name = self.get_nic_name(fixed_ip)
- nic_name = nic_name.strip().lower()
pid = self.exec_command('cat {path}{nic}.pid'.
format(path=file_path, nic=nic_name))
pid = pid.strip()
diff --git a/tempest/common/waiters.py b/tempest/common/waiters.py
index 85a03cf..8112e9e 100644
--- a/tempest/common/waiters.py
+++ b/tempest/common/waiters.py
@@ -144,6 +144,8 @@
volume_status = body['status']
if volume_status == 'error':
raise exceptions.VolumeBuildErrorException(volume_id=volume_id)
+ if volume_status == 'error_restoring':
+ raise exceptions.VolumeRestoreErrorException(volume_id=volume_id)
if int(time.time()) - start >= client.build_timeout:
message = ('Volume %s failed to reach %s status (current %s) '
diff --git a/tempest/exceptions.py b/tempest/exceptions.py
index 15617c6..15482ab 100644
--- a/tempest/exceptions.py
+++ b/tempest/exceptions.py
@@ -92,6 +92,10 @@
message = "Volume %(volume_id)s failed to build and is in ERROR status"
+class VolumeRestoreErrorException(TempestException):
+ message = "Volume %(volume_id)s failed to restore and is in ERROR status"
+
+
class SnapshotBuildErrorException(TempestException):
message = "Snapshot %(snapshot_id)s failed to build and is in ERROR status"
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index da4ebbe..e9530a2 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -342,7 +342,7 @@
'is_public': 'False',
}
params['properties'] = properties
- image = self.image_client.create_image(**params)
+ image = self.image_client.create_image(**params)['image']
self.addCleanup(self.image_client.delete_image, image['id'])
self.assertEqual("queued", image['status'])
self.image_client.update_image(image['id'], data=image_file)
@@ -419,7 +419,7 @@
def nova_volume_attach(self):
volume = self.servers_client.attach_volume(
- self.server['id'], self.volume['id'], '/dev/%s'
+ self.server['id'], volumeId=self.volume['id'], device='/dev/%s'
% CONF.compute.volume_device_name)
self.assertEqual(self.volume['id'], volume['id'])
self.volumes_client.wait_for_volume_status(volume['id'], 'in-use')
@@ -663,14 +663,18 @@
def _get_server_port_id_and_ip4(self, server, ip_addr=None):
ports = self._list_ports(device_id=server['id'],
fixed_ip=ip_addr)
- self.assertEqual(len(ports), 1,
- "Unable to determine which port to target.")
# it might happen here that this port has more then one ip address
# as in case of dual stack- when this port is created on 2 subnets
- for ip46 in ports[0]['fixed_ips']:
- ip = ip46['ip_address']
- if netaddr.valid_ipv4(ip):
- return ports[0]['id'], ip
+ port_map = [(p["id"], fxip["ip_address"])
+ for p in ports
+ for fxip in p["fixed_ips"]
+ if netaddr.valid_ipv4(fxip["ip_address"])]
+
+ self.assertEqual(len(port_map), 1,
+ "Found multiple IPv4 addresses: %s. "
+ "Unable to determine which port to target."
+ % port_map)
+ return port_map[0]
def _get_network_by_name(self, network_name):
net = self._list_networks(name=network_name)
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index e676063..12af667 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -338,8 +338,8 @@
for remote_ip in address_list:
if should_connect:
- msg = "Timed out waiting for "
- "%s to become reachable" % remote_ip
+ msg = ("Timed out waiting for %s to become "
+ "reachable") % remote_ip
else:
msg = "ip address %s is reachable" % remote_ip
try:
diff --git a/tempest/scenario/test_network_v6.py b/tempest/scenario/test_network_v6.py
index 9481e58..a9394cb 100644
--- a/tempest/scenario/test_network_v6.py
+++ b/tempest/scenario/test_network_v6.py
@@ -69,13 +69,18 @@
'key_name': self.keypair['name'],
'security_groups': [{'name': self.sec_grp['name']}]}
- def prepare_network(self, address6_mode, n_subnets6=1):
+ def prepare_network(self, address6_mode, n_subnets6=1, dualnet=False):
"""Creates network with
given number of IPv6 subnets in the given mode and
one IPv4 subnet
Creates router with ports on all subnets
+ if dualnet - create IPv6 subnets on a different network
+ :return: list of created networks
"""
self.network = self._create_network(tenant_id=self.tenant_id)
+ if dualnet:
+ self.network_v6 = self._create_network(tenant_id=self.tenant_id)
+
sub4 = self._create_subnet(network=self.network,
namestart='sub4',
ip_version=4)
@@ -86,7 +91,8 @@
self.subnets_v6 = []
for _ in range(n_subnets6):
- sub6 = self._create_subnet(network=self.network,
+ net6 = self.network_v6 if dualnet else self.network
+ sub6 = self._create_subnet(network=net6,
namestart='sub6',
ip_version=6,
ipv6_ra_mode=address6_mode,
@@ -96,6 +102,8 @@
self.addCleanup(sub6.delete)
self.subnets_v6.append(sub6)
+ return [self.network, self.network_v6] if dualnet else [self.network]
+
@staticmethod
def define_server_ips(srv):
ips = {'4': None, '6': []}
@@ -107,11 +115,12 @@
ips['4'] = nic['addr']
return ips
- def prepare_server(self):
+ def prepare_server(self, networks=None):
username = CONF.compute.image_ssh_user
create_kwargs = self.srv_kwargs
- create_kwargs['networks'] = [{'uuid': self.network.id}]
+ networks = networks or [self.network]
+ create_kwargs['networks'] = [{'uuid': n.id} for n in networks]
srv = self.create_server(create_kwargs=create_kwargs)
fip = self.create_floating_ip(thing=srv)
@@ -119,18 +128,42 @@
ssh = self.get_remote_client(
server_or_ip=fip.floating_ip_address,
username=username)
- return ssh, ips
+ return ssh, ips, srv["id"]
- def _prepare_and_test(self, address6_mode, n_subnets6=1):
- self.prepare_network(address6_mode=address6_mode,
- n_subnets6=n_subnets6)
+ def turn_nic6_on(self, ssh, sid):
+ """Turns the IPv6 vNIC on
- sshv4_1, ips_from_api_1 = self.prepare_server()
- sshv4_2, ips_from_api_2 = self.prepare_server()
+ Required because guest images usually set only the first vNIC on boot.
+ Searches for the IPv6 vNIC's MAC and brings it up.
+
+ @param ssh: RemoteClient ssh instance to server
+ @param sid: server uuid
+ """
+ ports = [p["mac_address"] for p in
+ self._list_ports(device_id=sid,
+ network_id=self.network_v6.id)]
+ self.assertEqual(1, len(ports),
+ message="Multiple IPv6 ports found on network %s"
+ % self.network_v6)
+ mac6 = ports[0]
+ ssh.turn_nic_on(ssh.get_nic_name(mac6))
+
+ def _prepare_and_test(self, address6_mode, n_subnets6=1, dualnet=False):
+ net_list = self.prepare_network(address6_mode=address6_mode,
+ n_subnets6=n_subnets6,
+ dualnet=dualnet)
+
+ sshv4_1, ips_from_api_1, sid1 = self.prepare_server(networks=net_list)
+ sshv4_2, ips_from_api_2, sid2 = self.prepare_server(networks=net_list)
def guest_has_address(ssh, addr):
return addr in ssh.get_ip_list()
+ # Turn on 2nd NIC for Cirros when dualnet
+ if dualnet:
+ self.turn_nic6_on(sshv4_1, sid1)
+ self.turn_nic6_on(sshv4_2, sid2)
+
# get addresses assigned to vNIC as reported by 'ip address' utility
ips_from_ip_1 = sshv4_1.get_ip_list()
ips_from_ip_2 = sshv4_2.get_ip_list()
@@ -196,3 +229,25 @@
@test.services('compute', 'network')
def test_multi_prefix_slaac(self):
self._prepare_and_test(address6_mode='slaac', n_subnets6=2)
+
+ @test.idempotent_id('b6399d76-4438-4658-bcf5-0d6c8584fde2')
+ @test.services('compute', 'network')
+ def test_dualnet_slaac_from_os(self):
+ self._prepare_and_test(address6_mode='slaac', dualnet=True)
+
+ @test.idempotent_id('76f26acd-9688-42b4-bc3e-cd134c4cb09e')
+ @test.services('compute', 'network')
+ def test_dualnet_dhcp6_stateless_from_os(self):
+ self._prepare_and_test(address6_mode='dhcpv6-stateless', dualnet=True)
+
+ @test.idempotent_id('cf1c4425-766b-45b8-be35-e2959728eb00')
+ @test.services('compute', 'network')
+ def test_dualnet_multi_prefix_dhcpv6_stateless(self):
+ self._prepare_and_test(address6_mode='dhcpv6-stateless', n_subnets6=2,
+ dualnet=True)
+
+ @test.idempotent_id('9178ad42-10e4-47e9-8987-e02b170cc5cd')
+ @test.services('compute', 'network')
+ def test_dualnet_multi_prefix_slaac(self):
+ self._prepare_and_test(address6_mode='slaac', n_subnets6=2,
+ dualnet=True)
diff --git a/tempest/scenario/test_stamp_pattern.py b/tempest/scenario/test_stamp_pattern.py
index c1d9a1b..8b5a595 100644
--- a/tempest/scenario/test_stamp_pattern.py
+++ b/tempest/scenario/test_stamp_pattern.py
@@ -104,7 +104,7 @@
def _attach_volume(self, server, volume):
attached_volume = self.servers_client.attach_volume(
- server['id'], volume['id'], device='/dev/%s'
+ server['id'], volumeId=volume['id'], device='/dev/%s'
% CONF.compute.volume_device_name)
self.assertEqual(volume['id'], attached_volume['id'])
self._wait_for_volume_status(attached_volume, 'in-use')
diff --git a/tempest/services/compute/json/servers_client.py b/tempest/services/compute/json/servers_client.py
index 1159a58..a99a1f5 100644
--- a/tempest/services/compute/json/servers_client.py
+++ b/tempest/services/compute/json/servers_client.py
@@ -341,14 +341,9 @@
def start(self, server_id, **kwargs):
return self.action(server_id, 'os-start', None, **kwargs)
- def attach_volume(self, server_id, volume_id, device='/dev/vdz'):
+ def attach_volume(self, server_id, **kwargs):
"""Attaches a volume to a server instance."""
- post_body = json.dumps({
- 'volumeAttachment': {
- 'volumeId': volume_id,
- 'device': device,
- }
- })
+ post_body = json.dumps({'volumeAttachment': kwargs})
resp, body = self.post('servers/%s/os-volume_attachments' % server_id,
post_body)
body = json.loads(body)
@@ -386,16 +381,10 @@
"""Removes a security group from the server."""
return self.action(server_id, 'removeSecurityGroup', None, name=name)
- def live_migrate_server(self, server_id, dest_host, use_block_migration):
+ def live_migrate_server(self, server_id, **kwargs):
"""This should be called with administrator privileges ."""
- migrate_params = {
- "disk_over_commit": False,
- "block_migration": use_block_migration,
- "host": dest_host
- }
-
- req_body = json.dumps({'os-migrateLive': migrate_params})
+ req_body = json.dumps({'os-migrateLive': kwargs})
resp, body = self.post("servers/%s/action" % server_id, req_body)
self.validate_response(schema.server_actions_common_schema,
diff --git a/tempest/services/image/v1/json/image_client.py b/tempest/services/image/v1/json/image_client.py
index a07612a..d97da36 100644
--- a/tempest/services/image/v1/json/image_client.py
+++ b/tempest/services/image/v1/json/image_client.py
@@ -130,7 +130,7 @@
self._error_checker('POST', '/v1/images', headers, data, resp,
body_iter)
body = json.loads(''.join([c for c in body_iter]))
- return service_client.ResponseBody(resp, body['image'])
+ return service_client.ResponseBody(resp, body)
def _update_with_data(self, image_id, headers, data):
url = '/v1/images/%s' % image_id
@@ -139,7 +139,7 @@
self._error_checker('PUT', url, headers, data,
resp, body_iter)
body = json.loads(''.join([c for c in body_iter]))
- return service_client.ResponseBody(resp, body['image'])
+ return service_client.ResponseBody(resp, body)
@property
def http(self):
@@ -169,7 +169,7 @@
resp, body = self.post('v1/images', None, headers)
self.expected_success(201, resp.status)
body = json.loads(body)
- return service_client.ResponseBody(resp, body['image'])
+ return service_client.ResponseBody(resp, body)
def update_image(self, image_id, name=None, container_format=None,
data=None, properties=None):
@@ -193,7 +193,7 @@
resp, body = self.put(url, data, headers)
self.expected_success(200, resp.status)
body = json.loads(body)
- return service_client.ResponseBody(resp, body['image'])
+ return service_client.ResponseBody(resp, body)
def delete_image(self, image_id):
url = 'v1/images/%s' % image_id
@@ -223,7 +223,7 @@
resp, body = self.get(url)
self.expected_success(200, resp.status)
body = json.loads(body)
- return service_client.ResponseBodyList(resp, body['images'])
+ return service_client.ResponseBody(resp, body)
def get_image_meta(self, image_id):
url = 'v1/images/%s' % image_id
diff --git a/tempest/services/object_storage/container_client.py b/tempest/services/object_storage/container_client.py
index b31fe1b..e8ee20b 100644
--- a/tempest/services/object_storage/container_client.py
+++ b/tempest/services/object_storage/container_client.py
@@ -119,24 +119,6 @@
params={'limit': limit, 'format': 'json'})
self.expected_success(200, resp.status)
return objlist
- """tmp = []
- for obj in objlist:
- tmp.append(obj['name'])
- objlist = tmp
-
- if len(objlist) >= limit:
-
- # Increment marker
- marker = objlist[len(objlist) - 1]
-
- # Get the next chunk of the list
- objlist.extend(_list_all_container_objects(container,
- params={'marker': marker,
- 'limit': limit}))
- return objlist
- else:
- # Return final, complete list
- return objlist"""
def list_container_contents(self, container, params=None):
"""
diff --git a/tempest/services/volume/json/extensions_client.py b/tempest/services/volume/json/extensions_client.py
index 1098e1e..5744d4a 100644
--- a/tempest/services/volume/json/extensions_client.py
+++ b/tempest/services/volume/json/extensions_client.py
@@ -25,7 +25,7 @@
resp, body = self.get(url)
body = json.loads(body)
self.expected_success(200, resp.status)
- return service_client.ResponseBodyList(resp, body['extensions'])
+ return service_client.ResponseBody(resp, body)
class ExtensionsClient(BaseExtensionsClient):
diff --git a/tempest/stress/actions/volume_attach_delete.py b/tempest/stress/actions/volume_attach_delete.py
index d6965c7..99e9eb6 100644
--- a/tempest/stress/actions/volume_attach_delete.py
+++ b/tempest/stress/actions/volume_attach_delete.py
@@ -49,8 +49,8 @@
self.logger.info("attach volume (%s) to vm %s" %
(volume['id'], server_id))
self.manager.servers_client.attach_volume(server_id,
- volume['id'],
- '/dev/vdc')
+ volumeId=volume['id'],
+ device='/dev/vdc')
self.manager.volumes_client.wait_for_volume_status(volume['id'],
'in-use')
self.logger.info("volume (%s) attached to vm %s" %
diff --git a/tempest/stress/actions/volume_attach_verify.py b/tempest/stress/actions/volume_attach_verify.py
index 0e0141f..e30ca0c 100644
--- a/tempest/stress/actions/volume_attach_verify.py
+++ b/tempest/stress/actions/volume_attach_verify.py
@@ -165,7 +165,7 @@
if not self.new_server:
self.new_server_ops()
- # now we just test is number of partition increased or decrised
+ # now we just test that the number of partitions has increased or decreased
def part_wait(self, num_match):
def _part_state():
self.partitions = self.remote_client.get_partitions().split('\n')
@@ -191,8 +191,8 @@
self.logger.info("attach volume (%s) to vm %s" %
(self.volume['id'], self.server_id))
servers_client.attach_volume(self.server_id,
- self.volume['id'],
- self.part_name)
+ volumeId=self.volume['id'],
+ device=self.part_name)
self.manager.volumes_client.wait_for_volume_status(self.volume['id'],
'in-use')
if self.enable_ssh_verify:
@@ -205,7 +205,7 @@
self.manager.volumes_client.wait_for_volume_status(self.volume['id'],
'available')
if self.enable_ssh_verify:
- self.logger.info("Scanning for block device disapperance on %s"
+ self.logger.info("Scanning for block device disappearance on %s"
% self.server_id)
self.part_wait(self.detach_match_count)
if self.new_volume:
diff --git a/tempest/tests/test_waiters.py b/tempest/tests/common/test_waiters.py
similarity index 65%
rename from tempest/tests/test_waiters.py
rename to tempest/tests/common/test_waiters.py
index 329d610..7aa6595 100644
--- a/tempest/tests/test_waiters.py
+++ b/tempest/tests/common/test_waiters.py
@@ -18,6 +18,7 @@
from tempest.common import waiters
from tempest import exceptions
+from tempest.services.volume.json import volumes_client
from tempest.tests import base
@@ -47,3 +48,21 @@
self.assertRaises(exceptions.AddImageException,
waiters.wait_for_image_status,
self.client, 'fake_image_id', 'active')
+
+ @mock.patch.object(time, 'sleep')
+ def test_wait_for_volume_status_error_restoring(self, mock_sleep):
+ # Tests that the wait method raises VolumeRestoreErrorException if
+ # the volume status is 'error_restoring'.
+ client = mock.Mock(spec=volumes_client.BaseVolumesClient,
+ build_interval=1)
+ volume1 = {'status': 'restoring-backup'}
+ volume2 = {'status': 'error_restoring'}
+ mock_show = mock.Mock(side_effect=(volume1, volume2))
+ client.show_volume = mock_show
+ volume_id = '7532b91e-aa0a-4e06-b3e5-20c0c5ee1caa'
+ self.assertRaises(exceptions.VolumeRestoreErrorException,
+ waiters.wait_for_volume_status,
+ client, volume_id, 'available')
+ mock_show.assert_has_calls([mock.call(volume_id),
+ mock.call(volume_id)])
+ mock_sleep.assert_called_once_with(1)
diff --git a/tempest/tests/services/compute/test_keypairs_client.py b/tempest/tests/services/compute/test_keypairs_client.py
index e79e411..a0022b4 100644
--- a/tempest/tests/services/compute/test_keypairs_client.py
+++ b/tempest/tests/services/compute/test_keypairs_client.py
@@ -12,8 +12,10 @@
# License for the specific language governing permissions and limitations
# under the License.
+import copy
import httplib2
+from oslo_serialization import jsonutils as json
from oslotest import mockpatch
from tempest.services.compute.json import keypairs_client
@@ -23,6 +25,13 @@
class TestKeyPairsClient(base.TestCase):
+ FAKE_KEYPAIR = {
+ "public_key": "ssh-rsa foo Generated-by-Nova",
+ "name": u'\u2740(*\xb4\u25e1`*)\u2740',
+ "user_id": "525d55f98980415ba98e634972fa4a10",
+ "fingerprint": "76:24:66:49:d7:ca:6e:5c:77:ea:8e:bb:9c:15:5f:98"
+ }
+
def setUp(self):
super(TestKeyPairsClient, self).setUp()
fake_auth = fake_auth_provider.FakeAuthProvider()
@@ -45,3 +54,58 @@
def test_list_keypairs_with_bytes_body(self):
self._test_list_keypairs(bytes_body=True)
+
+ def _test_show_keypair(self, bytes_body=False):
+ fake_keypair = copy.deepcopy(self.FAKE_KEYPAIR)
+ fake_keypair.update({
+ "deleted": False,
+ "created_at": "2015-07-22T04:53:52.000000",
+ "updated_at": None,
+ "deleted_at": None,
+ "id": 1
+ })
+ serialized_body = json.dumps({"keypair": fake_keypair})
+ if bytes_body:
+ serialized_body = serialized_body.encode('utf-8')
+
+ mocked_resp = (httplib2.Response({'status': 200}), serialized_body)
+ self.useFixture(mockpatch.Patch(
+ 'tempest.common.service_client.ServiceClient.get',
+ return_value=mocked_resp))
+ resp = self.client.show_keypair("test")
+ self.assertEqual(fake_keypair, resp)
+
+ def test_show_keypair_with_str_body(self):
+ self._test_show_keypair()
+
+ def test_show_keypair_with_bytes_body(self):
+ self._test_show_keypair(bytes_body=True)
+
+ def _test_create_keypair(self, bytes_body=False):
+ fake_keypair = copy.deepcopy(self.FAKE_KEYPAIR)
+ fake_keypair.update({"private_key": "foo"})
+ serialized_body = json.dumps({"keypair": fake_keypair})
+ if bytes_body:
+ serialized_body = serialized_body.encode('utf-8')
+
+ mocked_resp = (httplib2.Response({'status': 200}), serialized_body)
+ self.useFixture(mockpatch.Patch(
+ 'tempest.common.service_client.ServiceClient.post',
+ return_value=mocked_resp))
+ resp = self.client.create_keypair(name='test')
+ self.assertEqual(fake_keypair, resp)
+
+ def test_create_keypair_with_str_body(self):
+ self._test_create_keypair()
+
+ def test_create_keypair_with_bytes_body(self):
+ self._test_create_keypair(bytes_body=True)
+
+ def test_delete_keypair(self):
+ expected = {}
+ mocked_resp = (httplib2.Response({'status': 202}), None)
+ self.useFixture(mockpatch.Patch(
+ 'tempest.common.service_client.ServiceClient.delete',
+ return_value=mocked_resp))
+ resp = self.client.delete_keypair('test')
+ self.assertEqual(expected, resp)
diff --git a/tempest/tests/services/compute/test_quota_classes_client.py b/tempest/tests/services/compute/test_quota_classes_client.py
new file mode 100644
index 0000000..ff9b310
--- /dev/null
+++ b/tempest/tests/services/compute/test_quota_classes_client.py
@@ -0,0 +1,81 @@
+# Copyright 2015 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.
+
+import copy
+import httplib2
+
+from oslo_serialization import jsonutils as json
+from oslotest import mockpatch
+
+from tempest.services.compute.json import quota_classes_client
+from tempest.tests import base
+from tempest.tests import fake_auth_provider
+
+
+class TestQuotaClassesClient(base.TestCase):
+
+ FAKE_QUOTA_CLASS_SET = {
+ "injected_file_content_bytes": 10240,
+ "metadata_items": 128,
+ "server_group_members": 10,
+ "server_groups": 10,
+ "ram": 51200,
+ "floating_ips": 10,
+ "key_pairs": 100,
+ "id": u'\u2740(*\xb4\u25e1`*)\u2740',
+ "instances": 10,
+ "security_group_rules": 20,
+ "security_groups": 10,
+ "injected_files": 5,
+ "cores": 20,
+ "fixed_ips": -1,
+ "injected_file_path_bytes": 255,
+ }
+
+ def setUp(self):
+ super(TestQuotaClassesClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = quota_classes_client.QuotaClassesClient(
+ fake_auth, 'compute', 'regionOne')
+
+ def _test_show_quota_class_set(self, bytes_body=False):
+ serialized_body = json.dumps({
+ "quota_class_set": self.FAKE_QUOTA_CLASS_SET})
+ if bytes_body:
+ serialized_body = serialized_body.encode('utf-8')
+
+ mocked_resp = (httplib2.Response({'status': 200}), serialized_body)
+ self.useFixture(mockpatch.Patch(
+ 'tempest.common.service_client.ServiceClient.get',
+ return_value=mocked_resp))
+ resp = self.client.show_quota_class_set("test")
+ self.assertEqual(self.FAKE_QUOTA_CLASS_SET, resp)
+
+ def test_show_quota_class_set_with_str_body(self):
+ self._test_show_quota_class_set()
+
+ def test_show_quota_class_set_with_bytes_body(self):
+ self._test_show_quota_class_set(bytes_body=True)
+
+ def test_update_quota_class_set(self):
+ fake_quota_class_set = copy.deepcopy(self.FAKE_QUOTA_CLASS_SET)
+ fake_quota_class_set.pop("id")
+ serialized_body = json.dumps({"quota_class_set": fake_quota_class_set})
+
+ mocked_resp = (httplib2.Response({'status': 200}), serialized_body)
+ self.useFixture(mockpatch.Patch(
+ 'tempest.common.service_client.ServiceClient.put',
+ return_value=mocked_resp))
+ resp = self.client.update_quota_class_set("test")
+ self.assertEqual(fake_quota_class_set, resp)