Merge "Use 'OS-EXT-SRV-ATTR:host' directly"
diff --git a/README.rst b/README.rst
index 13f4f61..3c0463b 100644
--- a/README.rst
+++ b/README.rst
@@ -124,6 +124,9 @@
Release Versioning
------------------
+`Tempest Release Notes <http://docs.openstack.org/releasenotes/tempest>`_
+shows what changes have been released on each version.
+
Tempest's released versions are broken into 2 sets of information. Depending on
how you intend to consume tempest you might need
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/doc/source/configuration.rst b/doc/source/configuration.rst
index e4b104f..6c55015 100644
--- a/doc/source/configuration.rst
+++ b/doc/source/configuration.rst
@@ -135,7 +135,10 @@
It is worth pointing out that each set of credentials in the accounts.yaml
should have a unique project. This is required to provide proper isolation
to the tests using the credentials, and failure to do this will likely cause
-unexpected failures in some tests.
+unexpected failures in some tests. Also, ensure that these projects and users
+used do not have any pre-existing resources created. Tempest assumes all
+tenants it's using are empty and may sporadically fail if there are unexpected
+resources present.
When the keystone in the target cloud requires domain scoped tokens to
perform admin actions, all pre-provisioned admin users must have a role
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/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/setup.cfg b/setup.cfg
index 91ede20..50bf891 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -17,6 +17,7 @@
Programming Language :: Python :: 2.7
Programming Language :: Python :: 3
Programming Language :: Python :: 3.4
+ Programming Language :: Python :: 3.5
[files]
packages =
diff --git a/tempest/README.rst b/tempest/README.rst
index 113b191..c9a0491 100644
--- a/tempest/README.rst
+++ b/tempest/README.rst
@@ -26,10 +26,9 @@
API tests are validation tests for the OpenStack API. They should not
use the existing python clients for OpenStack, but should instead use
-the tempest implementations of clients. This allows us to test both
-XML and JSON. Having raw clients also lets us pass invalid JSON and
-XML to the APIs and see the results, something we could not get with
-the native clients.
+the tempest implementations of clients. Having raw clients let us
+pass invalid JSON to the APIs and see the results, something we could
+not get with the native clients.
When it makes sense, API testing should be moved closer to the
projects themselves, possibly as functional tests in their unit test
diff --git a/tempest/api/baremetal/admin/base.py b/tempest/api/baremetal/admin/base.py
index 2d3f190..ac5986c 100644
--- a/tempest/api/baremetal/admin/base.py
+++ b/tempest/api/baremetal/admin/base.py
@@ -99,7 +99,7 @@
def create_chassis(cls, description=None):
"""Wrapper utility for creating test chassis.
- :param description: A description of the chassis. if not supplied,
+ :param description: A description of the chassis. If not supplied,
a random value will be generated.
:return: Created chassis.
@@ -114,6 +114,7 @@
memory_mb=4096):
"""Wrapper utility for creating test baremetal nodes.
+ :param chassis_id: The unique identifier of the chassis.
:param cpu_arch: CPU architecture of the node. Default: x86.
:param cpus: Number of CPUs. Default: 8.
:param local_gb: Disk size. Default: 10.
@@ -133,6 +134,7 @@
def create_port(cls, node_id, address, extra=None, uuid=None):
"""Wrapper utility for creating test ports.
+ :param node_id: The unique identifier of the node.
:param address: MAC address of the port.
:param extra: Meta data of the port. If not supplied, an empty
dictionary will be created.
@@ -150,7 +152,7 @@
def delete_chassis(cls, chassis_id):
"""Deletes a chassis having the specified UUID.
- :param uuid: The unique identifier of the chassis.
+ :param chassis_id: The unique identifier of the chassis.
:return: Server response.
"""
@@ -166,7 +168,7 @@
def delete_node(cls, node_id):
"""Deletes a node having the specified UUID.
- :param uuid: The unique identifier of the node.
+ :param node_id: The unique identifier of the node.
:return: Server response.
"""
@@ -182,7 +184,7 @@
def delete_port(cls, port_id):
"""Deletes a port having the specified UUID.
- :param uuid: The unique identifier of the port.
+ :param port_id: The unique identifier of the port.
:return: Server response.
"""
diff --git a/tempest/api/compute/admin/test_live_migration.py b/tempest/api/compute/admin/test_live_migration.py
index fd309eb..18a6afc 100644
--- a/tempest/api/compute/admin/test_live_migration.py
+++ b/tempest/api/compute/admin/test_live_migration.py
@@ -156,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_security_groups.py b/tempest/api/compute/admin/test_security_groups.py
index 58da8b9..e329869 100644
--- a/tempest/api/compute/admin/test_security_groups.py
+++ b/tempest/api/compute/admin/test_security_groups.py
@@ -15,11 +15,8 @@
from tempest.api.compute import base
from tempest.common.utils import data_utils
-from tempest import config
from tempest import test
-CONF = config.CONF
-
class SecurityGroupsTestAdminJSON(base.BaseV2ComputeAdminTest):
diff --git a/tempest/api/compute/admin/test_servers.py b/tempest/api/compute/admin/test_servers.py
index 94c9a29..d7b1be7 100755
--- a/tempest/api/compute/admin/test_servers.py
+++ b/tempest/api/compute/admin/test_servers.py
@@ -68,6 +68,13 @@
self.assertIn(self.s1_id, map(lambda x: x['id'], servers))
self.assertNotIn(self.s2_id, map(lambda x: x['id'], servers))
+ @test.idempotent_id('d56e9540-73ed-45e0-9b88-98fc419087eb')
+ def test_list_servers_detailed_filter_by_invalid_status(self):
+ params = {'status': 'invalid_status'}
+ body = self.client.list_servers(detail=True, **params)
+ servers = body['servers']
+ self.assertEqual([], servers)
+
@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
diff --git a/tempest/api/compute/admin/test_servers_negative.py b/tempest/api/compute/admin/test_servers_negative.py
index 5ff5d58..db6e682 100755
--- a/tempest/api/compute/admin/test_servers_negative.py
+++ b/tempest/api/compute/admin/test_servers_negative.py
@@ -34,6 +34,7 @@
cls.client = cls.os_adm.servers_client
cls.non_adm_client = cls.servers_client
cls.flavors_client = cls.os_adm.flavors_client
+ cls.quotas_client = cls.os_adm.quotas_client
@classmethod
def resource_setup(cls):
@@ -64,8 +65,8 @@
self.useFixture(fixtures.LockFixture('compute_quotas'))
flavor_name = data_utils.rand_name("flavor")
flavor_id = self._get_unused_flavor_id()
- quota_set = (self.quotas_client.show_default_quota_set(self.tenant_id)
- ['quota_set'])
+ quota_set = self.quotas_client.show_quota_set(
+ self.tenant_id)['quota_set']
ram = int(quota_set['ram'])
if ram == -1:
raise self.skipException("default ram quota set is -1,"
@@ -93,8 +94,8 @@
flavor_name = data_utils.rand_name("flavor")
flavor_id = self._get_unused_flavor_id()
ram = 512
- quota_set = (self.quotas_client.show_default_quota_set(self.tenant_id)
- ['quota_set'])
+ quota_set = self.quotas_client.show_quota_set(
+ self.tenant_id)['quota_set']
vcpus = int(quota_set['cores'])
if vcpus == -1:
raise self.skipException("default cores quota set is -1,"
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/servers/test_create_server.py b/tempest/api/compute/servers/test_create_server.py
index e8df52d..78f0db4 100755
--- a/tempest/api/compute/servers/test_create_server.py
+++ b/tempest/api/compute/servers/test_create_server.py
@@ -139,7 +139,7 @@
hostname = linux_client.get_hostname()
msg = ('Failed while verifying servername equals hostname. Expected '
'hostname "%s" but got "%s".' % (self.name, hostname))
- self.assertEqual(self.name, hostname, msg)
+ self.assertEqual(self.name.lower(), hostname, msg)
@test.idempotent_id('ed20d3fb-9d1f-4329-b160-543fbd5d9811')
def test_create_server_with_scheduler_hint_group(self):
diff --git a/tempest/api/compute/servers/test_list_server_filters.py b/tempest/api/compute/servers/test_list_server_filters.py
index c1fbb12..26cbb090 100644
--- a/tempest/api/compute/servers/test_list_server_filters.py
+++ b/tempest/api/compute/servers/test_list_server_filters.py
@@ -17,13 +17,10 @@
from tempest.common import fixed_network
from tempest.common.utils import data_utils
from tempest.common import waiters
-from tempest import config
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
from tempest import test
-CONF = config.CONF
-
class ListServerFiltersTestJSON(base.BaseV2ComputeTest):
@@ -274,14 +271,9 @@
msg = 'fixed_network_name needs to be configured to run this test'
raise self.skipException(msg)
self.s1 = self.client.show_server(self.s1['id'])['server']
- for addr_spec in self.s1['addresses'][self.fixed_network_name]:
- ip = addr_spec['addr']
- if addr_spec['version'] == 4:
- params = {'ip': ip}
- break
- else:
- msg = "Skipped until bug 1450859 is resolved"
- raise self.skipException(msg)
+ # Get first ip address inspite of v4 or v6
+ addr_spec = self.s1['addresses'][self.fixed_network_name][0]
+ params = {'ip': addr_spec['addr']}
body = self.client.list_servers(**params)
servers = body['servers']
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index 4a5bab5..062e920 100755
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -270,6 +270,9 @@
'SHUTOFF')
self.client.resize_server(self.server_id, self.flavor_ref_alt)
+ # NOTE(jlk): Explicitly delete the server to get a new one for later
+ # tests. Avoids resize down race issues.
+ self.addCleanup(self.delete_server, self.server_id)
waiters.wait_for_server_status(self.client, self.server_id,
'VERIFY_RESIZE')
@@ -285,10 +288,6 @@
# NOTE(mriedem): tearDown requires the server to be started.
self.client.start_server(self.server_id)
- # NOTE(jlk): Explicitly delete the server to get a new one for later
- # tests. Avoids resize down race issues.
- self.addCleanup(self.delete_server, self.server_id)
-
@test.idempotent_id('1499262a-9328-4eda-9068-db1ac57498d2')
@testtools.skipUnless(CONF.compute_feature_enabled.resize,
'Resize not available.')
@@ -309,6 +308,9 @@
# values after a resize is reverted
self.client.resize_server(self.server_id, self.flavor_ref_alt)
+ # NOTE(zhufl): Explicitly delete the server to get a new one for later
+ # tests. Avoids resize down race issues.
+ self.addCleanup(self.delete_server, self.server_id)
waiters.wait_for_server_status(self.client, self.server_id,
'VERIFY_RESIZE')
diff --git a/tempest/api/data_processing/base.py b/tempest/api/data_processing/base.py
index d5ba76c..c8506ae 100644
--- a/tempest/api/data_processing/base.py
+++ b/tempest/api/data_processing/base.py
@@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from collections import OrderedDict
+import collections
import copy
import six
@@ -112,7 +112,7 @@
DEFAULT_TEMPLATES = {
- 'vanilla': OrderedDict([
+ 'vanilla': collections.OrderedDict([
('2.6.0', copy.deepcopy(BASE_VANILLA_DESC)),
('2.7.1', copy.deepcopy(BASE_VANILLA_DESC)),
('1.2.1', {
@@ -148,7 +148,7 @@
}
})
]),
- 'hdp': OrderedDict([
+ 'hdp': collections.OrderedDict([
('2.0.6', {
'NODES': {
'master1': {
@@ -174,11 +174,11 @@
}
})
]),
- 'spark': OrderedDict([
+ 'spark': collections.OrderedDict([
('1.0.0', copy.deepcopy(BASE_SPARK_DESC)),
('1.3.1', copy.deepcopy(BASE_SPARK_DESC))
]),
- 'cdh': OrderedDict([
+ 'cdh': collections.OrderedDict([
('5.4.0', copy.deepcopy(BASE_CDH_DESC)),
('5.3.0', copy.deepcopy(BASE_CDH_DESC)),
('5', copy.deepcopy(BASE_CDH_DESC))
diff --git a/tempest/api/identity/admin/v3/test_domains.py b/tempest/api/identity/admin/v3/test_domains.py
index 24a7a4e..cbf1439 100644
--- a/tempest/api/identity/admin/v3/test_domains.py
+++ b/tempest/api/identity/admin/v3/test_domains.py
@@ -44,11 +44,11 @@
super(DomainsTestJSON, cls).resource_cleanup()
@classmethod
- def _delete_domain(self, domain_id):
+ def _delete_domain(cls, domain_id):
# It is necessary to disable the domain before deleting,
# or else it would result in unauthorized error
- self.domains_client.update_domain(domain_id, enabled=False)
- self.domains_client.delete_domain(domain_id)
+ cls.domains_client.update_domain(domain_id, enabled=False)
+ cls.domains_client.delete_domain(domain_id)
@test.idempotent_id('8cf516ef-2114-48f1-907b-d32726c734d4')
def test_list_domains(self):
diff --git a/tempest/api/identity/admin/v3/test_inherits.py b/tempest/api/identity/admin/v3/test_inherits.py
index 0d3d1d6..76771bb 100644
--- a/tempest/api/identity/admin/v3/test_inherits.py
+++ b/tempest/api/identity/admin/v3/test_inherits.py
@@ -12,11 +12,8 @@
from tempest.api.identity import base
from tempest.common.utils import data_utils
-from tempest import config
from tempest import test
-CONF = config.CONF
-
class BaseInheritsV3Test(base.BaseIdentityV3AdminTest):
diff --git a/tempest/api/identity/base.py b/tempest/api/identity/base.py
index b512d50..deb5413 100644
--- a/tempest/api/identity/base.py
+++ b/tempest/api/identity/base.py
@@ -13,14 +13,11 @@
# License for the specific language governing permissions and limitations
# under the License.
-from oslo_log import log as logging
-
from tempest.common.utils import data_utils
from tempest import config
import tempest.test
CONF = config.CONF
-LOG = logging.getLogger(__name__)
class BaseIdentityTest(tempest.test.BaseTestCase):
diff --git a/tempest/api/image/base.py b/tempest/api/image/base.py
index 78e53b4..e7a46b0 100755
--- a/tempest/api/image/base.py
+++ b/tempest/api/image/base.py
@@ -144,6 +144,18 @@
cls.resource_types_client = cls.os.resource_types_client
cls.schemas_client = cls.os.schemas_client
+ def create_namespace(cls, namespace_name=None, visibility='public',
+ description='Tempest', protected=False,
+ **kwargs):
+ if not namespace_name:
+ namespace_name = data_utils.rand_name('test-ns')
+ kwargs.setdefault('display_name', namespace_name)
+ namespace = cls.namespaces_client.create_namespace(
+ namespace=namespace_name, visibility=visibility,
+ description=description, protected=protected, **kwargs)
+ cls.addCleanup(cls.namespaces_client.delete_namespace, namespace_name)
+ return namespace
+
class BaseV2MemberImageTest(BaseV2ImageTest):
diff --git a/tempest/api/image/v1/test_images.py b/tempest/api/image/v1/test_images.py
index e4fbbe3..694408d 100644
--- a/tempest/api/image/v1/test_images.py
+++ b/tempest/api/image/v1/test_images.py
@@ -322,10 +322,7 @@
metadata['properties'].update(req_metadata)
headers = common_image.image_meta_to_headers(
properties=metadata['properties'])
- metadata = self.client.update_image(self.image_id,
- headers=headers)['image']
-
+ self.client.update_image(self.image_id, headers=headers)
resp = self.client.check_image(self.image_id)
resp_metadata = common_image.get_image_meta_from_headers(resp)
- expected = {'key1': 'alt1', 'key2': 'value2'}
- self.assertEqual(expected, resp_metadata['properties'])
+ self.assertEqual(req_metadata, resp_metadata['properties'])
diff --git a/tempest/api/image/v2/test_images_metadefs_resource_types.py b/tempest/api/image/v2/test_images_metadefs_resource_types.py
new file mode 100644
index 0000000..a5143a1
--- /dev/null
+++ b/tempest/api/image/v2/test_images_metadefs_resource_types.py
@@ -0,0 +1,54 @@
+# Copyright 2016 Ericsson India Global Services Private Limited
+# 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.api.image import base
+from tempest import test
+
+
+class MetadataResourceTypesTest(base.BaseV2ImageTest):
+ """Test the Metadata definition ressource types basic functionality"""
+
+ @test.idempotent_id('6f358a4e-5ef0-11e6-a795-080027d0d606')
+ def test_basic_meta_def_resource_type_association(self):
+ # Get the available resource types and use one resource_type
+ body = self.resource_types_client.list_resource_types()
+ resource_name = body['resource_types'][0]['name']
+ # Create a namespace
+ namespace = self.create_namespace()
+ # Create resource type association
+ body = self.resource_types_client.create_resource_type_association(
+ namespace['namespace'], name=resource_name)
+ self.assertEqual(body['name'], resource_name)
+ # NOTE(raiesmh08): Here intentionally I have not added addcleanup
+ # method for resource type dissociation because its a metadata add and
+ # being cleaned as soon as namespace is cleaned at test case level.
+ # When namespace cleans, resource type associaion will automatically
+ # clean without any error or dependency.
+
+ # List resource type associations and validate creation
+ rs_type_associations = [
+ rs_type_association['name'] for rs_type_association in
+ self.resource_types_client.list_resource_type_association(
+ namespace['namespace'])['resource_type_associations']]
+ self.assertIn(resource_name, rs_type_associations)
+ # Delete resource type association
+ self.resource_types_client.delete_resource_type_association(
+ namespace['namespace'], resource_name)
+ # List resource type associations and validate deletion
+ rs_type_associations = [
+ rs_type_association['name'] for rs_type_association in
+ self.resource_types_client.list_resource_type_association(
+ namespace['namespace'])['resource_type_associations']]
+ self.assertNotIn(resource_name, rs_type_associations)
diff --git a/tempest/api/network/admin/test_floating_ips_admin_actions.py b/tempest/api/network/admin/test_floating_ips_admin_actions.py
index baeaa0c..2686af2 100644
--- a/tempest/api/network/admin/test_floating_ips_admin_actions.py
+++ b/tempest/api/network/admin/test_floating_ips_admin_actions.py
@@ -26,6 +26,13 @@
credentials = ['primary', 'alt', 'admin']
@classmethod
+ def skip_checks(cls):
+ super(FloatingIPAdminTestJSON, cls).skip_checks()
+ if not test.is_extension_enabled('router', 'network'):
+ msg = "router extension not enabled."
+ raise cls.skipException(msg)
+
+ @classmethod
def setup_clients(cls):
super(FloatingIPAdminTestJSON, cls).setup_clients()
cls.alt_floating_ips_client = cls.alt_manager.floating_ips_client
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index 9e7c795..5c67d68 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -270,7 +270,7 @@
"""Wrapper utility that returns a test metering label."""
body = cls.admin_metering_labels_client.create_metering_label(
description=description,
- name=data_utils.rand_name("metering-label"))
+ name=name)
metering_label = body['metering_label']
cls.metering_labels.append(metering_label)
return metering_label
diff --git a/tempest/api/object_storage/test_container_quotas.py b/tempest/api/object_storage/test_container_quotas.py
index 5ed92c4..8cbe441 100644
--- a/tempest/api/object_storage/test_container_quotas.py
+++ b/tempest/api/object_storage/test_container_quotas.py
@@ -15,11 +15,9 @@
from tempest.api.object_storage import base
from tempest.common.utils import data_utils
-from tempest import config
from tempest.lib import exceptions as lib_exc
from tempest import test
-CONF = config.CONF
QUOTA_BYTES = 10
QUOTA_COUNT = 3
diff --git a/tempest/api/object_storage/test_container_services.py b/tempest/api/object_storage/test_container_services.py
index cf6ded1..8522269 100644
--- a/tempest/api/object_storage/test_container_services.py
+++ b/tempest/api/object_storage/test_container_services.py
@@ -19,9 +19,6 @@
class ContainerTest(base.BaseObjectTest):
- def setUp(self):
- super(ContainerTest, self).setUp()
-
def tearDown(self):
self.delete_containers()
super(ContainerTest, self).tearDown()
diff --git a/tempest/api/object_storage/test_object_temp_url.py b/tempest/api/object_storage/test_object_temp_url.py
index c2d3b69..7287a2d 100644
--- a/tempest/api/object_storage/test_object_temp_url.py
+++ b/tempest/api/object_storage/test_object_temp_url.py
@@ -20,11 +20,8 @@
from tempest.api.object_storage import base
from tempest.common.utils import data_utils
-from tempest import config
from tempest import test
-CONF = config.CONF
-
class ObjectTempUrlTest(base.BaseObjectTest):
diff --git a/tempest/api/orchestration/stacks/test_environment.py b/tempest/api/orchestration/stacks/test_environment.py
index 9d2b425..f2ffbd7 100644
--- a/tempest/api/orchestration/stacks/test_environment.py
+++ b/tempest/api/orchestration/stacks/test_environment.py
@@ -12,13 +12,9 @@
from tempest.api.orchestration import base
from tempest.common.utils import data_utils
-from tempest import config
from tempest import test
-CONF = config.CONF
-
-
class StackEnvironmentTest(base.BaseOrchestrationTest):
@test.idempotent_id('37d4346b-1abd-4442-b7b1-2a4e5749a1e3')
diff --git a/tempest/api/orchestration/stacks/test_soft_conf.py b/tempest/api/orchestration/stacks/test_soft_conf.py
index aa0b46a..b660f6e 100644
--- a/tempest/api/orchestration/stacks/test_soft_conf.py
+++ b/tempest/api/orchestration/stacks/test_soft_conf.py
@@ -12,12 +12,9 @@
from tempest.api.orchestration import base
from tempest.common.utils import data_utils
-from tempest import config
from tempest.lib import exceptions as lib_exc
from tempest import test
-CONF = config.CONF
-
class TestSoftwareConfig(base.BaseOrchestrationTest):
diff --git a/tempest/api/volume/admin/test_backends_capabilities.py b/tempest/api/volume/admin/test_backends_capabilities.py
new file mode 100644
index 0000000..8a21853
--- /dev/null
+++ b/tempest/api/volume/admin/test_backends_capabilities.py
@@ -0,0 +1,79 @@
+# Copyright 2016 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.
+
+import operator
+
+from tempest.api.volume import base
+from tempest import test
+
+
+class BackendsCapabilitiesAdminV2TestsJSON(base.BaseVolumeAdminTest):
+
+ CAPABILITIES = ('namespace',
+ 'vendor_name',
+ 'volume_backend_name',
+ 'pool_name',
+ 'driver_version',
+ 'storage_protocol',
+ 'display_name',
+ 'description',
+ 'visibility',
+ 'properties')
+
+ @classmethod
+ def resource_setup(cls):
+ super(BackendsCapabilitiesAdminV2TestsJSON, cls).resource_setup()
+ # Get host list, formation: host@backend-name
+ cls.hosts = [
+ pool['name'] for pool in
+ cls.admin_volume_client.show_pools()['pools']
+ ]
+
+ @test.idempotent_id('3750af44-5ea2-4cd4-bc3e-56e7e6caf854')
+ def test_get_capabilities_backend(self):
+ # Test backend properties
+ backend = self.admin_volume_client.show_backend_capabilities(
+ self.hosts[0])
+
+ # Verify getting capabilities parameters from a backend
+ for key in self.CAPABILITIES:
+ self.assertIn(key, backend)
+
+ @test.idempotent_id('a9035743-d46a-47c5-9cb7-3c80ea16dea0')
+ def test_compare_volume_stats_values(self):
+ # Test values comparison between show_backend_capabilities
+ # to show_pools
+ VOLUME_STATS = ('vendor_name',
+ 'volume_backend_name',
+ 'storage_protocol')
+
+ # Get list backend capabilities using show_pools
+ cinder_pools = [
+ pool['capabilities'] for pool in
+ self.admin_volume_client.show_pools(detail=True)['pools']
+ ]
+
+ # Get list backends capabilities using show_backend_capabilities
+ capabilities = [
+ self.admin_volume_client.show_backend_capabilities(
+ host=host) for host in self.hosts
+ ]
+
+ # Returns a tuple of VOLUME_STATS values
+ expected_list = map(operator.itemgetter(*VOLUME_STATS),
+ cinder_pools)
+ observed_list = map(operator.itemgetter(*VOLUME_STATS),
+ capabilities)
+ self.assertEqual(expected_list, observed_list)
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_snapshots_actions.py b/tempest/api/volume/admin/test_snapshots_actions.py
index a17cc69..1468e90 100644
--- a/tempest/api/volume/admin/test_snapshots_actions.py
+++ b/tempest/api/volume/admin/test_snapshots_actions.py
@@ -15,7 +15,6 @@
from tempest.api.volume import base
from tempest.common.utils import data_utils
-from tempest.common import waiters
from tempest import config
from tempest import test
@@ -42,28 +41,13 @@
vol_name = data_utils.rand_name(cls.__name__ + '-Volume')
cls.name_field = cls.special_fields['name_field']
params = {cls.name_field: vol_name}
- cls.volume = cls.volumes_client.create_volume(**params)['volume']
- waiters.wait_for_volume_status(cls.volumes_client,
- cls.volume['id'], 'available')
+ cls.volume = cls.create_volume(**params)
# Create a test shared snapshot for tests
snap_name = data_utils.rand_name(cls.__name__ + '-Snapshot')
params = {cls.name_field: snap_name}
- cls.snapshot = cls.client.create_snapshot(
- volume_id=cls.volume['id'], **params)['snapshot']
- waiters.wait_for_snapshot_status(cls.client,
- cls.snapshot['id'], 'available')
-
- @classmethod
- def resource_cleanup(cls):
- # Delete the test snapshot
- cls.client.delete_snapshot(cls.snapshot['id'])
- cls.client.wait_for_resource_deletion(cls.snapshot['id'])
-
- # Delete the test volume
- cls.delete_volume(cls.volumes_client, cls.volume['id'])
-
- super(SnapshotsActionsV2Test, cls).resource_cleanup()
+ cls.snapshot = cls.create_snapshot(
+ volume_id=cls.volume['id'], **params)
def tearDown(self):
# Set snapshot's status to available after test
diff --git a/tempest/api/volume/admin/test_volume_quotas_negative.py b/tempest/api/volume/admin/test_volume_quotas_negative.py
index dde8915..c19b1c4 100644
--- a/tempest/api/volume/admin/test_volume_quotas_negative.py
+++ b/tempest/api/volume/admin/test_volume_quotas_negative.py
@@ -32,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
@@ -50,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')
@@ -61,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_services.py b/tempest/api/volume/admin/test_volume_services.py
index 755365d..165874b 100644
--- a/tempest/api/volume/admin/test_volume_services.py
+++ b/tempest/api/volume/admin/test_volume_services.py
@@ -79,7 +79,7 @@
services = (self.admin_volume_services_client.list_services(
host=self.host_name, binary=self.binary_name))['services']
- self.assertEqual(1, len(services))
+ self.assertNotEqual(0, len(services))
self.assertEqual(self.host_name, _get_host(services[0]['host']))
self.assertEqual(self.binary_name, services[0]['binary'])
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 01f96b7..00da5be 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']
@@ -162,6 +163,28 @@
encryption_type['volume_type_id']))
self.assertEmpty(deleted_encryption_type)
+ @test.idempotent_id('cf9f07c6-db9e-4462-a243-5933ad65e9c8')
+ def test_volume_type_update(self):
+ # Create volume type
+ volume_type = self.create_volume_type()
+
+ # New volume type details
+ name = data_utils.rand_name("volume-type")
+ description = data_utils.rand_name("volume-type-description")
+ is_public = not volume_type['is_public']
+
+ # Update volume type details
+ kwargs = {'name': name,
+ 'description': description,
+ 'is_public': is_public}
+ updated_vol_type = self.admin_volume_types_client.update_volume_type(
+ volume_type['id'], **kwargs)['volume_type']
+
+ # Verify volume type details were updated
+ self.assertEqual(name, updated_vol_type['name'])
+ self.assertEqual(description, updated_vol_type['description'])
+ self.assertEqual(is_public, updated_vol_type['is_public'])
+
class VolumeTypesV1Test(VolumeTypesV2Test):
_api_version = 1
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..5a3c71c 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -110,6 +110,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']
diff --git a/tempest/api/volume/test_volume_transfers.py b/tempest/api/volume/test_volume_transfers.py
index d138490..a8889e0 100644
--- a/tempest/api/volume/test_volume_transfers.py
+++ b/tempest/api/volume/test_volume_transfers.py
@@ -17,11 +17,8 @@
from tempest.api.volume import base
from tempest.common import waiters
-from tempest import config
from tempest import test
-CONF = config.CONF
-
class VolumesV2TransfersTest(base.BaseVolumeTest):
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_backup.py b/tempest/api/volume/test_volumes_backup.py
index 8e78a89..50a1360 100755
--- a/tempest/api/volume/test_volumes_backup.py
+++ b/tempest/api/volume/test_volumes_backup.py
@@ -34,21 +34,22 @@
def resource_setup(cls):
super(VolumesBackupsV2Test, cls).resource_setup()
- cls.volume = cls.create_volume()
-
@test.idempotent_id('a66eb488-8ee1-47d4-8e9f-575a095728c6')
def test_volume_backup_create_get_detailed_list_restore_delete(self):
# Create backup
+ volume = self.create_volume()
+ self.addCleanup(self.volumes_client.delete_volume,
+ volume['id'])
backup_name = data_utils.rand_name(
self.__class__.__name__ + '-Backup')
create_backup = self.backups_client.create_backup
- backup = create_backup(volume_id=self.volume['id'],
+ backup = create_backup(volume_id=volume['id'],
name=backup_name)['backup']
self.addCleanup(self.backups_client.delete_backup,
backup['id'])
self.assertEqual(backup_name, backup['name'])
waiters.wait_for_volume_status(self.volumes_client,
- self.volume['id'], 'available')
+ volume['id'], 'available')
self.backups_client.wait_for_backup_status(backup['id'],
'available')
@@ -84,24 +85,27 @@
is "available" or "in-use".
"""
# Create a server
+ volume = self.create_volume()
+ self.addCleanup(self.volumes_client.delete_volume,
+ volume['id'])
server_name = data_utils.rand_name(
self.__class__.__name__ + '-instance')
server = self.create_server(name=server_name, wait_until='ACTIVE')
self.addCleanup(self.servers_client.delete_server, server['id'])
# Attach volume to instance
self.servers_client.attach_volume(server['id'],
- volumeId=self.volume['id'])
+ volumeId=volume['id'])
waiters.wait_for_volume_status(self.volumes_client,
- self.volume['id'], 'in-use')
+ volume['id'], 'in-use')
self.addCleanup(waiters.wait_for_volume_status, self.volumes_client,
- self.volume['id'], 'available')
+ volume['id'], 'available')
self.addCleanup(self.servers_client.detach_volume, server['id'],
- self.volume['id'])
+ volume['id'])
# Create backup using force flag
backup_name = data_utils.rand_name(
self.__class__.__name__ + '-Backup')
backup = self.backups_client.create_backup(
- volume_id=self.volume['id'],
+ volume_id=volume['id'],
name=backup_name, force=True)['backup']
self.addCleanup(self.backups_client.delete_backup, backup['id'])
self.backups_client.wait_for_backup_status(backup['id'],
diff --git a/tempest/api/volume/test_volumes_clone.py b/tempest/api/volume/test_volumes_clone.py
index f38a068..7529dc2 100644
--- a/tempest/api/volume/test_volumes_clone.py
+++ b/tempest/api/volume/test_volumes_clone.py
@@ -23,6 +23,12 @@
class VolumesCloneTest(base.BaseVolumeTest):
+ @classmethod
+ def skip_checks(cls):
+ super(VolumesCloneTest, cls).skip_checks()
+ if not CONF.volume_feature_enabled.clone:
+ raise cls.skipException("Cinder volume clones are disabled")
+
@test.idempotent_id('9adae371-a257-43a5-9555-dc7c88e66e0e')
def test_create_from_volume(self):
# Creates a volume from another volume passing a size different from
diff --git a/tempest/api/volume/test_volumes_clone_negative.py b/tempest/api/volume/test_volumes_clone_negative.py
index ee51e00..d1bedb4 100644
--- a/tempest/api/volume/test_volumes_clone_negative.py
+++ b/tempest/api/volume/test_volumes_clone_negative.py
@@ -24,6 +24,12 @@
class VolumesCloneTest(base.BaseVolumeTest):
+ @classmethod
+ def skip_checks(cls):
+ super(VolumesCloneTest, cls).skip_checks()
+ if not CONF.volume_feature_enabled.clone:
+ raise cls.skipException("Cinder volume clones are disabled")
+
@test.idempotent_id('9adae371-a257-43a5-459a-dc7c88e66e0e')
def test_create_from_volume_decreasing_size(self):
# Creates a volume from another volume passing a size different from
diff --git a/tempest/api/volume/test_volumes_extend.py b/tempest/api/volume/test_volumes_extend.py
index 1947779..7aea1c4 100644
--- a/tempest/api/volume/test_volumes_extend.py
+++ b/tempest/api/volume/test_volumes_extend.py
@@ -15,11 +15,8 @@
from tempest.api.volume import base
from tempest.common import waiters
-from tempest import config
from tempest import test
-CONF = config.CONF
-
class VolumesV2ExtendTest(base.BaseVolumeTest):
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/v2/test_volumes_list.py b/tempest/api/volume/v2/test_volumes_list.py
index c501ffc..60a35b0 100644
--- a/tempest/api/volume/v2/test_volumes_list.py
+++ b/tempest/api/volume/v2/test_volumes_list.py
@@ -42,11 +42,13 @@
super(VolumesV2ListTestJSON, cls).resource_setup()
# Create 3 test volumes
- cls.volume_id_list = []
cls.metadata = {'Type': 'work'}
+ # NOTE(zhufl): When using pre-provisioned credentials, the project
+ # may have volumes other than those created below.
+ existing_volumes = cls.client.list_volumes()['volumes']
+ cls.volume_id_list = [vol['id'] for vol in existing_volumes]
for i in range(3):
volume = cls.create_volume(metadata=cls.metadata)
- volume = cls.client.show_volume(volume['id'])['volume']
cls.volume_id_list.append(volume['id'])
@test.idempotent_id('2a7064eb-b9c3-429b-b888-33928fc5edd3')
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..5406d73 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -297,12 +297,10 @@
**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/cmd/init.py b/tempest/cmd/init.py
index bf7289a..eeca063 100644
--- a/tempest/cmd/init.py
+++ b/tempest/cmd/init.py
@@ -22,7 +22,7 @@
from oslo_log import log as logging
from six import moves
-from tempest.cmd.workspace import WorkspaceManager
+from tempest.cmd import workspace
LOG = logging.getLogger(__name__)
@@ -167,7 +167,8 @@
subprocess.call(['testr', 'init'], cwd=local_dir)
def take_action(self, parsed_args):
- workspace_manager = WorkspaceManager(parsed_args.workspace_path)
+ workspace_manager = workspace.WorkspaceManager(
+ parsed_args.workspace_path)
name = parsed_args.name or parsed_args.dir.split(os.path.sep)[-1]
workspace_manager.register_new_workspace(
name, parsed_args.dir, init=True)
diff --git a/tempest/cmd/list_plugins.py b/tempest/cmd/list_plugins.py
index 36e45a5..86732da 100644
--- a/tempest/cmd/list_plugins.py
+++ b/tempest/cmd/list_plugins.py
@@ -21,7 +21,7 @@
from cliff import command
import prettytable
-from tempest.test_discover.plugins import TempestTestPluginManager
+from tempest.test_discover import plugins as plg
class TempestListPlugins(command.Command):
@@ -32,7 +32,7 @@
return 'List all tempest plugins'
def _list_plugins(self):
- plugins = TempestTestPluginManager()
+ plugins = plg.TempestTestPluginManager()
output = prettytable.PrettyTable(["Name", "EntryPoint"])
for plugin in plugins.ext_plugins.extensions:
diff --git a/tempest/cmd/run.py b/tempest/cmd/run.py
index 1c0d9c4..fef836c 100644
--- a/tempest/cmd/run.py
+++ b/tempest/cmd/run.py
@@ -23,7 +23,7 @@
any tests that match on re.match() with the regex
* **--smoke**: Run all the tests tagged as smoke
-There are also the **--blacklist_file** and **--whitelist_file** options that
+There are also the **--blacklist-file** and **--whitelist-file** options that
let you pass a filepath to tempest run with the file format being a line
separated regex, with '#' used to signify the start of a comment on a line.
For example::
@@ -191,11 +191,11 @@
help='A normal testr selection regex used to '
'specify a subset of tests to run')
list_selector = parser.add_mutually_exclusive_group()
- list_selector.add_argument('--whitelist_file',
+ list_selector.add_argument('--whitelist-file', '--whitelist_file',
help="Path to a whitelist file, this file "
"contains a separate regex on each "
"newline.")
- list_selector.add_argument('--blacklist_file',
+ list_selector.add_argument('--blacklist-file', '--blacklist_file',
help='Path to a blacklist file, this file '
'contains a separate regex exclude on '
'each newline')
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/dynamic_creds.py b/tempest/common/dynamic_creds.py
index c9b9db1..04c9645 100644
--- a/tempest/common/dynamic_creds.py
+++ b/tempest/common/dynamic_creds.py
@@ -401,9 +401,18 @@
except lib_exc.NotFound:
LOG.warning("user with name: %s not found for delete" %
creds.username)
+ # NOTE(zhufl): Only when neutron's security_group ext is
+ # enabled, _cleanup_default_secgroup will not raise error. But
+ # here cannot use test.is_extension_enabled for it will cause
+ # "circular dependency". So here just use try...except to
+ # ensure tenant deletion without big changes.
try:
if CONF.service_available.neutron:
self._cleanup_default_secgroup(creds.tenant_id)
+ except lib_exc.NotFound:
+ LOG.warning("failed to cleanup tenant %s's secgroup" %
+ creds.tenant_name)
+ try:
self.creds_client.delete_project(creds.tenant_id)
except lib_exc.NotFound:
LOG.warning("tenant with name: %s not found for delete" %
diff --git a/tempest/common/utils/net_utils.py b/tempest/common/utils/net_utils.py
index fd0391d..f0d3da3 100644
--- a/tempest/common/utils/net_utils.py
+++ b/tempest/common/utils/net_utils.py
@@ -37,6 +37,11 @@
for fixed_ip in port.get('fixed_ips'):
alloc_set.add(fixed_ip['ip_address'])
+ # exclude gateway_ip of subnet
+ gateway_ip = subnet['subnet']['gateway_ip']
+ if gateway_ip:
+ alloc_set.add(gateway_ip)
+
av_set = subnet_set - alloc_set
addrs = []
for cidr in reversed(av_set.iter_cidrs()):
diff --git a/tempest/lib/auth.py b/tempest/lib/auth.py
index 1857a43..83aa405 100644
--- a/tempest/lib/auth.py
+++ b/tempest/lib/auth.py
@@ -689,6 +689,10 @@
"""Credentials are equal if attributes in self.ATTRIBUTES are equal"""
return str(self) == str(other)
+ def __ne__(self, other):
+ """Contrary to the __eq__"""
+ return not self.__eq__(other)
+
def __getattr__(self, key):
# If an attribute is set, __getattr__ is not invoked
# If an attribute is not set, and it is a known one, return None
diff --git a/tempest/lib/base.py b/tempest/lib/base.py
index f687343..33a32ee 100644
--- a/tempest/lib/base.py
+++ b/tempest/lib/base.py
@@ -42,7 +42,7 @@
def setUp(self):
super(BaseTestCase, self).setUp()
if not self.setUpClassCalled:
- raise RuntimeError("setUpClass does not calls the super's"
+ raise RuntimeError("setUpClass does not calls the super's "
"setUpClass in the "
+ self.__class__.__name__)
test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0)
diff --git a/tempest/lib/common/rest_client.py b/tempest/lib/common/rest_client.py
index 4e851b0..8507f8a 100644
--- a/tempest/lib/common/rest_client.py
+++ b/tempest/lib/common/rest_client.py
@@ -105,6 +105,9 @@
timeout=http_timeout)
def _get_type(self):
+ if self.TYPE != "json":
+ self.LOG.warning("Tempest has dropped XML support and the TYPE "
+ "became meaningless")
return self.TYPE
def get_headers(self, accept_type=None, send_type=None):
@@ -232,8 +235,8 @@
raise TypeError("'read_code' must be an int instead of (%s)"
% type(read_code))
- assert_msg = ("This function only allowed to use for HTTP status"
- "codes which explicitly defined in the RFC 7231 & 4918."
+ assert_msg = ("This function only allowed to use for HTTP status "
+ "codes which explicitly defined in the RFC 7231 & 4918. "
"{0} is not a defined Success Code!"
).format(expected_code)
if isinstance(expected_code, list):
@@ -400,19 +403,14 @@
else:
return text
- def _log_request_start(self, method, req_url, req_headers=None,
- req_body=None):
- if req_headers is None:
- req_headers = {}
+ def _log_request_start(self, method, req_url):
caller_name = test_utils.find_test_caller()
if self.trace_requests and re.search(self.trace_requests, caller_name):
self.LOG.debug('Starting Request (%s): %s %s' %
(caller_name, method, req_url))
- def _log_request_full(self, method, req_url, resp,
- secs="", req_headers=None,
- req_body=None, resp_body=None,
- caller_name=None, extra=None):
+ def _log_request_full(self, resp, req_headers=None, req_body=None,
+ resp_body=None, extra=None):
if 'X-Auth-Token' in req_headers:
req_headers['X-Auth-Token'] = '<omitted>'
# A shallow copy is sufficient
@@ -458,8 +456,8 @@
# Also look everything at DEBUG if you want to filter this
# out, don't run at debug.
if self.LOG.isEnabledFor(real_logging.DEBUG):
- self._log_request_full(method, req_url, resp, secs, req_headers,
- req_body, resp_body, caller_name, extra)
+ self._log_request_full(resp, req_headers, req_body,
+ resp_body, extra)
def _parse_resp(self, body):
try:
@@ -895,11 +893,11 @@
cls=JSONSCHEMA_VALIDATOR,
format_checker=FORMAT_CHECKER)
except jsonschema.ValidationError as ex:
- msg = ("HTTP response body is invalid (%s)") % ex
+ msg = ("HTTP response body is invalid (%s)" % ex)
raise exceptions.InvalidHTTPResponseBody(msg)
else:
if body:
- msg = ("HTTP response body should not exist (%s)") % body
+ msg = ("HTTP response body should not exist (%s)" % body)
raise exceptions.InvalidHTTPResponseBody(msg)
# Check the header of a response
@@ -910,7 +908,7 @@
cls=JSONSCHEMA_VALIDATOR,
format_checker=FORMAT_CHECKER)
except jsonschema.ValidationError as ex:
- msg = ("HTTP response header is invalid (%s)") % ex
+ msg = ("HTTP response header is invalid (%s)" % ex)
raise exceptions.InvalidHTTPResponseHeader(msg)
diff --git a/tempest/lib/common/ssh.py b/tempest/lib/common/ssh.py
index a831dbd..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"
@@ -121,7 +121,6 @@
channel.fileno() # Register event pipe
channel.exec_command(cmd)
channel.shutdown_write()
- exit_status = channel.recv_exit_status()
# If the executing host is linux-based, poll the channel
if self._can_system_poll():
@@ -162,6 +161,8 @@
out_data = out_data.decode(encoding)
err_data = err_data.decode(encoding)
+ exit_status = channel.recv_exit_status()
+
if 0 != exit_status:
raise exceptions.SSHExecCommandFailed(
command=cmd, exit_status=exit_status,
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/lib/exceptions.py b/tempest/lib/exceptions.py
index de2d713..e3f25e6 100644
--- a/tempest/lib/exceptions.py
+++ b/tempest/lib/exceptions.py
@@ -100,7 +100,7 @@
class OverLimit(ClientRestClientException):
- message = "Quota exceeded"
+ message = "Request entity is too large"
class ServerFault(ServerRestClientException):
diff --git a/tempest/lib/services/compute/images_client.py b/tempest/lib/services/compute/images_client.py
index da8a61e..3dc3749 100644
--- a/tempest/lib/services/compute/images_client.py
+++ b/tempest/lib/services/compute/images_client.py
@@ -61,7 +61,6 @@
def show_image(self, image_id):
"""Return the details of a single image."""
resp, body = self.get("images/%s" % image_id)
- self.expected_success(200, resp.status)
body = json.loads(body)
self.validate_response(schema.get_image, resp, body)
return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/identity/v2/roles_client.py b/tempest/lib/services/identity/v2/roles_client.py
index 15c8834..aaa75f1 100644
--- a/tempest/lib/services/identity/v2/roles_client.py
+++ b/tempest/lib/services/identity/v2/roles_client.py
@@ -66,7 +66,7 @@
Available params: see http://developer.openstack.org/
api-ref-identity-v2-ext.html#deleteRole
"""
- resp, body = self.delete('OS-KSADM/roles/%s' % str(role_id))
+ resp, body = self.delete('OS-KSADM/roles/%s' % role_id)
self.expected_success(204, resp.status)
return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/identity/v3/json/projects_client.py b/tempest/lib/services/identity/v3/projects_client.py
similarity index 97%
rename from tempest/services/identity/v3/json/projects_client.py
rename to tempest/lib/services/identity/v3/projects_client.py
index 97e43df..ce2f38d 100644
--- a/tempest/services/identity/v3/json/projects_client.py
+++ b/tempest/lib/services/identity/v3/projects_client.py
@@ -68,6 +68,6 @@
def delete_project(self, project_id):
"""Delete a project."""
- resp, body = self.delete('projects/%s' % str(project_id))
+ resp, body = self.delete('projects/%s' % project_id)
self.expected_success(204, resp.status)
return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/identity/v3/json/regions_client.py b/tempest/lib/services/identity/v3/regions_client.py
similarity index 100%
rename from tempest/services/identity/v3/json/regions_client.py
rename to tempest/lib/services/identity/v3/regions_client.py
diff --git a/tempest/services/identity/v3/json/services_client.py b/tempest/lib/services/identity/v3/services_client.py
similarity index 100%
rename from tempest/services/identity/v3/json/services_client.py
rename to tempest/lib/services/identity/v3/services_client.py
diff --git a/tempest/lib/services/image/v2/resource_types_client.py b/tempest/lib/services/image/v2/resource_types_client.py
index 1349c63..8f2a977 100644
--- a/tempest/lib/services/image/v2/resource_types_client.py
+++ b/tempest/lib/services/image/v2/resource_types_client.py
@@ -22,8 +22,54 @@
api_version = "v2"
def list_resource_types(self):
+ """Lists all resource types.
+
+ Available params: see http://developer.openstack.org/
+ api-ref/image/v2/metadefs-index.html?expanded=#
+ list-resource-types
+ """
url = 'metadefs/resource_types'
resp, body = self.get(url)
self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
+
+ def create_resource_type_association(self, namespace_id, **kwargs):
+ """Creates a resource type association in given namespace.
+
+ Available params: see http://developer.openstack.org/
+ api-ref/image/v2/metadefs-index.html?expanded=#
+ create-resource-type-association
+ """
+ url = 'metadefs/namespaces/%s/resource_types' % namespace_id
+ data = json.dumps(kwargs)
+ resp, body = self.post(url, data)
+ self.expected_success(201, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def list_resource_type_association(self, namespace_id):
+ """Lists resource type associations in given namespace.
+
+ Available params: see http://developer.openstack.org/
+ api-ref/image/v2/metadefs-index.html?expanded=#
+ list-resource-type-associations
+ """
+ url = 'metadefs/namespaces/%s/resource_types' % namespace_id
+ resp, body = self.get(url)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def delete_resource_type_association(self, namespace_id, resource_name):
+ """Removes resource type association in given namespace.
+
+ Available params: see http://developer.openstack.org/
+ api-ref/image/v2/metadefs-index.html?expanded=#
+ remove-resource-type-association
+ """
+ url = 'metadefs/namespaces/%s/resource_types/%s' % (namespace_id,
+ resource_name)
+ resp, _ = self.delete(url)
+ self.expected_success(204, resp.status)
+ return rest_client.ResponseBody(resp)
diff --git a/tempest/lib/services/network/agents_client.py b/tempest/lib/services/network/agents_client.py
index c5d4c66..9bdf090 100644
--- a/tempest/lib/services/network/agents_client.py
+++ b/tempest/lib/services/network/agents_client.py
@@ -44,7 +44,7 @@
# link to api-site.
# LP: https://bugs.launchpad.net/openstack-api-site/+bug/1526670
uri = '/agents/%s/l3-routers' % agent_id
- return self.create_resource(uri, kwargs)
+ return self.create_resource(uri, kwargs, expect_empty_body=True)
def delete_router_from_l3_agent(self, agent_id, router_id):
uri = '/agents/%s/l3-routers/%s' % (agent_id, router_id)
@@ -65,4 +65,4 @@
# link to api-site.
# LP: https://bugs.launchpad.net/openstack-api-site/+bug/1526212
uri = '/agents/%s/dhcp-networks' % agent_id
- return self.create_resource(uri, kwargs)
+ return self.create_resource(uri, kwargs, expect_empty_body=True)
diff --git a/tempest/lib/services/network/base.py b/tempest/lib/services/network/base.py
index 620e0f1..b6f9c91 100644
--- a/tempest/lib/services/network/base.py
+++ b/tempest/lib/services/network/base.py
@@ -63,6 +63,8 @@
# body. Otherwise we returns the body as it is.
if not expect_empty_body:
body = json.loads(body)
+ else:
+ body = None
self.expected_success(201, resp.status)
return rest_client.ResponseBody(resp, body)
@@ -75,5 +77,7 @@
# body. Otherwise we returns the body as it is.
if not expect_empty_body:
body = json.loads(body)
+ else:
+ body = None
self.expected_success(200, resp.status)
return rest_client.ResponseBody(resp, body)
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 62ab67d..a3f832a 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -87,45 +87,10 @@
cls.volumes_client = cls.manager.volumes_v2_client
cls.snapshots_client = cls.manager.snapshots_v2_client
- # ## Methods to handle sync and async deletes
-
- def setUp(self):
- super(ScenarioTest, self).setUp()
- self.cleanup_waits = []
- # NOTE(mtreinish) This is safe to do in setUp instead of setUp class
- # because scenario tests in the same test class should not share
- # resources. If resources were shared between test cases then it
- # should be a single scenario test instead of multiples.
-
- # NOTE(yfried): this list is cleaned at the end of test_methods and
- # not at the end of the class
- self.addCleanup(self._wait_for_cleanups)
-
- def addCleanup_with_wait(self, waiter_callable, thing_id, thing_id_param,
- cleanup_callable, cleanup_args=None,
- cleanup_kwargs=None, waiter_client=None):
- """Adds wait for async resource deletion at the end of cleanups
-
- @param waiter_callable: callable to wait for the resource to delete
- with the following waiter_client if specified.
- @param thing_id: the id of the resource to be cleaned-up
- @param thing_id_param: the name of the id param in the waiter
- @param cleanup_callable: method to load pass to self.addCleanup with
- the following *cleanup_args, **cleanup_kwargs.
- usually a delete method.
- """
- if cleanup_args is None:
- cleanup_args = []
- if cleanup_kwargs is None:
- cleanup_kwargs = {}
- self.addCleanup(cleanup_callable, *cleanup_args, **cleanup_kwargs)
- wait_dict = {
- 'waiter_callable': waiter_callable,
- thing_id_param: thing_id
- }
- if waiter_client:
- wait_dict['client'] = waiter_client
- self.cleanup_waits.append(wait_dict)
+ # ## Test functions library
+ #
+ # The create_[resource] functions only return body and discard the
+ # resp part which is not used in scenario tests
def _create_port(self, network_id, client=None, namestart='port-quotatest',
**kwargs):
@@ -142,23 +107,6 @@
client.delete_port, port['id'])
return port
- def _wait_for_cleanups(self):
- # To handle async delete actions, a list of waits is added
- # which will be iterated over as the last step of clearing the
- # cleanup queue. That way all the delete calls are made up front
- # and the tests won't succeed unless the deletes are eventually
- # successful. This is the same basic approach used in the api tests to
- # limit cleanup execution time except here it is multi-resource,
- # because of the nature of the scenario tests.
- for wait in self.cleanup_waits:
- waiter_callable = wait.pop('waiter_callable')
- waiter_callable(**wait)
-
- # ## Test functions library
- #
- # The create_[resource] functions only return body and discard the
- # resp part which is not used in scenario tests
-
def create_keypair(self, client=None):
if not client:
client = self.keypairs_client
@@ -170,7 +118,7 @@
def create_server(self, name=None, image_id=None, flavor=None,
validatable=False, wait_until=None,
- wait_on_delete=True, clients=None, **kwargs):
+ clients=None, **kwargs):
"""Wrapper utility that returns a test server.
This wrapper utility calls the common create test server and
@@ -256,31 +204,24 @@
name=name, flavor=flavor,
image_id=image_id, **kwargs)
- # TODO(jlanoux) Move wait_on_delete in compute.py
- if wait_on_delete:
- self.addCleanup(waiters.wait_for_server_termination,
- clients.servers_client,
- body['id'])
-
- self.addCleanup_with_wait(
- waiter_callable=waiters.wait_for_server_termination,
- thing_id=body['id'], thing_id_param='server_id',
- cleanup_callable=test_utils.call_and_ignore_notfound_exc,
- cleanup_args=[clients.servers_client.delete_server, body['id']],
- waiter_client=clients.servers_client)
+ self.addCleanup(waiters.wait_for_server_termination,
+ clients.servers_client, body['id'])
+ self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+ clients.servers_client.delete_server, body['id'])
server = clients.servers_client.show_server(body['id'])['server']
return server
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,
@@ -481,11 +422,12 @@
image = _images_client.create_image(server['id'], name=name)
image_id = image.response['location'].split('images/')[1]
waiters.wait_for_image_status(_image_client, image_id, 'active')
- self.addCleanup_with_wait(
- waiter_callable=_image_client.wait_for_resource_deletion,
- thing_id=image_id, thing_id_param='id',
- cleanup_callable=test_utils.call_and_ignore_notfound_exc,
- cleanup_args=[_image_client.delete_image, image_id])
+
+ self.addCleanup(_image_client.wait_for_resource_deletion,
+ image_id)
+ self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+ _image_client.delete_image, image_id)
+
if CONF.image_feature_enabled.api_v1:
# In glance v1 the additional properties are stored in the headers.
resp = _image_client.check_image(image_id)
@@ -572,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,
@@ -916,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'],
@@ -973,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,
@@ -1308,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))
@@ -1332,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)
diff --git a/tempest/scenario/test_baremetal_basic_ops.py b/tempest/scenario/test_baremetal_basic_ops.py
index 655d19d..45c38f6 100644
--- a/tempest/scenario/test_baremetal_basic_ops.py
+++ b/tempest/scenario/test_baremetal_basic_ops.py
@@ -15,17 +15,14 @@
from oslo_log import log as logging
-from tempest import config
from tempest.scenario import manager
from tempest import test
-CONF = config.CONF
-
LOG = logging.getLogger(__name__)
class BaremetalBasicOps(manager.BaremetalScenarioTest):
- """This smoke test tests the pxe_ssh Ironic driver.
+ """This test tests the pxe_ssh Ironic driver.
It follows this basic set of operations:
* Creates a keypair
diff --git a/tempest/scenario/test_encrypted_cinder_volumes.py b/tempest/scenario/test_encrypted_cinder_volumes.py
index dcd77ad..1659ebe 100644
--- a/tempest/scenario/test_encrypted_cinder_volumes.py
+++ b/tempest/scenario/test_encrypted_cinder_volumes.py
@@ -53,7 +53,7 @@
volume_type = self.create_volume_type(name=volume_type)
self.create_encryption_type(type_id=volume_type['id'],
provider=encryption_provider,
- key_size=512,
+ key_size=256,
cipher='aes-xts-plain64',
control_location='front-end')
return self.create_volume(volume_type=volume_type['name'])
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_advanced_server_ops.py b/tempest/scenario/test_network_advanced_server_ops.py
index e4b699e..a89147a 100644
--- a/tempest/scenario/test_network_advanced_server_ops.py
+++ b/tempest/scenario/test_network_advanced_server_ops.py
@@ -58,7 +58,7 @@
security_groups = [{'name': security_group['name']}]
network, subnet, router = self.create_networks()
public_network_id = CONF.network.public_network_id
- server_name = data_utils.rand_name('server-smoke')
+ server_name = data_utils.rand_name('server')
server = self.create_server(
name=server_name,
networks=[{'uuid': network['id']}],
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_object_storage_basic_ops.py b/tempest/scenario/test_object_storage_basic_ops.py
index 63ffa0b..9ac1e30 100644
--- a/tempest/scenario/test_object_storage_basic_ops.py
+++ b/tempest/scenario/test_object_storage_basic_ops.py
@@ -13,12 +13,9 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest import config
from tempest.scenario import manager
from tempest import test
-CONF = config.CONF
-
class TestObjectStorageBasicOps(manager.ObjectStorageScenarioTest):
"""Test swift basic ops.
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/v3/__init__.py b/tempest/services/identity/v3/__init__.py
index 6ad8ef2..c77c78d 100644
--- a/tempest/services/identity/v3/__init__.py
+++ b/tempest/services/identity/v3/__init__.py
@@ -14,20 +14,20 @@
from tempest.lib.services.identity.v3.endpoints_client import EndPointsClient
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.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.regions_client import RegionsClient
from tempest.services.identity.v3.json.roles_client import RolesClient
-from tempest.services.identity.v3.json.services_client import ServicesClient
from tempest.services.identity.v3.json.trusts_client import TrustsClient
from tempest.services.identity.v3.json.users_clients import UsersClient
-__all__ = ['EndPointsClient', 'PoliciesClient', 'V3TokenClient',
+__all__ = ['EndPointsClient', 'PoliciesClient', 'ProjectsClient',
+ 'RegionsClient', 'ServicesClient', 'V3TokenClient',
'CredentialsClient', 'DomainsClient', 'GroupsClient',
- 'IdentityClient', 'ProjectsClient', 'RegionsClient', 'RolesClient',
- 'ServicesClient', 'TrustsClient', 'UsersClient', ]
+ 'IdentityClient', 'RolesClient', 'TrustsClient', 'UsersClient', ]
diff --git a/tempest/services/identity/v3/json/credentials_client.py b/tempest/services/identity/v3/json/credentials_client.py
index 6ab94d0..55eeee4 100644
--- a/tempest/services/identity/v3/json/credentials_client.py
+++ b/tempest/services/identity/v3/json/credentials_client.py
@@ -14,10 +14,11 @@
# under the License.
"""
-http://developer.openstack.org/api-ref-identity-v3.html#credentials-v3
+http://developer.openstack.org/api-ref-identity-v3.html#credentials
"""
from oslo_serialization import jsonutils as json
+from six.moves.urllib import parse as urllib
from tempest.lib.common import rest_client
@@ -29,7 +30,7 @@
"""Creates a credential.
Available params: see http://developer.openstack.org/
- api-ref-identity-v3.html#createCredential
+ api-ref-identity-v3.html#create-credential
"""
post_body = json.dumps({'credential': kwargs})
resp, body = self.post('credentials', post_body)
@@ -42,7 +43,7 @@
"""Updates a credential.
Available params: see http://developer.openstack.org/
- api-ref-identity-v3.html#updateCredential
+ api-ref-identity-v3.html#update-credential
"""
post_body = json.dumps({'credential': kwargs})
resp, body = self.patch('credentials/%s' % credential_id, post_body)
@@ -52,22 +53,37 @@
return rest_client.ResponseBody(resp, body)
def show_credential(self, credential_id):
- """To GET Details of a credential."""
+ """To GET Details of a credential.
+
+ For API details, see http://developer.openstack.org/
+ api-ref-identity-v3.html#show-credential-details
+ """
resp, body = self.get('credentials/%s' % credential_id)
self.expected_success(200, resp.status)
body = json.loads(body)
body['credential']['blob'] = json.loads(body['credential']['blob'])
return rest_client.ResponseBody(resp, body)
- def list_credentials(self):
- """Lists out all the available credentials."""
- resp, body = self.get('credentials')
+ def list_credentials(self, **params):
+ """Lists out all the available credentials.
+
+ Available params: see http://developer.openstack.org/
+ api-ref/identity/v3/#list-credentials
+ """
+ url = 'credentials'
+ 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)
def delete_credential(self, credential_id):
- """Deletes a credential."""
+ """Deletes a credential.
+
+ For API details, see http://developer.openstack.org/
+ api-ref/identity/v3/#delete-credential
+ """
resp, body = self.delete('credentials/%s' % credential_id)
self.expected_success(204, resp.status)
return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/identity/v3/json/domains_client.py b/tempest/services/identity/v3/json/domains_client.py
index d129a0a..fe929a5 100644
--- a/tempest/services/identity/v3/json/domains_client.py
+++ b/tempest/services/identity/v3/json/domains_client.py
@@ -38,7 +38,7 @@
def delete_domain(self, domain_id):
"""Deletes a domain."""
- resp, body = self.delete('domains/%s' % str(domain_id))
+ resp, body = self.delete('domains/%s' % domain_id)
self.expected_success(204, resp.status)
return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/identity/v3/json/groups_client.py b/tempest/services/identity/v3/json/groups_client.py
index 628b3e1..3674496 100644
--- a/tempest/services/identity/v3/json/groups_client.py
+++ b/tempest/services/identity/v3/json/groups_client.py
@@ -73,7 +73,7 @@
def delete_group(self, group_id):
"""Delete a group."""
- resp, body = self.delete('groups/%s' % str(group_id))
+ resp, body = self.delete('groups/%s' % group_id)
self.expected_success(204, resp.status)
return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/identity/v3/json/roles_client.py b/tempest/services/identity/v3/json/roles_client.py
index bdb0490..aab203f 100644
--- a/tempest/services/identity/v3/json/roles_client.py
+++ b/tempest/services/identity/v3/json/roles_client.py
@@ -34,7 +34,7 @@
def show_role(self, role_id):
"""GET a Role."""
- resp, body = self.get('roles/%s' % str(role_id))
+ resp, body = self.get('roles/%s' % role_id)
self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
@@ -53,14 +53,14 @@
api-ref-identity-v3.html#updateRole
"""
post_body = json.dumps({'role': kwargs})
- resp, body = self.patch('roles/%s' % str(role_id), post_body)
+ resp, body = self.patch('roles/%s' % role_id, post_body)
self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
def delete_role(self, role_id):
"""Delete a role."""
- resp, body = self.delete('roles/%s' % str(role_id))
+ resp, body = self.delete('roles/%s' % role_id)
self.expected_success(204, resp.status)
return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/object_storage/object_client.py b/tempest/services/object_storage/object_client.py
index 0988373..a7db30e 100644
--- a/tempest/services/object_storage/object_client.py
+++ b/tempest/services/object_storage/object_client.py
@@ -42,12 +42,6 @@
self.expected_success(201, resp.status)
return resp, body
- def update_object(self, container, object_name, data):
- """Upload data to replace current storage object."""
- resp, body = self.create_object(container, object_name, data)
- self.expected_success(201, resp.status)
- return resp, body
-
def delete_object(self, container, object_name, params=None):
"""Delete storage object."""
url = "%s/%s" % (str(container), str(object_name))
diff --git a/tempest/services/volume/base/admin/base_types_client.py b/tempest/services/volume/base/admin/base_types_client.py
index 0b0e061..83870ae 100755
--- a/tempest/services/volume/base/admin/base_types_client.py
+++ b/tempest/services/volume/base/admin/base_types_client.py
@@ -140,6 +140,18 @@
self.expected_success(202, resp.status)
return rest_client.ResponseBody(resp, body)
+ def update_volume_type(self, volume_type_id, **kwargs):
+ """Updates volume type name, description, and/or is_public.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-blockstorage-v2.html#updateVolumeType
+ """
+ put_body = json.dumps({'volume_type': kwargs})
+ resp, body = self.put('types/%s' % volume_type_id, put_body)
+ body = json.loads(body)
+ self.expected_success(200, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
def update_volume_type_extra_specs(self, volume_type_id, extra_spec_name,
extra_specs):
"""Update a volume_type extra spec.
@@ -190,42 +202,3 @@
"/types/%s/encryption/provider" % volume_type_id)
self.expected_success(202, resp.status)
return rest_client.ResponseBody(resp, body)
-
- def add_type_access(self, volume_type_id, **kwargs):
- """Adds volume type access for the given project.
-
- Available params: see http://developer.openstack.org/
- api-ref-blockstorage-v2.html
- #createVolumeTypeAccessExt
- """
- post_body = json.dumps({'addProjectAccess': kwargs})
- url = 'types/%s/action' % volume_type_id
- resp, body = self.post(url, post_body)
- self.expected_success(202, resp.status)
- return rest_client.ResponseBody(resp, body)
-
- def remove_type_access(self, volume_type_id, **kwargs):
- """Removes volume type access for the given project.
-
- Available params: see http://developer.openstack.org/
- api-ref-blockstorage-v2.html
- #removeVolumeTypeAccessExt
- """
- post_body = json.dumps({'removeProjectAccess': kwargs})
- url = 'types/%s/action' % volume_type_id
- resp, body = self.post(url, post_body)
- self.expected_success(202, resp.status)
- return rest_client.ResponseBody(resp, body)
-
- def list_type_access(self, volume_type_id):
- """Print access information about the given volume type.
-
- Available params: see http://developer.openstack.org/
- api-ref-blockstorage-v2.html#
- listVolumeTypeAccessExt
- """
- url = 'types/%s/os-volume-type-access' % volume_type_id
- resp, body = self.get(url)
- body = json.loads(body)
- self.expected_success(200, resp.status)
- return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/volume/base/base_backups_client.py b/tempest/services/volume/base/base_backups_client.py
index fc247a9..a57e628 100644
--- a/tempest/services/volume/base/base_backups_client.py
+++ b/tempest/services/volume/base/base_backups_client.py
@@ -51,13 +51,13 @@
def delete_backup(self, backup_id):
"""Delete a backup of volume."""
- resp, body = self.delete('backups/%s' % (str(backup_id)))
+ resp, body = self.delete('backups/%s' % backup_id)
self.expected_success(202, resp.status)
return rest_client.ResponseBody(resp, body)
def show_backup(self, backup_id):
"""Returns the details of a single backup."""
- url = "backups/%s" % str(backup_id)
+ url = "backups/%s" % backup_id
resp, body = self.get(url)
body = json.loads(body)
self.expected_success(200, resp.status)
diff --git a/tempest/services/volume/base/base_qos_client.py b/tempest/services/volume/base/base_qos_client.py
index 2d9f02a..e00ac68 100644
--- a/tempest/services/volume/base/base_qos_client.py
+++ b/tempest/services/volume/base/base_qos_client.py
@@ -82,7 +82,7 @@
def delete_qos(self, qos_id, force=False):
"""Delete the specified QoS specification."""
resp, body = self.delete(
- "qos-specs/%s?force=%s" % (str(qos_id), force))
+ "qos-specs/%s?force=%s" % (qos_id, force))
self.expected_success(202, resp.status)
return rest_client.ResponseBody(resp, body)
@@ -96,7 +96,7 @@
def show_qos(self, qos_id):
"""Get the specified QoS specification."""
- url = "qos-specs/%s" % str(qos_id)
+ url = "qos-specs/%s" % qos_id
resp, body = self.get(url)
body = json.loads(body)
self.expected_success(200, resp.status)
@@ -128,7 +128,7 @@
def associate_qos(self, qos_id, vol_type_id):
"""Associate the specified QoS with specified volume-type."""
- url = "qos-specs/%s/associate" % str(qos_id)
+ url = "qos-specs/%s/associate" % qos_id
url += "?vol_type_id=%s" % vol_type_id
resp, body = self.get(url)
self.expected_success(202, resp.status)
@@ -136,7 +136,7 @@
def show_association_qos(self, qos_id):
"""Get the association of the specified QoS specification."""
- url = "qos-specs/%s/associations" % str(qos_id)
+ url = "qos-specs/%s/associations" % qos_id
resp, body = self.get(url)
body = json.loads(body)
self.expected_success(200, resp.status)
@@ -144,7 +144,7 @@
def disassociate_qos(self, qos_id, vol_type_id):
"""Disassociate the specified QoS with specified volume-type."""
- url = "qos-specs/%s/disassociate" % str(qos_id)
+ url = "qos-specs/%s/disassociate" % qos_id
url += "?vol_type_id=%s" % vol_type_id
resp, body = self.get(url)
self.expected_success(202, resp.status)
@@ -152,7 +152,7 @@
def disassociate_all_qos(self, qos_id):
"""Disassociate the specified QoS with all associations."""
- url = "qos-specs/%s/disassociate_all" % str(qos_id)
+ url = "qos-specs/%s/disassociate_all" % qos_id
resp, body = self.get(url)
self.expected_success(202, resp.status)
return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/volume/base/base_snapshots_client.py b/tempest/services/volume/base/base_snapshots_client.py
index 7a8e12b..38a6dc7 100755
--- a/tempest/services/volume/base/base_snapshots_client.py
+++ b/tempest/services/volume/base/base_snapshots_client.py
@@ -45,7 +45,7 @@
Available params: see http://developer.openstack.org/
api-ref-blockstorage-v2.html#showSnapshot
"""
- url = "snapshots/%s" % str(snapshot_id)
+ url = "snapshots/%s" % snapshot_id
resp, body = self.get(url)
body = json.loads(body)
self.expected_success(200, resp.status)
@@ -81,7 +81,7 @@
Available params: see http://developer.openstack.org/
api-ref-blockstorage-v2.html#deleteSnapshot
"""
- resp, body = self.delete("snapshots/%s" % str(snapshot_id))
+ resp, body = self.delete("snapshots/%s" % snapshot_id)
self.expected_success(202, resp.status)
return rest_client.ResponseBody(resp, body)
@@ -112,7 +112,7 @@
# Bug https://bugs.launchpad.net/openstack-api-site/+bug/1532645
post_body = json.dumps({'os-update_snapshot_status': kwargs})
- url = 'snapshots/%s/action' % str(snapshot_id)
+ url = 'snapshots/%s/action' % snapshot_id
resp, body = self.post(url, post_body)
self.expected_success(202, resp.status)
return rest_client.ResponseBody(resp, body)
@@ -120,7 +120,7 @@
def create_snapshot_metadata(self, snapshot_id, metadata):
"""Create metadata for the snapshot."""
put_body = json.dumps({'metadata': metadata})
- url = "snapshots/%s/metadata" % str(snapshot_id)
+ url = "snapshots/%s/metadata" % snapshot_id
resp, body = self.post(url, put_body)
body = json.loads(body)
self.expected_success(200, resp.status)
@@ -133,7 +133,7 @@
api-ref-blockstorage-v2.html#
showSnapshotMetadata
"""
- url = "snapshots/%s/metadata" % str(snapshot_id)
+ url = "snapshots/%s/metadata" % snapshot_id
resp, body = self.get(url)
body = json.loads(body)
self.expected_success(200, resp.status)
@@ -147,7 +147,7 @@
updateSnapshotMetadata
"""
put_body = json.dumps(kwargs)
- url = "snapshots/%s/metadata" % str(snapshot_id)
+ url = "snapshots/%s/metadata" % snapshot_id
resp, body = self.put(url, put_body)
body = json.loads(body)
self.expected_success(200, resp.status)
@@ -160,7 +160,7 @@
# link to api-site.
# LP: https://bugs.launchpad.net/openstack-api-site/+bug/1529064
put_body = json.dumps(kwargs)
- url = "snapshots/%s/metadata/%s" % (str(snapshot_id), str(id))
+ url = "snapshots/%s/metadata/%s" % (snapshot_id, id)
resp, body = self.put(url, put_body)
body = json.loads(body)
self.expected_success(200, resp.status)
@@ -168,7 +168,7 @@
def delete_snapshot_metadata_item(self, snapshot_id, id):
"""Delete metadata item for the snapshot."""
- url = "snapshots/%s/metadata/%s" % (str(snapshot_id), str(id))
+ url = "snapshots/%s/metadata/%s" % (snapshot_id, id)
resp, body = self.delete(url)
self.expected_success(200, resp.status)
return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/volume/base/base_volumes_client.py b/tempest/services/volume/base/base_volumes_client.py
index d694c53..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.
@@ -63,7 +53,11 @@
return rest_client.ResponseBody(resp, body)
def show_pools(self, detail=False):
- # List all the volumes pools (hosts)
+ """List all the volumes pools (hosts).
+
+ Output params: see http://developer.openstack.org/
+ api-ref-blockstorage-v2.html#listPools
+ """
url = 'scheduler-stats/get_pools'
if detail:
url += '?detail=True'
@@ -73,9 +67,22 @@
self.expected_success(200, resp.status)
return rest_client.ResponseBody(resp, body)
+ def show_backend_capabilities(self, host):
+ """Shows capabilities for a storage back end.
+
+ Output params: see http://developer.openstack.org/
+ api-ref-blockstorage-v2.html
+ #showBackendCapabilities
+ """
+ url = 'capabilities/%s' % host
+ resp, body = self.get(url)
+ body = json.loads(body)
+ self.expected_success(200, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
def show_volume(self, volume_id):
"""Returns the details of a single volume."""
- url = "volumes/%s" % str(volume_id)
+ url = "volumes/%s" % volume_id
resp, body = self.get(url)
body = json.loads(body)
self.expected_success(200, resp.status)
@@ -87,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)
@@ -109,7 +114,7 @@
def delete_volume(self, volume_id):
"""Deletes the Specified Volume."""
- resp, body = self.delete("volumes/%s" % str(volume_id))
+ resp, body = self.delete("volumes/%s" % volume_id)
self.expected_success(202, resp.status)
return rest_client.ResponseBody(resp, body)
@@ -201,22 +206,6 @@
self.expected_success(202, resp.status)
return rest_client.ResponseBody(resp, body)
- def volume_begin_detaching(self, volume_id):
- """Volume Begin Detaching."""
- # ref cinder/api/contrib/volume_actions.py#L158
- post_body = json.dumps({'os-begin_detaching': {}})
- resp, body = self.post('volumes/%s/action' % volume_id, post_body)
- self.expected_success(202, resp.status)
- return rest_client.ResponseBody(resp, body)
-
- def volume_roll_detaching(self, volume_id):
- """Volume Roll Detaching."""
- # cinder/api/contrib/volume_actions.py#L170
- post_body = json.dumps({'os-roll_detaching': {}})
- resp, body = self.post('volumes/%s/action' % volume_id, post_body)
- self.expected_success(202, resp.status)
- return rest_client.ResponseBody(resp, body)
-
def create_volume_transfer(self, **kwargs):
"""Create a volume transfer.
@@ -231,7 +220,7 @@
def show_volume_transfer(self, transfer_id):
"""Returns the details of a volume transfer."""
- url = "os-volume-transfer/%s" % str(transfer_id)
+ url = "os-volume-transfer/%s" % transfer_id
resp, body = self.get(url)
body = json.loads(body)
self.expected_success(200, resp.status)
@@ -253,7 +242,7 @@
def delete_volume_transfer(self, transfer_id):
"""Delete a volume transfer."""
- resp, body = self.delete("os-volume-transfer/%s" % str(transfer_id))
+ resp, body = self.delete("os-volume-transfer/%s" % transfer_id)
self.expected_success(202, resp.status)
return rest_client.ResponseBody(resp, body)
@@ -288,7 +277,7 @@
def create_volume_metadata(self, volume_id, metadata):
"""Create metadata for the volume."""
put_body = json.dumps({'metadata': metadata})
- url = "volumes/%s/metadata" % str(volume_id)
+ url = "volumes/%s/metadata" % volume_id
resp, body = self.post(url, put_body)
body = json.loads(body)
self.expected_success(200, resp.status)
@@ -296,7 +285,7 @@
def show_volume_metadata(self, volume_id):
"""Get metadata of the volume."""
- url = "volumes/%s/metadata" % str(volume_id)
+ url = "volumes/%s/metadata" % volume_id
resp, body = self.get(url)
body = json.loads(body)
self.expected_success(200, resp.status)
@@ -305,7 +294,7 @@
def update_volume_metadata(self, volume_id, metadata):
"""Update metadata for the volume."""
put_body = json.dumps({'metadata': metadata})
- url = "volumes/%s/metadata" % str(volume_id)
+ url = "volumes/%s/metadata" % volume_id
resp, body = self.put(url, put_body)
body = json.loads(body)
self.expected_success(200, resp.status)
@@ -314,7 +303,7 @@
def update_volume_metadata_item(self, volume_id, id, meta_item):
"""Update metadata item for the volume."""
put_body = json.dumps({'meta': meta_item})
- url = "volumes/%s/metadata/%s" % (str(volume_id), str(id))
+ url = "volumes/%s/metadata/%s" % (volume_id, id)
resp, body = self.put(url, put_body)
body = json.loads(body)
self.expected_success(200, resp.status)
@@ -322,7 +311,7 @@
def delete_volume_metadata_item(self, volume_id, id):
"""Delete metadata item for the volume."""
- url = "volumes/%s/metadata/%s" % (str(volume_id), str(id))
+ url = "volumes/%s/metadata/%s" % (volume_id, id)
resp, body = self.delete(url)
self.expected_success(200, resp.status)
return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/volume/v2/json/admin/types_client.py b/tempest/services/volume/v2/json/admin/types_client.py
index ecf5131..f76e8dc 100644
--- a/tempest/services/volume/v2/json/admin/types_client.py
+++ b/tempest/services/volume/v2/json/admin/types_client.py
@@ -13,9 +13,51 @@
# 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.services.volume.base.admin import base_types_client
class TypesClient(base_types_client.BaseTypesClient):
"""Client class to send CRUD Volume V2 API requests"""
api_version = "v2"
+
+ def add_type_access(self, volume_type_id, **kwargs):
+ """Adds volume type access for the given project.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-blockstorage-v2.html
+ #createVolumeTypeAccessExt
+ """
+ post_body = json.dumps({'addProjectAccess': kwargs})
+ url = 'types/%s/action' % volume_type_id
+ resp, body = self.post(url, post_body)
+ self.expected_success(202, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
+ def remove_type_access(self, volume_type_id, **kwargs):
+ """Removes volume type access for the given project.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-blockstorage-v2.html
+ #removeVolumeTypeAccessExt
+ """
+ post_body = json.dumps({'removeProjectAccess': kwargs})
+ url = 'types/%s/action' % volume_type_id
+ resp, body = self.post(url, post_body)
+ self.expected_success(202, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
+ def list_type_access(self, volume_type_id):
+ """Print access information about the given volume type.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-blockstorage-v2.html#
+ listVolumeTypeAccessExt
+ """
+ url = 'types/%s/os-volume-type-access' % volume_type_id
+ resp, body = self.get(url)
+ body = json.loads(body)
+ self.expected_success(200, resp.status)
+ return rest_client.ResponseBody(resp, body)
diff --git a/tempest/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/cmd/test_workspace.py b/tempest/tests/cmd/test_workspace.py
index 2639d93..6ca4d42 100644
--- a/tempest/tests/cmd/test_workspace.py
+++ b/tempest/tests/cmd/test_workspace.py
@@ -17,7 +17,7 @@
import subprocess
import tempfile
-from tempest.cmd.workspace import WorkspaceManager
+from tempest.cmd import workspace
from tempest.lib.common.utils import data_utils
from tempest.tests import base
@@ -31,7 +31,8 @@
store_dir = tempfile.mkdtemp()
self.addCleanup(shutil.rmtree, store_dir, ignore_errors=True)
self.store_file = os.path.join(store_dir, 'workspace.yaml')
- self.workspace_manager = WorkspaceManager(path=self.store_file)
+ self.workspace_manager = workspace.WorkspaceManager(
+ path=self.store_file)
self.workspace_manager.register_new_workspace(self.name, self.path)
@@ -92,7 +93,8 @@
store_dir = tempfile.mkdtemp()
self.addCleanup(shutil.rmtree, store_dir, ignore_errors=True)
self.store_file = os.path.join(store_dir, 'workspace.yaml')
- self.workspace_manager = WorkspaceManager(path=self.store_file)
+ self.workspace_manager = workspace.WorkspaceManager(
+ path=self.store_file)
self.workspace_manager.register_new_workspace(self.name, self.path)
def test_workspace_manager_get(self):
diff --git a/tempest/tests/common/test_dynamic_creds.py b/tempest/tests/common/test_dynamic_creds.py
index b7cc05d..e7b9a4c 100644
--- a/tempest/tests/common/test_dynamic_creds.py
+++ b/tempest/tests/common/test_dynamic_creds.py
@@ -27,13 +27,13 @@
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.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
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/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_regions_client.py b/tempest/tests/lib/services/identity/v3/test_regions_client.py
new file mode 100644
index 0000000..a2cb86f
--- /dev/null
+++ b/tempest/tests/lib/services/identity/v3/test_regions_client.py
@@ -0,0 +1,125 @@
+# 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 regions_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestRegionsClient(base.BaseServiceTest):
+ FAKE_CREATE_REGION = {
+ "region": {
+ "description": "My subregion",
+ "id": "RegionOneSubRegion",
+ "parent_region_id": "RegionOne"
+ }
+ }
+
+ FAKE_REGION_INFO = {
+ "region": {
+ "description": "My subregion 3",
+ "id": "RegionThree",
+ "links": {
+ "self": "http://example.com/identity/v3/regions/RegionThree"
+ },
+ "parent_region_id": "RegionOne"
+ }
+ }
+
+ FAKE_LIST_REGIONS = {
+ "links": {
+ "next": None,
+ "previous": None,
+ "self": "http://example.com/identity/v3/regions"
+ },
+ "regions": [
+ {
+ "description": "",
+ "id": "RegionOne",
+ "links": {
+ "self": "http://example.com/identity/v3/regions/RegionOne"
+ },
+ "parent_region_id": None
+ }
+ ]
+ }
+
+ def setUp(self):
+ super(TestRegionsClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = regions_client.RegionsClient(fake_auth, 'identity',
+ 'regionOne')
+
+ def _test_create_region(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.create_region,
+ 'tempest.lib.common.rest_client.RestClient.post',
+ self.FAKE_CREATE_REGION,
+ bytes_body,
+ status=201)
+
+ def _test_show_region(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_region,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_REGION_INFO,
+ bytes_body,
+ region_id="RegionThree")
+
+ def _test_list_regions(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_regions,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_LIST_REGIONS,
+ bytes_body)
+
+ def _test_update_region(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.update_region,
+ 'tempest.lib.common.rest_client.RestClient.patch',
+ self.FAKE_REGION_INFO,
+ bytes_body,
+ region_id="RegionThree")
+
+ def test_create_region_with_str_body(self):
+ self._test_create_region()
+
+ def test_create_region_with_bytes_body(self):
+ self._test_create_region(bytes_body=True)
+
+ def test_show_region_with_str_body(self):
+ self._test_show_region()
+
+ def test_show_region_with_bytes_body(self):
+ self._test_show_region(bytes_body=True)
+
+ def test_list_regions_with_str_body(self):
+ self._test_list_regions()
+
+ def test_list_regions_with_bytes_body(self):
+ self._test_list_regions(bytes_body=True)
+
+ def test_update_region_with_str_body(self):
+ self._test_update_region()
+
+ def test_update_region_with_bytes_body(self):
+ self._test_update_region(bytes_body=True)
+
+ def test_delete_region(self):
+ self.check_service_client_function(
+ self.client.delete_region,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ region_id="RegionThree",
+ status=204)
diff --git a/tempest/tests/lib/services/identity/v3/test_services_client.py b/tempest/tests/lib/services/identity/v3/test_services_client.py
new file mode 100644
index 0000000..f87fcce
--- /dev/null
+++ b/tempest/tests/lib/services/identity/v3/test_services_client.py
@@ -0,0 +1,149 @@
+# 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 services_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestServicesClient(base.BaseServiceTest):
+ FAKE_CREATE_SERVICE = {
+ "service": {
+ "type": "compute",
+ "name": "compute2",
+ "description": "Compute service 2"
+ }
+ }
+
+ FAKE_SERVICE_INFO = {
+ "service": {
+ "description": "Keystone Identity Service",
+ "enabled": True,
+ "id": "686766",
+ "links": {
+ "self": "http://example.com/identity/v3/services/686766"
+ },
+ "name": "keystone",
+ "type": "identity"
+ }
+ }
+
+ FAKE_LIST_SERVICES = {
+ "links": {
+ "next": None,
+ "previous": None,
+ "self": "http://example.com/identity/v3/services"
+ },
+ "services": [
+ {
+ "description": "Nova Compute Service",
+ "enabled": True,
+ "id": "1999c3",
+ "links": {
+ "self": "http://example.com/identity/v3/services/1999c3"
+ },
+ "name": "nova",
+ "type": "compute"
+ },
+ {
+ "description": "Cinder Volume Service V2",
+ "enabled": True,
+ "id": "392166",
+ "links": {
+ "self": "http://example.com/identity/v3/services/392166"
+ },
+ "name": "cinderv2",
+ "type": "volumev2"
+ },
+ {
+ "description": "Neutron Service",
+ "enabled": True,
+ "id": "4fe41a",
+ "links": {
+ "self": "http://example.com/identity/v3/services/4fe41a"
+ },
+ "name": "neutron",
+ "type": "network"
+ }
+ ]
+ }
+
+ def setUp(self):
+ super(TestServicesClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = services_client.ServicesClient(fake_auth, 'identity',
+ 'regionOne')
+
+ def _test_create_service(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.create_service,
+ 'tempest.lib.common.rest_client.RestClient.post',
+ self.FAKE_CREATE_SERVICE,
+ bytes_body,
+ status=201)
+
+ def _test_show_service(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_service,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_SERVICE_INFO,
+ bytes_body,
+ service_id="686766")
+
+ def _test_list_services(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_services,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_LIST_SERVICES,
+ bytes_body)
+
+ def _test_update_service(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.update_service,
+ 'tempest.lib.common.rest_client.RestClient.patch',
+ self.FAKE_SERVICE_INFO,
+ bytes_body,
+ service_id="686766")
+
+ def test_create_service_with_str_body(self):
+ self._test_create_service()
+
+ def test_create_service_with_bytes_body(self):
+ self._test_create_service(bytes_body=True)
+
+ def test_show_service_with_str_body(self):
+ self._test_show_service()
+
+ def test_show_service_with_bytes_body(self):
+ self._test_show_service(bytes_body=True)
+
+ def test_list_services_with_str_body(self):
+ self._test_list_services()
+
+ def test_list_services_with_bytes_body(self):
+ self._test_list_services(bytes_body=True)
+
+ def test_update_service_with_str_body(self):
+ self._test_update_service()
+
+ def test_update_service_with_bytes_body(self):
+ self._test_update_service(bytes_body=True)
+
+ def test_delete_service(self):
+ self.check_service_client_function(
+ self.client.delete_service,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ service_id="686766",
+ status=204)
diff --git a/tempest/tests/lib/services/network/test_versions_client.py b/tempest/tests/lib/services/network/test_versions_client.py
index 715176b..ae52c8a 100644
--- a/tempest/tests/lib/services/network/test_versions_client.py
+++ b/tempest/tests/lib/services/network/test_versions_client.py
@@ -14,7 +14,7 @@
import copy
-from tempest.lib.services.network.versions_client import NetworkVersionsClient
+from tempest.lib.services.network import versions_client
from tempest.tests.lib import fake_auth_provider
from tempest.tests.lib.services import base
@@ -59,7 +59,7 @@
super(TestNetworkVersionsClient, self).setUp()
fake_auth = fake_auth_provider.FakeAuthProvider()
self.versions_client = (
- NetworkVersionsClient
+ versions_client.NetworkVersionsClient
(fake_auth, 'compute', 'regionOne'))
def _test_versions_client(self, bytes_body=False):
diff --git a/tox.ini b/tox.ini
index cff222d..a621492 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
[tox]
-envlist = pep8,py34,py27
+envlist = pep8,py35,py34,py27
minversion = 2.3.1
skipsdist = True
@@ -77,7 +77,7 @@
# See the testrepository bug: https://bugs.launchpad.net/testrepository/+bug/1208610
commands =
find . -type f -name "*.pyc" -delete
- bash tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty)) {posargs}'
+ bash tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario)) {posargs}'
[testenv:full-serial]
envdir = .tox/tempest
@@ -88,7 +88,7 @@
# See the testrepository bug: https://bugs.launchpad.net/testrepository/+bug/1208610
commands =
find . -type f -name "*.pyc" -delete
- bash tools/pretty_tox_serial.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty)) {posargs}'
+ bash tools/pretty_tox_serial.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario)) {posargs}'
[testenv:smoke]
envdir = .tox/tempest