Merge "Capture logs when running unit tests"
diff --git a/HACKING.rst b/HACKING.rst
index 446d865..cc1f161 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -358,10 +358,10 @@
When adding tests for new features that were not in previous releases of the
projects the new test has to be properly skipped with a feature flag. Whether
-this is just as simple as using the @test.requires_ext() decorator to check
-if the required extension (or discoverable optional API) is enabled or adding
-a new config option to the appropriate section. If there isn't a method of
-selecting the new **feature** from the config file then there won't be a
+this is just as simple as using the @utils.requires_ext() decorator to
+check if the required extension (or discoverable optional API) is enabled or
+adding a new config option to the appropriate section. If there isn't a method
+of selecting the new **feature** from the config file then there won't be a
mechanism to disable the test with older stable releases and the new test won't
be able to merge.
@@ -380,7 +380,7 @@
Otherwise the bug fix won't be able to land in the project.
Handily, `Zuul’s cross-repository dependencies
-<https://docs.openstack.org/infra/zuul/gating.html#cross-repository-dependencies>`_.
+<https://docs.openstack.org/infra/zuul/user/gating.html#cross-project-dependencies>`_.
can be leveraged to do without step 2 and to have steps 3 and 4 happen
"atomically". To do that, make the patch written in step 1 to depend (refer to
Zuul's documentation above) on the patch written in step 4. The commit message
diff --git a/README.rst b/README.rst
index 2e13fec..17d4cba 100644
--- a/README.rst
+++ b/README.rst
@@ -3,7 +3,7 @@
========================
.. image:: http://governance.openstack.org/badges/tempest.svg
- :target: http://governance.openstack.org/reference/tags/index.html
+ :target: https://governance.openstack.org/tc/reference/tags/index.html
.. Change things from this point on
diff --git a/bindep.txt b/bindep.txt
index 8914ade..efd3a10 100644
--- a/bindep.txt
+++ b/bindep.txt
@@ -1,5 +1,5 @@
# This file contains runtime (non-python) dependencies
-# More info at: http://docs.openstack.org/infra/bindep/readme.html
+# More info at: https://docs.openstack.org/infra/bindep/readme.html
libffi-dev [platform:dpkg]
libffi-devel [platform:rpm]
diff --git a/doc/source/conf.py b/doc/source/conf.py
index 0cfdf34..067eb81 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -158,10 +158,6 @@
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
-# If true, SmartyPants will be used to convert quotes and dashes to
-# typographically correct entities.
-html_use_smartypants = False
-
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
diff --git a/doc/source/library/credential_providers.rst b/doc/source/library/credential_providers.rst
index 7e831cc..d96c97a 100644
--- a/doc/source/library/credential_providers.rst
+++ b/doc/source/library/credential_providers.rst
@@ -6,7 +6,7 @@
These library interfaces are used to deal with allocating credentials on demand
either dynamically by calling keystone to allocate new credentials, or from
a list of preprovisioned credentials. These 2 modules are implementations of
-the same abstract credential providers class and can be used interchangably.
+the same abstract credential providers class and can be used interchangeably.
However, each implementation has some additional parameters that are used to
influence the behavior of the modules. The API reference at the bottom of this
doc shows the interface definitions for both modules, however that may be a bit
@@ -130,19 +130,18 @@
# role
provider.clear_creds()
-API Reference
-=============
-------------------------------
+API Reference
+-------------
+
The dynamic credentials module
-------------------------------
+''''''''''''''''''''''''''''''
.. automodule:: tempest.lib.common.dynamic_creds
:members:
---------------------------------------
The pre-provisioned credentials module
---------------------------------------
+''''''''''''''''''''''''''''''''''''''
.. automodule:: tempest.lib.common.preprov_creds
:members:
diff --git a/doc/source/microversion_testing.rst b/doc/source/microversion_testing.rst
index d80081d..307eb07 100644
--- a/doc/source/microversion_testing.rst
+++ b/doc/source/microversion_testing.rst
@@ -300,35 +300,35 @@
* `2.2`_
- .. _2.2: http://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id2
+ .. _2.2: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id2
* `2.10`_
- .. _2.10: http://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id9
+ .. _2.10: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id9
* `2.20`_
- .. _2.20: http://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id18
+ .. _2.20: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id18
* `2.25`_
- .. _2.25: http://docs.openstack.org/nova/latest/reference/api-microversion-history.html#maximum-in-mitaka
+ .. _2.25: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#maximum-in-mitaka
* `2.32`_
- .. _2.32: http://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id29
+ .. _2.32: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id29
* `2.37`_
- .. _2.37: http://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id34
+ .. _2.37: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id34
* `2.42`_
- .. _2.42: http://docs.openstack.org/nova/latest/reference/api-microversion-history.html#maximum-in-ocata
+ .. _2.42: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#maximum-in-ocata
* `2.47`_
- .. _2.47: http://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id42
+ .. _2.47: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id42
* `2.48`_
@@ -338,4 +338,4 @@
* `3.3`_
- .. _3.3: https://docs.openstack.org/cinder/ocata/devref/api_microversion_history.html#id4
+ .. _3.3: https://docs.openstack.org/cinder/latest/contributor/api_microversion_history.html#id4
diff --git a/releasenotes/notes/add-ip-version-check-in-addresses-x491ac6d9abaxa12.yaml b/releasenotes/notes/add-ip-version-check-in-addresses-x491ac6d9abaxa12.yaml
new file mode 100644
index 0000000..957e903
--- /dev/null
+++ b/releasenotes/notes/add-ip-version-check-in-addresses-x491ac6d9abaxa12.yaml
@@ -0,0 +1,4 @@
+---
+fixes:
+ Add more accurate ip version check in addresses schema which will
+ limit the ip version value in [4, 6].
diff --git a/releasenotes/notes/add-is-resource-deleted-sg-client-f4a7a7a54ff024d7.yaml b/releasenotes/notes/add-is-resource-deleted-sg-client-f4a7a7a54ff024d7.yaml
new file mode 100644
index 0000000..e046326
--- /dev/null
+++ b/releasenotes/notes/add-is-resource-deleted-sg-client-f4a7a7a54ff024d7.yaml
@@ -0,0 +1,5 @@
+---
+features:
+ - |
+ Implement the `rest_client` method `is_resource_deleted` in the network
+ security group client.
diff --git a/releasenotes/notes/add-return-value-to-retype-volume-a401aa619aaa2457.yaml b/releasenotes/notes/add-return-value-to-retype-volume-a401aa619aaa2457.yaml
index 4abfe9e..ca42014 100644
--- a/releasenotes/notes/add-return-value-to-retype-volume-a401aa619aaa2457.yaml
+++ b/releasenotes/notes/add-return-value-to-retype-volume-a401aa619aaa2457.yaml
@@ -1,5 +1,7 @@
---
fixes:
- Add a missing return statement to the retype_volume API in the v2 volumes_client library.
- This changes the response body from None to an empty dictionary.
+ - |
+ Add a missing return statement to the retype_volume API in the v2
+ volumes_client library: Bug#1703997
+ This changes the response body from None to an empty dictionary.
diff --git a/releasenotes/notes/compare-header-version-func-de5139b2161b3627.yaml b/releasenotes/notes/compare-header-version-func-de5139b2161b3627.yaml
new file mode 100644
index 0000000..305e756
--- /dev/null
+++ b/releasenotes/notes/compare-header-version-func-de5139b2161b3627.yaml
@@ -0,0 +1,15 @@
+---
+features:
+ - |
+ Add a new function called ``compare_version_header_to_response`` to
+ ``tempest.lib.common.api_version_utils``, which compares the API
+ micoversion in the response header to another microversion using the
+ comparators defined in
+ ``tempest.lib.common.api_version_request.APIVersionRequest``.
+
+ It is now possible to determine how to retrieve an attribute from a
+ response body of an API call, depending on the returned microversion.
+
+ Add a new exception type called ``InvalidParam`` to
+ ``tempest.lib.exceptions``, allowing the possibility of raising an
+ exception if an invalid parameter is passed to a library function.
diff --git a/releasenotes/notes/fix-remoteclient-default-ssh-shell-prologue-33e99343d086f601.yaml b/releasenotes/notes/fix-remoteclient-default-ssh-shell-prologue-33e99343d086f601.yaml
new file mode 100644
index 0000000..5063fd5
--- /dev/null
+++ b/releasenotes/notes/fix-remoteclient-default-ssh-shell-prologue-33e99343d086f601.yaml
@@ -0,0 +1,7 @@
+---
+fixes:
+ - |
+ Fix RemoteClient default ssh_shell_prologue: Bug#1707478
+
+ The default ssh_shell_proloque has been modified from
+ specifying erroneous PATH=$$PATH:/sbin to PATH=$PATH:/sbin.
diff --git a/releasenotes/notes/identity-tests-domain-drivers-76235f6672221e45.yaml b/releasenotes/notes/identity-tests-domain-drivers-76235f6672221e45.yaml
new file mode 100644
index 0000000..7ed3081
--- /dev/null
+++ b/releasenotes/notes/identity-tests-domain-drivers-76235f6672221e45.yaml
@@ -0,0 +1,7 @@
+---
+features:
+ - |
+ A new boolean config option ``domain_specific_drivers``
+ is added to the section ``identity-feature-enabled``.
+ This option must be enabled when testing an environment that
+ is configured to use domain-specific identity drivers.
diff --git a/releasenotes/notes/raise-exception-when-error-deleting-on-volume-18d0d0c5886212dd.yaml b/releasenotes/notes/raise-exception-when-error-deleting-on-volume-18d0d0c5886212dd.yaml
new file mode 100644
index 0000000..194dbc1
--- /dev/null
+++ b/releasenotes/notes/raise-exception-when-error-deleting-on-volume-18d0d0c5886212dd.yaml
@@ -0,0 +1,8 @@
+---
+upgrade:
+ - |
+ Tempest checks a volume delete by waiting for NotFound(404) on
+ show_volume(). Sometime a volume delete fails and the volume status
+ becomes error_deleting which means the delete is failed.
+ So Tempest doesn't need to wait anymore. A new release of Tempest
+ raises an exception DeleteErrorException instead of waiting.
diff --git a/releasenotes/notes/start-of-pike-support-f2a1b7ea8e8b0311.yaml b/releasenotes/notes/start-of-pike-support-f2a1b7ea8e8b0311.yaml
new file mode 100644
index 0000000..0787821
--- /dev/null
+++ b/releasenotes/notes/start-of-pike-support-f2a1b7ea8e8b0311.yaml
@@ -0,0 +1,11 @@
+---
+prelude: >
+ This release marks the start of support for the Pike release in Tempest.
+other:
+ - OpenStack Releases supported after this release are **Pike**, **Ocata**,
+ and **Newton**.
+
+ The release under current development of this tag is Queens, meaning
+ that every Tempest commit is also tested against master during the Queens
+ cycle. However, this does not necessarily mean that using Tempest as of
+ this tag will work against a Queens (or future release) cloud.
diff --git a/releasenotes/source/conf.py b/releasenotes/source/conf.py
index 3137541..ae3dca1 100644
--- a/releasenotes/source/conf.py
+++ b/releasenotes/source/conf.py
@@ -158,10 +158,6 @@
# using the given strftime format.
# html_last_updated_fmt = '%b %d, %Y'
-# If true, SmartyPants will be used to convert quotes and dashes to
-# typographically correct entities.
-# html_use_smartypants = True
-
# Custom sidebar templates, maps document names to template names.
# html_sidebars = {}
diff --git a/releasenotes/source/index.rst b/releasenotes/source/index.rst
index db01da0..df1de46 100644
--- a/releasenotes/source/index.rst
+++ b/releasenotes/source/index.rst
@@ -6,6 +6,7 @@
:maxdepth: 1
unreleased
+ v17.0.0
v16.1.0
v16.0.0
v15.0.0
diff --git a/releasenotes/source/v17.0.0.rst b/releasenotes/source/v17.0.0.rst
new file mode 100644
index 0000000..3f50f11
--- /dev/null
+++ b/releasenotes/source/v17.0.0.rst
@@ -0,0 +1,6 @@
+=====================
+v17.0.0 Release Notes
+=====================
+
+.. release-notes:: 17.0.0 Release Notes
+ :version: 17.0.0
diff --git a/requirements.txt b/requirements.txt
index a74f5c2..36b9efa 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -5,17 +5,17 @@
cliff>=2.8.0 # Apache-2.0
jsonschema!=2.5.0,<3.0.0,>=2.0.0 # MIT
testtools>=1.4.0 # MIT
-paramiko>=2.0 # LGPLv2.1+
+paramiko>=2.0.0 # LGPLv2.1+
netaddr!=0.7.16,>=0.7.13 # BSD
testrepository>=0.0.18 # Apache-2.0/BSD
oslo.concurrency>=3.8.0 # Apache-2.0
oslo.config!=4.3.0,!=4.4.0,>=4.0.0 # Apache-2.0
-oslo.log>=3.22.0 # Apache-2.0
+oslo.log>=3.30.0 # Apache-2.0
oslo.serialization!=2.19.1,>=1.10.0 # Apache-2.0
oslo.utils>=3.20.0 # Apache-2.0
six>=1.9.0 # MIT
fixtures>=3.0.0 # Apache-2.0/BSD
-PyYAML>=3.10.0 # MIT
+PyYAML>=3.10 # MIT
python-subunit>=0.0.18 # Apache-2.0/BSD
stevedore>=1.20.0 # Apache-2.0
PrettyTable<0.8,>=0.7.1 # BSD
diff --git a/tempest/api/compute/admin/test_agents.py b/tempest/api/compute/admin/test_agents.py
index 69cbfb5..0901374 100644
--- a/tempest/api/compute/admin/test_agents.py
+++ b/tempest/api/compute/admin/test_agents.py
@@ -86,7 +86,7 @@
body = self.client.create_agent(**self.params_agent)['agent']
self.addCleanup(self.client.delete_agent, body['agent_id'])
agents = self.client.list_agents()['agents']
- self.assertNotEmpty(agents, 'Cannot get any agents.(%s)' % agents)
+ self.assertNotEmpty(agents, 'Cannot get any agents.')
self.assertIn(body['agent_id'], map(lambda x: x['agent_id'], agents))
@decorators.idempotent_id('eabadde4-3cd7-4ec4-a4b5-5a936d2d4408')
@@ -104,7 +104,7 @@
agent_id_xen = agent_xen['agent_id']
agents = (self.client.list_agents(hypervisor=agent_xen['hypervisor'])
['agents'])
- self.assertNotEmpty(agents, 'Cannot get any agents.(%s)' % agents)
+ self.assertNotEmpty(agents, 'Cannot get any agents.')
self.assertIn(agent_id_xen, map(lambda x: x['agent_id'], agents))
self.assertNotIn(body['agent_id'], map(lambda x: x['agent_id'],
agents))
diff --git a/tempest/api/compute/admin/test_auto_allocate_network.py b/tempest/api/compute/admin/test_auto_allocate_network.py
index 83fe215..6f23866 100644
--- a/tempest/api/compute/admin/test_auto_allocate_network.py
+++ b/tempest/api/compute/admin/test_auto_allocate_network.py
@@ -16,12 +16,11 @@
from tempest.api.compute import base
from tempest.common import compute
-from tempest.common import credentials_factory as credentials
+from tempest.common import utils
from tempest import config
from tempest.lib.common.utils import test_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_excs
-from tempest import test
CONF = config.CONF
LOG = log.getLogger(__name__)
@@ -46,14 +45,10 @@
@classmethod
def skip_checks(cls):
super(AutoAllocateNetworkTest, cls).skip_checks()
- identity_version = cls.get_identity_version()
- if not credentials.is_admin_available(
- identity_version=identity_version):
- msg = "Missing Identity Admin API credentials in configuration."
- raise cls.skipException(msg)
if not CONF.service_available.neutron:
raise cls.skipException('Neutron is required')
- if not test.is_extension_enabled('auto-allocated-topology', 'network'):
+ if not utils.is_extension_enabled('auto-allocated-topology',
+ 'network'):
raise cls.skipException(
'auto-allocated-topology extension is not available')
@@ -180,9 +175,11 @@
_, servers = compute.create_test_server(
self.os_primary, networks='auto', wait_until='ACTIVE',
min_count=3)
- server_nets = set()
for server in servers:
self.addCleanup(self.delete_server, server['id'])
+
+ server_nets = set()
+ for server in servers:
# get the server ips
addresses = self.servers_client.list_addresses(
server['id'])['addresses']
diff --git a/tempest/api/compute/admin/test_create_server.py b/tempest/api/compute/admin/test_create_server.py
index 3449aba..66bedd9 100644
--- a/tempest/api/compute/admin/test_create_server.py
+++ b/tempest/api/compute/admin/test_create_server.py
@@ -25,8 +25,6 @@
class ServersWithSpecificFlavorTestJSON(base.BaseV2ComputeAdminTest):
- disk_config = 'AUTO'
-
@classmethod
def setup_credentials(cls):
cls.prepare_instance_network()
diff --git a/tempest/api/compute/admin/test_fixed_ips.py b/tempest/api/compute/admin/test_fixed_ips.py
index 1e09eeb..ebba73c 100644
--- a/tempest/api/compute/admin/test_fixed_ips.py
+++ b/tempest/api/compute/admin/test_fixed_ips.py
@@ -14,9 +14,9 @@
# under the License.
from tempest.api.compute import base
+from tempest.common import utils
from tempest import config
from tempest.lib import decorators
-from tempest import test
CONF = config.CONF
@@ -29,6 +29,8 @@
if CONF.service_available.neutron:
msg = ("%s skipped as neutron is available" % cls.__name__)
raise cls.skipException(msg)
+ if not utils.get_service_list()['network']:
+ raise cls.skipException("network service not enabled.")
@classmethod
def setup_clients(cls):
@@ -49,17 +51,14 @@
break
@decorators.idempotent_id('16b7d848-2f7c-4709-85a3-2dfb4576cc52')
- @test.services('network')
def test_list_fixed_ip_details(self):
fixed_ip = self.client.show_fixed_ip(self.ip)
self.assertEqual(fixed_ip['fixed_ip']['address'], self.ip)
@decorators.idempotent_id('5485077b-7e46-4cec-b402-91dc3173433b')
- @test.services('network')
def test_set_reserve(self):
self.client.reserve_fixed_ip(self.ip, reserve="None")
@decorators.idempotent_id('7476e322-b9ff-4710-bf82-49d51bac6e2e')
- @test.services('network')
def test_set_unreserve(self):
self.client.reserve_fixed_ip(self.ip, unreserve="None")
diff --git a/tempest/api/compute/admin/test_fixed_ips_negative.py b/tempest/api/compute/admin/test_fixed_ips_negative.py
index a77011e..a5deb3c 100644
--- a/tempest/api/compute/admin/test_fixed_ips_negative.py
+++ b/tempest/api/compute/admin/test_fixed_ips_negative.py
@@ -13,10 +13,10 @@
# under the License.
from tempest.api.compute import base
+from tempest.common import utils
from tempest import config
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
-from tempest import test
CONF = config.CONF
@@ -29,6 +29,8 @@
if CONF.service_available.neutron:
msg = ("%s skipped as neutron is available" % cls.__name__)
raise cls.skipException(msg)
+ if not utils.get_service_list()['network']:
+ raise cls.skipException("network service not enabled.")
@classmethod
def setup_clients(cls):
@@ -51,14 +53,12 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('9f17f47d-daad-4adc-986e-12370c93e407')
- @test.services('network')
def test_list_fixed_ip_details_with_non_admin_user(self):
self.assertRaises(lib_exc.Forbidden,
self.non_admin_client.show_fixed_ip, self.ip)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('ce60042c-fa60-4836-8d43-1c8e3359dc47')
- @test.services('network')
def test_set_reserve_with_non_admin_user(self):
self.assertRaises(lib_exc.Forbidden,
self.non_admin_client.reserve_fixed_ip,
@@ -66,7 +66,6 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('f1f7a35b-0390-48c5-9803-5f27461439db')
- @test.services('network')
def test_set_unreserve_with_non_admin_user(self):
self.assertRaises(lib_exc.Forbidden,
self.non_admin_client.reserve_fixed_ip,
@@ -74,7 +73,6 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('f51cf464-7fc5-4352-bc3e-e75cfa2cb717')
- @test.services('network')
def test_set_reserve_with_invalid_ip(self):
# NOTE(maurosr): since this exercises the same code snippet, we do it
# only for reserve action
@@ -87,7 +85,6 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('fd26ef50-f135-4232-9d32-281aab3f9176')
- @test.services('network')
def test_fixed_ip_with_invalid_action(self):
self.assertRaises(lib_exc.BadRequest,
self.client.reserve_fixed_ip,
diff --git a/tempest/api/compute/admin/test_flavors.py b/tempest/api/compute/admin/test_flavors.py
index 36ebc25..1483c2e 100644
--- a/tempest/api/compute/admin/test_flavors.py
+++ b/tempest/api/compute/admin/test_flavors.py
@@ -16,10 +16,10 @@
import uuid
from tempest.api.compute import base
+from tempest.common import utils
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
-from tempest import test
class FlavorsAdminTestJSON(base.BaseV2ComputeAdminTest):
@@ -28,7 +28,7 @@
@classmethod
def skip_checks(cls):
super(FlavorsAdminTestJSON, cls).skip_checks()
- if not test.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'):
+ if not utils.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'):
msg = "OS-FLV-EXT-DATA extension not enabled."
raise cls.skipException(msg)
diff --git a/tempest/api/compute/admin/test_flavors_access.py b/tempest/api/compute/admin/test_flavors_access.py
index 2c236ec..b8e2b42 100644
--- a/tempest/api/compute/admin/test_flavors_access.py
+++ b/tempest/api/compute/admin/test_flavors_access.py
@@ -14,8 +14,8 @@
# under the License.
from tempest.api.compute import base
+from tempest.common import utils
from tempest.lib import decorators
-from tempest import test
class FlavorsAccessTestJSON(base.BaseV2ComputeAdminTest):
@@ -27,7 +27,7 @@
@classmethod
def skip_checks(cls):
super(FlavorsAccessTestJSON, cls).skip_checks()
- if not test.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'):
+ if not utils.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'):
msg = "OS-FLV-EXT-DATA extension not enabled."
raise cls.skipException(msg)
diff --git a/tempest/api/compute/admin/test_flavors_access_negative.py b/tempest/api/compute/admin/test_flavors_access_negative.py
index be165cb..45ca10a 100644
--- a/tempest/api/compute/admin/test_flavors_access_negative.py
+++ b/tempest/api/compute/admin/test_flavors_access_negative.py
@@ -14,9 +14,9 @@
# under the License.
from tempest.api.compute import base
+from tempest.common import utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
-from tempest import test
class FlavorsAccessNegativeTestJSON(base.BaseV2ComputeAdminTest):
@@ -30,7 +30,7 @@
@classmethod
def skip_checks(cls):
super(FlavorsAccessNegativeTestJSON, cls).skip_checks()
- if not test.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'):
+ if not utils.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'):
msg = "OS-FLV-EXT-DATA extension not enabled."
raise cls.skipException(msg)
diff --git a/tempest/api/compute/admin/test_flavors_extra_specs.py b/tempest/api/compute/admin/test_flavors_extra_specs.py
index 747cb42..d4e7bd5 100644
--- a/tempest/api/compute/admin/test_flavors_extra_specs.py
+++ b/tempest/api/compute/admin/test_flavors_extra_specs.py
@@ -14,9 +14,9 @@
# under the License.
from tempest.api.compute import base
+from tempest.common import utils
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
-from tempest import test
class FlavorsExtraSpecsTestJSON(base.BaseV2ComputeAdminTest):
@@ -29,7 +29,7 @@
@classmethod
def skip_checks(cls):
super(FlavorsExtraSpecsTestJSON, cls).skip_checks()
- if not test.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'):
+ if not utils.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'):
msg = "OS-FLV-EXT-DATA extension not enabled."
raise cls.skipException(msg)
diff --git a/tempest/api/compute/admin/test_flavors_extra_specs_negative.py b/tempest/api/compute/admin/test_flavors_extra_specs_negative.py
index f39feb9..bc32346 100644
--- a/tempest/api/compute/admin/test_flavors_extra_specs_negative.py
+++ b/tempest/api/compute/admin/test_flavors_extra_specs_negative.py
@@ -15,10 +15,10 @@
# under the License.
from tempest.api.compute import base
+from tempest.common import utils
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
-from tempest import test
class FlavorsExtraSpecsNegativeTestJSON(base.BaseV2ComputeAdminTest):
@@ -30,7 +30,7 @@
@classmethod
def skip_checks(cls):
super(FlavorsExtraSpecsNegativeTestJSON, cls).skip_checks()
- if not test.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'):
+ if not utils.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'):
msg = "OS-FLV-EXT-DATA extension not enabled."
raise cls.skipException(msg)
diff --git a/tempest/api/compute/admin/test_floating_ips_bulk.py b/tempest/api/compute/admin/test_floating_ips_bulk.py
index 496f119..ba19937 100644
--- a/tempest/api/compute/admin/test_floating_ips_bulk.py
+++ b/tempest/api/compute/admin/test_floating_ips_bulk.py
@@ -16,11 +16,11 @@
import netaddr
from tempest.api.compute import base
+from tempest.common import utils
from tempest import config
from tempest.lib.common.utils import test_utils
from tempest.lib import decorators
from tempest.lib import exceptions
-from tempest import test
CONF = config.CONF
@@ -57,7 +57,7 @@
return
@decorators.idempotent_id('2c8f145f-8012-4cb8-ac7e-95a587f0e4ab')
- @test.services('network')
+ @utils.services('network')
def test_create_list_delete_floating_ips_bulk(self):
# Create, List and delete the Floating IPs Bulk
pool = 'test_pool'
diff --git a/tempest/api/compute/admin/test_hypervisor.py b/tempest/api/compute/admin/test_hypervisor.py
index 0db802c..404fd94 100644
--- a/tempest/api/compute/admin/test_hypervisor.py
+++ b/tempest/api/compute/admin/test_hypervisor.py
@@ -30,26 +30,23 @@
hypers = self.client.list_hypervisors()['hypervisors']
return hypers
- def assertHypervisors(self, hypers):
- self.assertNotEmpty(hypers, "No hypervisors found: %s" % hypers)
-
@decorators.idempotent_id('7f0ceacd-c64d-4e96-b8ee-d02943142cc5')
def test_get_hypervisor_list(self):
# List of hypervisor and available hypervisors hostname
hypers = self._list_hypervisors()
- self.assertHypervisors(hypers)
+ self.assertNotEmpty(hypers, "No hypervisors found.")
@decorators.idempotent_id('1e7fdac2-b672-4ad1-97a4-bad0e3030118')
def test_get_hypervisor_list_details(self):
# Display the details of the all hypervisor
hypers = self.client.list_hypervisors(detail=True)['hypervisors']
- self.assertHypervisors(hypers)
+ self.assertNotEmpty(hypers, "No hypervisors found.")
@decorators.idempotent_id('94ff9eae-a183-428e-9cdb-79fde71211cc')
def test_get_hypervisor_show_details(self):
# Display the details of the specified hypervisor
hypers = self._list_hypervisors()
- self.assertHypervisors(hypers)
+ self.assertNotEmpty(hypers, "No hypervisors found.")
details = self.client.show_hypervisor(hypers[0]['id'])['hypervisor']
self.assertNotEmpty(details)
@@ -60,7 +57,7 @@
def test_get_hypervisor_show_servers(self):
# Show instances about the specific hypervisors
hypers = self._list_hypervisors()
- self.assertHypervisors(hypers)
+ self.assertNotEmpty(hypers, "No hypervisors found.")
hostname = hypers[0]['hypervisor_hostname']
hypervisors = (self.client.list_servers_on_hypervisor(hostname)
@@ -116,7 +113,7 @@
@decorators.idempotent_id('d7e1805b-3b14-4a3b-b6fd-50ec6d9f361f')
def test_search_hypervisor(self):
hypers = self._list_hypervisors()
- self.assertHypervisors(hypers)
+ self.assertNotEmpty(hypers, "No hypervisors found.")
hypers = self.client.search_hypervisor(
hypers[0]['hypervisor_hostname'])['hypervisors']
- self.assertHypervisors(hypers)
+ self.assertNotEmpty(hypers, "No hypervisors found.")
diff --git a/tempest/api/compute/admin/test_live_migration.py b/tempest/api/compute/admin/test_live_migration.py
index 256a267..14be947 100644
--- a/tempest/api/compute/admin/test_live_migration.py
+++ b/tempest/api/compute/admin/test_live_migration.py
@@ -20,10 +20,10 @@
from tempest.api.compute import base
from tempest.common import compute
+from tempest.common import utils
from tempest.common import waiters
from tempest import config
from tempest.lib import decorators
-from tempest import test
CONF = config.CONF
LOG = logging.getLogger(__name__)
@@ -122,7 +122,7 @@
@decorators.skip_because(bug="1524898")
@decorators.idempotent_id('5071cf17-3004-4257-ae61-73a84e28badd')
- @test.services('volume')
+ @utils.services('volume')
def test_volume_backed_live_migration(self):
self._test_live_migration(volume_backed=True)
diff --git a/tempest/api/compute/admin/test_quotas.py b/tempest/api/compute/admin/test_quotas.py
index 1aa9227..5894e80 100644
--- a/tempest/api/compute/admin/test_quotas.py
+++ b/tempest/api/compute/admin/test_quotas.py
@@ -157,8 +157,7 @@
def _restore_default_quotas(self, original_defaults):
LOG.debug("restoring quota class defaults")
- self.adm_client.update_quota_class_set(
- 'default', **original_defaults)['quota_class_set']
+ self.adm_client.update_quota_class_set('default', **original_defaults)
# NOTE(sdague): this test is problematic as it changes
# global state, and possibly needs to be part of a set of
diff --git a/tempest/api/compute/admin/test_quotas_negative.py b/tempest/api/compute/admin/test_quotas_negative.py
index 747f320..5ef7ee4 100644
--- a/tempest/api/compute/admin/test_quotas_negative.py
+++ b/tempest/api/compute/admin/test_quotas_negative.py
@@ -13,11 +13,11 @@
# under the License.
from tempest.api.compute import base
+from tempest.common import utils
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
-from tempest import test
CONF = config.CONF
@@ -89,7 +89,7 @@
condition=CONF.service_available.neutron)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('7c6c8f3b-2bf6-4918-b240-57b136a66aa0')
- @test.services('network')
+ @utils.services('network')
def test_security_groups_exceed_limit(self):
# Negative test: Creation Security Groups over limit should FAIL
# Set the quota to number of used security groups
@@ -108,7 +108,7 @@
condition=CONF.service_available.neutron)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('6e9f436d-f1ed-4f8e-a493-7275dfaa4b4d')
- @test.services('network')
+ @utils.services('network')
def test_security_groups_rules_exceed_limit(self):
# Negative test: Creation of Security Group Rules should FAIL
# when we reach limit maxSecurityGroupRules
diff --git a/tempest/api/compute/admin/test_security_groups.py b/tempest/api/compute/admin/test_security_groups.py
index 8abe03a..ff9caa3 100644
--- a/tempest/api/compute/admin/test_security_groups.py
+++ b/tempest/api/compute/admin/test_security_groups.py
@@ -14,9 +14,9 @@
# under the License.
from tempest.api.compute import base
+from tempest.common import utils
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
-from tempest import test
class SecurityGroupsTestAdminJSON(base.BaseV2ComputeAdminTest):
@@ -34,7 +34,7 @@
self.client.delete_security_group(securitygroup_id)
@decorators.idempotent_id('49667619-5af9-4c63-ab5d-2cfdd1c8f7f1')
- @test.services('network')
+ @utils.services('network')
def test_list_security_groups_list_all_tenants_filter(self):
# Admin can list security groups of all tenants
# List of all security groups created
diff --git a/tempest/api/compute/admin/test_servers.py b/tempest/api/compute/admin/test_servers.py
index d9a7800..3f06c4e 100644
--- a/tempest/api/compute/admin/test_servers.py
+++ b/tempest/api/compute/admin/test_servers.py
@@ -13,9 +13,7 @@
# under the License.
from tempest.api.compute import base
-from tempest.common import compute
from tempest.common import waiters
-from tempest.lib.common import fixed_network
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
@@ -126,26 +124,17 @@
@decorators.idempotent_id('86c7a8f7-50cf-43a9-9bac-5b985317134f')
def test_list_servers_filter_by_exist_host(self):
# Filter the list of servers by existent host
- name = data_utils.rand_name(self.__class__.__name__ + '-server')
- network = self.get_tenant_network()
- network_kwargs = fixed_network.set_networks_kwarg(network)
- # We need to create the server as an admin, so we can't use
- # self.create_test_server() here as this method creates the server
- # in the "primary" (i.e non-admin) tenant.
- test_server, _ = compute.create_test_server(
- self.os_admin, wait_until="ACTIVE", name=name, **network_kwargs)
- self.addCleanup(self.client.delete_server, test_server['id'])
- server = self.client.show_server(test_server['id'])['server']
- self.assertEqual(server['status'], 'ACTIVE')
+ server = self.client.show_server(self.s1_id)['server']
hostname = server['OS-EXT-SRV-ATTR:host']
- params = {'host': hostname}
- body = self.client.list_servers(**params)
- servers = body['servers']
- nonexistent_params = {'host': 'nonexistent_host'}
+ params = {'host': hostname, 'all_tenants': '1'}
+ servers = self.client.list_servers(**params)['servers']
+ self.assertIn(server['id'], map(lambda x: x['id'], servers))
+
+ nonexistent_params = {'host': 'nonexistent_host',
+ 'all_tenants': '1'}
nonexistent_body = self.client.list_servers(**nonexistent_params)
nonexistent_servers = nonexistent_body['servers']
- self.assertIn(test_server['id'], map(lambda x: x['id'], servers))
- self.assertNotIn(test_server['id'],
+ self.assertNotIn(server['id'],
map(lambda x: x['id'], nonexistent_servers))
@decorators.idempotent_id('ee8ae470-db70-474d-b752-690b7892cab1')
diff --git a/tempest/api/compute/admin/test_servers_on_multinodes.py b/tempest/api/compute/admin/test_servers_on_multinodes.py
index 72f4ddc..2e7b07b 100644
--- a/tempest/api/compute/admin/test_servers_on_multinodes.py
+++ b/tempest/api/compute/admin/test_servers_on_multinodes.py
@@ -76,3 +76,38 @@
wait_until='ACTIVE')['id']
host02 = self._get_host(server02)
self.assertNotEqual(self.host01, host02)
+
+ @decorators.idempotent_id('f8bd0867-e459-45f5-ba53-59134552fe04')
+ @testtools.skipUnless(
+ compute.is_scheduler_filter_enabled("ServerGroupAntiAffinityFilter"),
+ 'ServerGroupAntiAffinityFilter is not available.')
+ def test_create_server_with_scheduler_hint_group_anti_affinity(self):
+ """Tests the ServerGroupAntiAffinityFilter
+
+ Creates two servers in an anti-affinity server group and
+ asserts the servers are in the group and on different hosts.
+ """
+ group_id = self.create_test_server_group(
+ policy=['anti-affinity'])['id']
+ hints = {'group': group_id}
+ reservation_id = self.create_test_server(
+ scheduler_hints=hints, wait_until='ACTIVE', min_count=2,
+ return_reservation_id=True)['reservation_id']
+
+ # Get the servers using the reservation_id.
+ servers = self.servers_client.list_servers(
+ detail=True, reservation_id=reservation_id)['servers']
+ self.assertEqual(2, len(servers))
+
+ # Assert the servers are in the group.
+ server_group = self.server_groups_client.show_server_group(
+ group_id)['server_group']
+ hosts = {}
+ for server in servers:
+ self.assertIn(server['id'], server_group['members'])
+ hosts[server['id']] = self._get_host(server['id'])
+
+ # Assert the servers are on different hosts.
+ hostnames = list(hosts.values())
+ self.assertNotEqual(hostnames[0], hostnames[1],
+ 'Servers are on the same host: %s' % hosts)
diff --git a/tempest/api/compute/admin/test_volume_swap.py b/tempest/api/compute/admin/test_volume_swap.py
index 22a5bc4..d715a42 100644
--- a/tempest/api/compute/admin/test_volume_swap.py
+++ b/tempest/api/compute/admin/test_volume_swap.py
@@ -13,11 +13,11 @@
import time
from tempest.api.compute import base
+from tempest.common import 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
@@ -80,7 +80,7 @@
raise lib_exc.TimeoutException(message)
@decorators.idempotent_id('1769f00d-a693-4d67-a631-6a3496773813')
- @test.services('volume')
+ @utils.services('volume')
def test_volume_swap(self):
# Create two volumes.
# NOTE(gmann): Volumes are created before server creation so that
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 746f83a..3340d8c 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -495,12 +495,10 @@
def get_host_other_than(self, server_id):
source_host = self.get_host_for_server(server_id)
- list_hosts_resp = self.os_admin.hosts_client.list_hosts()['hosts']
- hosts = [
- host_record['host_name']
- for host_record in list_hosts_resp
- if host_record['service'] == 'compute'
- ]
+ hypers = self.os_admin.hypervisor_client.list_hypervisors(
+ )['hypervisors']
+ hosts = [hyper['hypervisor_hostname'] for hyper in hypers
+ if hyper['state'] == 'up' and hyper['status'] == 'enabled']
for target_host in hosts:
if source_host != target_host:
diff --git a/tempest/api/compute/flavors/test_flavors_negative.py b/tempest/api/compute/flavors/test_flavors_negative.py
index ebb9d2e..efd4f0e 100644
--- a/tempest/api/compute/flavors/test_flavors_negative.py
+++ b/tempest/api/compute/flavors/test_flavors_negative.py
@@ -19,11 +19,11 @@
from tempest.api.compute import base
from tempest.common import image as common_image
+from tempest.common import utils
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
-from tempest import test
CONF = config.CONF
@@ -43,7 +43,7 @@
'[image-feature-enabled].')
@decorators.attr(type=['negative'])
- @test.services('image')
+ @utils.services('image')
@decorators.idempotent_id('90f0d93a-91c1-450c-91e6-07d18172cefe')
def test_boot_with_low_ram(self):
"""Try boot a vm with lower than min ram
diff --git a/tempest/api/compute/floating_ips/test_floating_ips_actions.py b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
index faa7b5d..9ee0ac9 100644
--- a/tempest/api/compute/floating_ips/test_floating_ips_actions.py
+++ b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
@@ -16,11 +16,11 @@
import testtools
from tempest.api.compute.floating_ips import base
+from tempest.common import utils
from tempest import config
from tempest.lib.common.utils import test_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
-from tempest import test
CONF = config.CONF
@@ -32,6 +32,8 @@
@classmethod
def skip_checks(cls):
super(FloatingIPsTestJSON, cls).skip_checks()
+ if not utils.get_service_list()['network']:
+ raise cls.skipException("network service not enabled.")
if not CONF.network_feature_enabled.floating_ips:
raise cls.skipException("Floating ips are not available")
@@ -62,7 +64,6 @@
super(FloatingIPsTestJSON, cls).resource_cleanup()
@decorators.idempotent_id('f7bfb946-297e-41b8-9e8c-aba8e9bb5194')
- @test.services('network')
def test_allocate_floating_ip(self):
# Positive test:Allocation of a new floating IP to a project
# should be successful
@@ -78,7 +79,6 @@
self.assertIn(floating_ip_details, body)
@decorators.idempotent_id('de45e989-b5ca-4a9b-916b-04a52e7bbb8b')
- @test.services('network')
def test_delete_floating_ip(self):
# Positive test:Deletion of valid floating IP from project
# should be successful
@@ -93,7 +93,6 @@
self.client.wait_for_resource_deletion(floating_ip_body['id'])
@decorators.idempotent_id('307efa27-dc6f-48a0-8cd2-162ce3ef0b52')
- @test.services('network')
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
def test_associate_disassociate_floating_ip(self):
@@ -116,7 +115,6 @@
self.server_id)
@decorators.idempotent_id('6edef4b2-aaf1-4abc-bbe3-993e2561e0fe')
- @test.services('network')
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
def test_associate_already_associated_floating_ip(self):
diff --git a/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py b/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py
index 483bd95..c3d7816 100644
--- a/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py
+++ b/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py
@@ -16,11 +16,11 @@
import testtools
from tempest.api.compute.floating_ips import base
+from tempest.common import utils
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
-from tempest import test
CONF = config.CONF
@@ -30,6 +30,8 @@
@classmethod
def skip_checks(cls):
super(FloatingIPsNegativeTestJSON, cls).skip_checks()
+ if not utils.get_service_list()['network']:
+ raise cls.skipException("network service not enabled.")
if not CONF.network_feature_enabled.floating_ips:
raise cls.skipException("Floating ips are not available")
@@ -58,7 +60,6 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('6e0f059b-e4dd-48fb-8207-06e3bba5b074')
- @test.services('network')
def test_allocate_floating_ip_from_nonexistent_pool(self):
# Negative test:Allocation of a new floating IP from a nonexistent_pool
# to a project should fail
@@ -68,7 +69,6 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('ae1c55a8-552b-44d4-bfb6-2a115a15d0ba')
- @test.services('network')
def test_delete_nonexistent_floating_ip(self):
# Negative test:Deletion of a nonexistent floating IP
# from project should fail
@@ -79,7 +79,6 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('595fa616-1a71-4670-9614-46564ac49a4c')
- @test.services('network')
def test_associate_nonexistent_floating_ip(self):
# Negative test:Association of a non existent floating IP
# to specific server should fail
@@ -90,7 +89,6 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('0a081a66-e568-4e6b-aa62-9587a876dca8')
- @test.services('network')
def test_dissociate_nonexistent_floating_ip(self):
# Negative test:Dissociation of a non existent floating IP should fail
# Dissociating non existent floating IP
@@ -100,7 +98,6 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('804b4fcb-bbf5-412f-925d-896672b61eb3')
- @test.services('network')
def test_associate_ip_to_server_without_passing_floating_ip(self):
# Negative test:Association of empty floating IP to specific server
# should raise NotFound or BadRequest(In case of Nova V2.1) exception.
@@ -110,7 +107,6 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('58a80596-ffb2-11e6-9393-fa163e4fa634')
- @test.services('network')
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
def test_associate_ip_to_server_with_floating_ip(self):
diff --git a/tempest/api/compute/floating_ips/test_list_floating_ips.py b/tempest/api/compute/floating_ips/test_list_floating_ips.py
index 913b992..2314433 100644
--- a/tempest/api/compute/floating_ips/test_list_floating_ips.py
+++ b/tempest/api/compute/floating_ips/test_list_floating_ips.py
@@ -14,9 +14,9 @@
# under the License.
from tempest.api.compute import base
+from tempest.common import utils
from tempest import config
from tempest.lib import decorators
-from tempest import test
CONF = config.CONF
@@ -26,6 +26,8 @@
@classmethod
def skip_checks(cls):
super(FloatingIPDetailsTestJSON, cls).skip_checks()
+ if not utils.get_service_list()['network']:
+ raise cls.skipException("network service not enabled.")
if not CONF.network_feature_enabled.floating_ips:
raise cls.skipException("Floating ips are not available")
@@ -53,7 +55,6 @@
super(FloatingIPDetailsTestJSON, cls).resource_cleanup()
@decorators.idempotent_id('16db31c3-fb85-40c9-bbe2-8cf7b67ff99f')
- @test.services('network')
def test_list_floating_ips(self):
# Positive test:Should return the list of floating IPs
body = self.client.list_floating_ips()['floating_ips']
@@ -64,7 +65,6 @@
self.assertIn(self.floating_ip[i], floating_ips)
@decorators.idempotent_id('eef497e0-8ff7-43c8-85ef-558440574f84')
- @test.services('network')
def test_get_floating_ip_details(self):
# Positive test:Should be able to GET the details of floatingIP
# Creating a floating IP for which details are to be checked
@@ -86,7 +86,6 @@
self.assertEqual(floating_ip_id, body['id'])
@decorators.idempotent_id('df389fc8-56f5-43cc-b290-20eda39854d3')
- @test.services('network')
def test_list_floating_ip_pools(self):
# Positive test:Should return the list of floating IP Pools
floating_ip_pools = self.pools_client.list_floating_ip_pools()
diff --git a/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py b/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py
index b5bbb8c..0ade872 100644
--- a/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py
+++ b/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py
@@ -14,11 +14,11 @@
# under the License.
from tempest.api.compute import base
+from tempest.common import utils
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
-from tempest import test
CONF = config.CONF
@@ -28,6 +28,8 @@
@classmethod
def skip_checks(cls):
super(FloatingIPDetailsNegativeTestJSON, cls).skip_checks()
+ if not utils.get_service_list()['network']:
+ raise cls.skipException("network service not enabled.")
if not CONF.network_feature_enabled.floating_ips:
raise cls.skipException("Floating ips are not available")
@@ -38,7 +40,6 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('7ab18834-4a4b-4f28-a2c5-440579866695')
- @test.services('network')
def test_get_nonexistent_floating_ip_details(self):
# Negative test:Should not be able to GET the details
# of non-existent floating IP
diff --git a/tempest/api/compute/security_groups/base.py b/tempest/api/compute/security_groups/base.py
index 6148e16..54a6da8 100644
--- a/tempest/api/compute/security_groups/base.py
+++ b/tempest/api/compute/security_groups/base.py
@@ -14,9 +14,9 @@
# under the License.
from tempest.api.compute import base
+from tempest.common import utils
from tempest import config
from tempest.lib.common.utils import data_utils
-from tempest import test
CONF = config.CONF
@@ -24,6 +24,12 @@
class BaseSecurityGroupsTest(base.BaseV2ComputeTest):
@classmethod
+ def skip_checks(cls):
+ super(BaseSecurityGroupsTest, cls).skip_checks()
+ if not utils.get_service_list()['network']:
+ raise cls.skipException("network service not enabled.")
+
+ @classmethod
def setup_credentials(cls):
# A network and a subnet will be created for these tests
cls.set_network_resources(network=True, subnet=True)
@@ -32,7 +38,7 @@
@staticmethod
def generate_random_security_group_id():
if (CONF.service_available.neutron and
- test.is_extension_enabled('security-group', 'network')):
+ utils.is_extension_enabled('security-group', 'network')):
return data_utils.rand_uuid()
else:
return data_utils.rand_int_id(start=999)
diff --git a/tempest/api/compute/security_groups/test_security_group_rules.py b/tempest/api/compute/security_groups/test_security_group_rules.py
index 124db0e..4c99ea6 100644
--- a/tempest/api/compute/security_groups/test_security_group_rules.py
+++ b/tempest/api/compute/security_groups/test_security_group_rules.py
@@ -15,7 +15,6 @@
from tempest.api.compute.security_groups import base
from tempest.lib import decorators
-from tempest import test
class SecurityGroupRulesTestJSON(base.BaseSecurityGroupsTest):
@@ -55,7 +54,6 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('850795d7-d4d3-4e55-b527-a774c0123d3a')
- @test.services('network')
def test_security_group_rules_create(self):
# Positive test: Creation of Security Group rule
# should be successful
@@ -73,7 +71,6 @@
self._check_expected_response(rule)
@decorators.idempotent_id('7a01873e-3c38-4f30-80be-31a043cfe2fd')
- @test.services('network')
def test_security_group_rules_create_with_optional_cidr(self):
# Positive test: Creation of Security Group rule
# with optional argument cidr
@@ -96,7 +93,6 @@
self._check_expected_response(rule)
@decorators.idempotent_id('7f5d2899-7705-4d4b-8458-4505188ffab6')
- @test.services('network')
def test_security_group_rules_create_with_optional_group_id(self):
# Positive test: Creation of Security Group rule
# with optional argument group_id
@@ -125,7 +121,6 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('a6154130-5a55-4850-8be4-5e9e796dbf17')
- @test.services('network')
def test_security_group_rules_list(self):
# Positive test: Created Security Group rules should be
# in the list of all rules
@@ -163,7 +158,6 @@
self.assertNotEmpty([i for i in rules if i['id'] == rule2_id])
@decorators.idempotent_id('fc5c5acf-2091-43a6-a6ae-e42760e9ffaf')
- @test.services('network')
def test_security_group_rules_delete_when_peer_group_deleted(self):
# Positive test:rule will delete when peer group deleting
# Creating a Security Group to add rules to it
@@ -178,7 +172,7 @@
ip_protocol=self.ip_protocol,
from_port=self.from_port,
to_port=self.to_port,
- group_id=sg2_id)['security_group_rule']
+ group_id=sg2_id)
# Delete group2
self.security_groups_client.delete_security_group(sg2_id)
diff --git a/tempest/api/compute/security_groups/test_security_group_rules_negative.py b/tempest/api/compute/security_groups/test_security_group_rules_negative.py
index 4efb8b7..8283aae 100644
--- a/tempest/api/compute/security_groups/test_security_group_rules_negative.py
+++ b/tempest/api/compute/security_groups/test_security_group_rules_negative.py
@@ -17,7 +17,6 @@
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
-from tempest import test
class SecurityGroupRulesNegativeTestJSON(base.BaseSecurityGroupsTest):
@@ -29,7 +28,6 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('1d507e98-7951-469b-82c3-23f1e6b8c254')
- @test.services('network')
def test_create_security_group_rule_with_non_existent_id(self):
# Negative test: Creation of Security Group rule should FAIL
# with non existent Parent group id
@@ -46,7 +44,6 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('2244d7e4-adb7-4ecb-9930-2d77e123ce4f')
- @test.services('network')
def test_create_security_group_rule_with_invalid_id(self):
# Negative test: Creation of Security Group rule should FAIL
# with Parent group id which is not integer
@@ -63,7 +60,6 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('8bd56d02-3ffa-4d67-9933-b6b9a01d6089')
- @test.services('network')
def test_create_security_group_rule_duplicate(self):
# Negative test: Create Security Group rule duplicate should fail
# Creating a Security Group to add rule to it
@@ -88,7 +84,6 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('84c81249-9f6e-439c-9bbf-cbb0d2cddbdf')
- @test.services('network')
def test_create_security_group_rule_with_invalid_ip_protocol(self):
# Negative test: Creation of Security Group rule should FAIL
# with invalid ip_protocol
@@ -108,7 +103,6 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('12bbc875-1045-4f7a-be46-751277baedb9')
- @test.services('network')
def test_create_security_group_rule_with_invalid_from_port(self):
# Negative test: Creation of Security Group rule should FAIL
# with invalid from_port
@@ -127,7 +121,6 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('ff88804d-144f-45d1-bf59-dd155838a43a')
- @test.services('network')
def test_create_security_group_rule_with_invalid_to_port(self):
# Negative test: Creation of Security Group rule should FAIL
# with invalid to_port
@@ -146,7 +139,6 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('00296fa9-0576-496a-ae15-fbab843189e0')
- @test.services('network')
def test_create_security_group_rule_with_invalid_port_range(self):
# Negative test: Creation of Security Group rule should FAIL
# with invalid port range.
@@ -165,7 +157,6 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('56fddcca-dbb8-4494-a0db-96e9f869527c')
- @test.services('network')
def test_delete_security_group_rule_with_non_existent_id(self):
# Negative test: Deletion of Security Group rule should be FAIL
# with non existent id
diff --git a/tempest/api/compute/security_groups/test_security_groups.py b/tempest/api/compute/security_groups/test_security_groups.py
index a101a19..62d5bea 100644
--- a/tempest/api/compute/security_groups/test_security_groups.py
+++ b/tempest/api/compute/security_groups/test_security_groups.py
@@ -18,7 +18,6 @@
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
-from tempest import test
class SecurityGroupsTestJSON(base.BaseSecurityGroupsTest):
@@ -30,7 +29,6 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('eb2b087d-633d-4d0d-a7bd-9e6ba35b32de')
- @test.services('network')
def test_security_groups_create_list_delete(self):
# Positive test:Should return the list of Security Groups
# Create 3 Security Groups
@@ -54,15 +52,13 @@
self.client.wait_for_resource_deletion(sg['id'])
# Now check if all the created Security Groups are deleted
fetched_list = self.client.list_security_groups()['security_groups']
- deleted_sgs = \
- [sg for sg in security_group_list if sg in fetched_list]
+ deleted_sgs = [sg for sg in security_group_list if sg in fetched_list]
self.assertFalse(deleted_sgs,
"Failed to delete Security Group %s "
"list" % ', '.join(m_group['name']
for m_group in deleted_sgs))
@decorators.idempotent_id('ecc0da4a-2117-48af-91af-993cca39a615')
- @test.services('network')
def test_security_group_create_get_delete(self):
# Security Group should be created, fetched and deleted
# with char space between name along with
@@ -83,7 +79,6 @@
self.client.wait_for_resource_deletion(securitygroup['id'])
@decorators.idempotent_id('fe4abc0d-83f5-4c50-ad11-57a1127297a2')
- @test.services('network')
def test_server_security_groups(self):
# Checks that security groups may be added and linked to a server
# and not deleted if the server is active.
@@ -125,7 +120,6 @@
self.client.delete_security_group(sg2['id'])
@decorators.idempotent_id('7d4e1d3c-3209-4d6d-b020-986304ebad1f')
- @test.services('network')
def test_update_security_groups(self):
# Update security group name and description
# Create a security group
@@ -144,7 +138,6 @@
self.assertEqual(s_new_des, fetched_group['description'])
@decorators.idempotent_id('79517d60-535a-438f-af3d-e6feab1cbea7')
- @test.services('network')
def test_list_security_groups_by_server(self):
# Create a couple security groups that we will use
# for the server resource this test creates
diff --git a/tempest/api/compute/security_groups/test_security_groups_negative.py b/tempest/api/compute/security_groups/test_security_groups_negative.py
index c4dff15..9c44bb2 100644
--- a/tempest/api/compute/security_groups/test_security_groups_negative.py
+++ b/tempest/api/compute/security_groups/test_security_groups_negative.py
@@ -20,7 +20,6 @@
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
-from tempest import test
CONF = config.CONF
@@ -34,7 +33,6 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('673eaec1-9b3e-48ed-bdf1-2786c1b9661c')
- @test.services('network')
def test_security_group_get_nonexistent_group(self):
# Negative test:Should not be able to GET the details
# of non-existent Security Group
@@ -46,7 +44,6 @@
condition=CONF.service_available.neutron)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('1759c3cb-b0fc-44b7-86ce-c99236be911d')
- @test.services('network')
def test_security_group_create_with_invalid_group_name(self):
# Negative test: Security Group should not be created with group name
# as an empty string/with white spaces/chars more than 255
@@ -69,7 +66,6 @@
condition=CONF.service_available.neutron)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('777b6f14-aca9-4758-9e84-38783cfa58bc')
- @test.services('network')
def test_security_group_create_with_invalid_group_description(self):
# Negative test: Security Group should not be created with description
# longer than 255 chars. Empty description is allowed by the API
@@ -85,7 +81,6 @@
@testtools.skipIf(CONF.service_available.neutron,
"Neutron allows duplicate names for security groups")
@decorators.attr(type=['negative'])
- @test.services('network')
def test_security_group_create_with_duplicate_name(self):
# Negative test:Security Group with duplicate name should not
# be created
@@ -99,7 +94,6 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('36a1629f-c6da-4a26-b8b8-55e7e5d5cd58')
- @test.services('network')
def test_delete_the_default_security_group(self):
# Negative test:Deletion of the "default" Security Group should Fail
default_security_group_id = None
@@ -115,7 +109,6 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('6727c00b-214c-4f9e-9a52-017ac3e98411')
- @test.services('network')
def test_delete_nonexistent_security_group(self):
# Negative test:Deletion of a non-existent Security Group should fail
non_exist_id = self.generate_random_security_group_id()
@@ -124,7 +117,6 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('1438f330-8fa4-4aeb-8a94-37c250106d7f')
- @test.services('network')
def test_delete_security_group_without_passing_id(self):
# Negative test:Deletion of a Security Group with out passing ID
# should Fail
@@ -135,7 +127,6 @@
@testtools.skipIf(CONF.service_available.neutron,
"Neutron does not check the security group ID")
@decorators.attr(type=['negative'])
- @test.services('network')
def test_update_security_group_with_invalid_sg_id(self):
# Update security_group with invalid sg_id should fail
s_name = data_utils.rand_name('sg')
@@ -150,7 +141,6 @@
@testtools.skipIf(CONF.service_available.neutron,
"Neutron does not check the security group name")
@decorators.attr(type=['negative'])
- @test.services('network')
def test_update_security_group_with_invalid_sg_name(self):
# Update security_group with invalid sg_name should fail
securitygroup = self.create_security_group()
@@ -165,7 +155,6 @@
@testtools.skipIf(CONF.service_available.neutron,
"Neutron does not check the security group description")
@decorators.attr(type=['negative'])
- @test.services('network')
def test_update_security_group_with_invalid_sg_des(self):
# Update security_group with invalid sg_des should fail
securitygroup = self.create_security_group()
@@ -178,7 +167,6 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('27edee9c-873d-4da6-a68a-3c256efebe8f')
- @test.services('network')
def test_update_non_existent_security_group(self):
# Update a non-existent Security Group should Fail
non_exist_id = self.generate_random_security_group_id()
diff --git a/tempest/api/compute/servers/test_attach_interfaces.py b/tempest/api/compute/servers/test_attach_interfaces.py
index bfde847..0248c65 100644
--- a/tempest/api/compute/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/servers/test_attach_interfaces.py
@@ -19,12 +19,12 @@
from tempest.api.compute import base
from tempest.common import compute
+from tempest.common import utils
from tempest.common.utils import net_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
@@ -103,7 +103,6 @@
['interfaceAttachment'])
iface = waiters.wait_for_interface_status(
self.interfaces_client, server['id'], iface['port_id'], 'ACTIVE')
- self._check_interface(iface)
return iface
def _test_create_interface_by_network_id(self, server, ifs):
@@ -185,12 +184,11 @@
self.assertEqual(sorted(list1), sorted(list2))
@decorators.idempotent_id('73fe8f02-590d-4bf1-b184-e9ca81065051')
- @test.services('network')
+ @utils.services('network')
def test_create_list_show_delete_interfaces(self):
server, ifs = self._create_server_get_interfaces()
interface_count = len(ifs)
self.assertGreater(interface_count, 0)
- self._check_interface(ifs[0])
try:
iface = self._test_create_interface(server)
@@ -222,13 +220,12 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('c7e0e60b-ee45-43d0-abeb-8596fd42a2f9')
- @test.services('network')
+ @utils.services('network')
def test_add_remove_fixed_ip(self):
# Add and Remove the fixed IP to server.
server, ifs = self._create_server_get_interfaces()
interface_count = len(ifs)
self.assertGreater(interface_count, 0)
- self._check_interface(ifs[0])
network_id = ifs[0]['net_id']
self.servers_client.add_fixed_ip(server['id'], networkId=network_id)
# Remove the fixed IP from server.
@@ -245,7 +242,6 @@
break
self.servers_client.remove_fixed_ip(server['id'], address=fixed_ip)
- @decorators.skip_because(bug='1607714')
@decorators.idempotent_id('2f3a0127-95c7-4977-92d2-bc5aec602fb4')
def test_reassign_port_between_servers(self):
"""Tests the following:
diff --git a/tempest/api/compute/servers/test_create_server.py b/tempest/api/compute/servers/test_create_server.py
index b727ddd..d8ce7ea 100644
--- a/tempest/api/compute/servers/test_create_server.py
+++ b/tempest/api/compute/servers/test_create_server.py
@@ -17,12 +17,11 @@
import testtools
from tempest.api.compute import base
-from tempest.common import compute
+from tempest.common import utils
from tempest.common.utils.linux import remote_client
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
-from tempest import test
CONF = config.CONF
@@ -133,22 +132,6 @@
'hostname "%s" but got "%s".' % (self.name, hostname))
self.assertEqual(self.name.lower(), hostname, msg)
- @decorators.idempotent_id('ed20d3fb-9d1f-4329-b160-543fbd5d9811')
- @testtools.skipUnless(
- compute.is_scheduler_filter_enabled("ServerGroupAffinityFilter"),
- 'ServerGroupAffinityFilter is not available.')
- def test_create_server_with_scheduler_hint_group(self):
- # Create a server with the scheduler hint "group".
- group_id = self.create_test_server_group()['id']
- hints = {'group': group_id}
- server = self.create_test_server(scheduler_hints=hints,
- wait_until='ACTIVE')
-
- # Check a server is in the group
- server_group = (self.server_groups_client.show_server_group(group_id)
- ['server_group'])
- self.assertIn(server['id'], server_group['members'])
-
class ServersTestManualDisk(ServersTestJSON):
disk_config = 'MANUAL'
@@ -168,6 +151,6 @@
@classmethod
def skip_checks(cls):
super(ServersTestBootFromVolume, cls).skip_checks()
- if not test.get_service_list()['volume']:
+ if not utils.get_service_list()['volume']:
msg = "Volume service not enabled."
raise cls.skipException(msg)
diff --git a/tempest/api/compute/servers/test_delete_server.py b/tempest/api/compute/servers/test_delete_server.py
index 2b03b2b..0093752 100644
--- a/tempest/api/compute/servers/test_delete_server.py
+++ b/tempest/api/compute/servers/test_delete_server.py
@@ -17,10 +17,10 @@
from tempest.api.compute import base
from tempest.common import compute
+from tempest.common import utils
from tempest.common import waiters
from tempest import config
from tempest.lib import decorators
-from tempest import test
CONF = config.CONF
@@ -104,7 +104,7 @@
waiters.wait_for_server_termination(self.client, server['id'])
@decorators.idempotent_id('d0f3f0d6-d9b6-4a32-8da4-23015dcab23c')
- @test.services('volume')
+ @utils.services('volume')
def test_delete_server_while_in_attached_volume(self):
# Delete a server while a volume is attached to it
device = '/dev/%s' % CONF.compute.volume_device_name
diff --git a/tempest/api/compute/servers/test_device_tagging.py b/tempest/api/compute/servers/test_device_tagging.py
index 7ee1b02..dbf6713 100644
--- a/tempest/api/compute/servers/test_device_tagging.py
+++ b/tempest/api/compute/servers/test_device_tagging.py
@@ -17,13 +17,13 @@
from oslo_log import log as logging
from tempest.api.compute import base
+from tempest.common import utils
from tempest.common.utils.linux import remote_client
from tempest import config
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
-from tempest import test
CONF = config.CONF
@@ -94,7 +94,7 @@
'other']))
@decorators.idempotent_id('a2e65a6c-66f1-4442-aaa8-498c31778d96')
- @test.services('network', 'volume', 'image')
+ @utils.services('network', 'volume', 'image')
def test_device_tagging(self):
# Create volumes
# The create_volume methods waits for the volumes to be available and
diff --git a/tempest/api/compute/servers/test_list_server_filters.py b/tempest/api/compute/servers/test_list_server_filters.py
index a4ed8e1..14aecfd 100644
--- a/tempest/api/compute/servers/test_list_server_filters.py
+++ b/tempest/api/compute/servers/test_list_server_filters.py
@@ -262,7 +262,7 @@
# so as to ensure only one server is returned.
ip_list = {}
self.s1 = self.client.show_server(self.s1['id'])['server']
- # Get first ip address inspite of v4 or v6
+ # Get first ip address in spite of v4 or v6
ip_addr = self.s1['addresses'][self.fixed_network_name][0]['addr']
ip_list[ip_addr] = self.s1['id']
diff --git a/tempest/api/compute/servers/test_novnc.py b/tempest/api/compute/servers/test_novnc.py
index 90b0665..d9581e3 100644
--- a/tempest/api/compute/servers/test_novnc.py
+++ b/tempest/api/compute/servers/test_novnc.py
@@ -166,7 +166,7 @@
self._validate_novnc_html(body['url'])
# Do the WebSockify HTTP Request to novncproxy to do the RFB connection
self._websocket = compute.create_websocket(body['url'])
- # Validate that we succesfully connected and upgraded to Web Sockets
+ # Validate that we successfully connected and upgraded to Web Sockets
self._validate_websocket_upgrade()
# Validate the RFB Negotiation to determine if a valid VNC session
self._validate_rfb_negotiation()
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index f41c3fb..b5fc39c 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -19,13 +19,14 @@
from tempest.api.compute import base
from tempest.common import compute
+from tempest.common import utils
from tempest.common.utils.linux import remote_client
from tempest.common import waiters
from tempest import config
+from tempest.lib.common import api_version_utils
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
-from tempest import test
CONF = config.CONF
@@ -33,8 +34,6 @@
class ServerActionsTestJSON(base.BaseV2ComputeTest):
- run_ssh = CONF.validation.run_validation
-
def setUp(self):
# NOTE(afazekas): Normally we use the same server with all test cases,
# but if it has an issue, we build a new one
@@ -254,7 +253,7 @@
self.client.start_server(self.server_id)
@decorators.idempotent_id('b68bd8d6-855d-4212-b59b-2e704044dace')
- @test.services('volume')
+ @utils.services('volume')
def test_rebuild_server_with_volume_attached(self):
# create a new volume and attach it to the server
volume = self.create_volume()
@@ -335,7 +334,7 @@
@decorators.idempotent_id('b963d4f1-94b3-4c40-9e97-7b583f46e470')
@testtools.skipUnless(CONF.compute_feature_enabled.snapshot,
'Snapshotting not available, backup not possible.')
- @test.services('image')
+ @utils.services('image')
def test_create_backup(self):
# Positive test:create backup successfully and rotate backups correctly
# create the first and the second backup
@@ -371,7 +370,11 @@
"been successful as it should have been "
"deleted during rotation.", oldest_backup)
- image1_id = data_utils.parse_image_id(resp['location'])
+ if api_version_utils.compare_version_header_to_response(
+ "OpenStack-API-Version", "compute 2.45", resp, "lt"):
+ image1_id = resp['image_id']
+ else:
+ image1_id = data_utils.parse_image_id(resp['location'])
self.addCleanup(_clean_oldest_backup, image1_id)
waiters.wait_for_image_status(glance_client,
image1_id, 'active')
@@ -382,7 +385,11 @@
backup_type='daily',
rotation=2,
name=backup2).response
- image2_id = data_utils.parse_image_id(resp['location'])
+ if api_version_utils.compare_version_header_to_response(
+ "OpenStack-API-Version", "compute 2.45", resp, "lt"):
+ image2_id = resp['image_id']
+ else:
+ image2_id = data_utils.parse_image_id(resp['location'])
self.addCleanup(glance_client.delete_image, image2_id)
waiters.wait_for_image_status(glance_client,
image2_id, 'active')
@@ -421,7 +428,11 @@
backup_type='daily',
rotation=2,
name=backup3).response
- image3_id = data_utils.parse_image_id(resp['location'])
+ if api_version_utils.compare_version_header_to_response(
+ "OpenStack-API-Version", "compute 2.45", resp, "lt"):
+ image3_id = resp['image_id']
+ else:
+ image3_id = data_utils.parse_image_id(resp['location'])
self.addCleanup(glance_client.delete_image, image3_id)
# the first back up should be deleted
waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE')
@@ -520,7 +531,7 @@
@decorators.idempotent_id('77eba8e0-036e-4635-944b-f7a8f3b78dc9')
@testtools.skipUnless(CONF.compute_feature_enabled.shelve,
'Shelve is not available.')
- @test.services('image')
+ @utils.services('image')
def test_shelve_unshelve_server(self):
if CONF.image_feature_enabled.api_v2:
glance_client = self.os_primary.image_client_v2
diff --git a/tempest/api/compute/servers/test_server_addresses.py b/tempest/api/compute/servers/test_server_addresses.py
index 022ceba..f79b05f 100644
--- a/tempest/api/compute/servers/test_server_addresses.py
+++ b/tempest/api/compute/servers/test_server_addresses.py
@@ -14,8 +14,8 @@
# under the License.
from tempest.api.compute import base
+from tempest.common import utils
from tempest.lib import decorators
-from tempest import test
class ServerAddressesTestJSON(base.BaseV2ComputeTest):
@@ -39,7 +39,7 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('6eb718c0-02d9-4d5e-acd1-4e0c269cef39')
- @test.services('network')
+ @utils.services('network')
def test_list_server_addresses(self):
# All public and private addresses for
# a server should be returned
@@ -51,13 +51,10 @@
self.assertNotEmpty(addresses)
for network_addresses in addresses.values():
self.assertNotEmpty(network_addresses)
- for address in network_addresses:
- self.assertTrue(address['addr'])
- self.assertTrue(address['version'])
@decorators.attr(type='smoke')
@decorators.idempotent_id('87bbc374-5538-4f64-b673-2b0e4443cc30')
- @test.services('network')
+ @utils.services('network')
def test_list_server_addresses_by_network(self):
# Providing a network type should filter
# the addresses return by that type
diff --git a/tempest/api/compute/servers/test_server_addresses_negative.py b/tempest/api/compute/servers/test_server_addresses_negative.py
index 76a102b..b2b3cc0 100644
--- a/tempest/api/compute/servers/test_server_addresses_negative.py
+++ b/tempest/api/compute/servers/test_server_addresses_negative.py
@@ -14,9 +14,9 @@
# under the License.
from tempest.api.compute import base
+from tempest.common import utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
-from tempest import test
class ServerAddressesNegativeTestJSON(base.BaseV2ComputeTest):
@@ -38,7 +38,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('02c3f645-2d2e-4417-8525-68c0407d001b')
- @test.services('network')
+ @utils.services('network')
def test_list_server_addresses_invalid_server_id(self):
# List addresses request should fail if server id not in system
self.assertRaises(lib_exc.NotFound, self.client.list_addresses,
@@ -46,7 +46,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('a2ab5144-78c0-4942-a0ed-cc8edccfd9ba')
- @test.services('network')
+ @utils.services('network')
def test_list_server_addresses_by_network_neg(self):
# List addresses by network should fail if network name not valid
self.assertRaises(lib_exc.NotFound,
diff --git a/tempest/api/compute/servers/test_server_group.py b/tempest/api/compute/servers/test_server_group.py
index 69d7897..5286c8f 100644
--- a/tempest/api/compute/servers/test_server_group.py
+++ b/tempest/api/compute/servers/test_server_group.py
@@ -13,10 +13,13 @@
# License for the specific language governing permissions and limitations
# under the License.
+import testtools
+
from tempest.api.compute import base
+from tempest.common import compute
+from tempest.common import utils
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
-from tempest import test
class ServerGroupTestJSON(base.BaseV2ComputeTest):
@@ -30,7 +33,7 @@
@classmethod
def skip_checks(cls):
super(ServerGroupTestJSON, cls).skip_checks()
- if not test.is_extension_enabled('os-server-groups', 'compute'):
+ if not utils.is_extension_enabled('os-server-groups', 'compute'):
msg = "os-server-groups extension is not enabled."
raise cls.skipException(msg)
@@ -106,3 +109,19 @@
# List the server-group
body = self.client.list_server_groups()['server_groups']
self.assertIn(self.created_server_group, body)
+
+ @decorators.idempotent_id('ed20d3fb-9d1f-4329-b160-543fbd5d9811')
+ @testtools.skipUnless(
+ compute.is_scheduler_filter_enabled("ServerGroupAffinityFilter"),
+ 'ServerGroupAffinityFilter is not available.')
+ def test_create_server_with_scheduler_hint_group(self):
+ # Create a server with the scheduler hint "group".
+ hints = {'group': self.created_server_group['id']}
+ server = self.create_test_server(scheduler_hints=hints,
+ wait_until='ACTIVE')
+ self.addCleanup(self.delete_server, server['id'])
+
+ # Check a server is in the group
+ server_group = (self.server_groups_client.show_server_group(
+ self.created_server_group['id'])['server_group'])
+ self.assertIn(server['id'], server_group['members'])
diff --git a/tempest/api/compute/servers/test_server_metadata.py b/tempest/api/compute/servers/test_server_metadata.py
index f77e7d3..fe95018 100644
--- a/tempest/api/compute/servers/test_server_metadata.py
+++ b/tempest/api/compute/servers/test_server_metadata.py
@@ -32,7 +32,7 @@
def setUp(self):
super(ServerMetadataTestJSON, self).setUp()
meta = {'key1': 'value1', 'key2': 'value2'}
- self.client.set_server_metadata(self.server['id'], meta)['metadata']
+ self.client.set_server_metadata(self.server['id'], meta)
@decorators.idempotent_id('479da087-92b3-4dcf-aeb3-fd293b2d14ce')
def test_list_server_metadata(self):
@@ -49,8 +49,7 @@
# The server's metadata should be replaced with the provided values
# Create a new set of metadata for the server
req_metadata = {'meta2': 'data2', 'meta3': 'data3'}
- self.client.set_server_metadata(self.server['id'],
- req_metadata)['metadata']
+ self.client.set_server_metadata(self.server['id'], req_metadata)
# Verify the expected values are correct, and that the
# previous values have been removed
diff --git a/tempest/api/compute/servers/test_server_rescue_negative.py b/tempest/api/compute/servers/test_server_rescue_negative.py
index 5fac433..1260c6b 100644
--- a/tempest/api/compute/servers/test_server_rescue_negative.py
+++ b/tempest/api/compute/servers/test_server_rescue_negative.py
@@ -16,12 +16,12 @@
import testtools
from tempest.api.compute import base
+from tempest.common import utils
from tempest.common import waiters
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
-from tempest import test
CONF = config.CONF
@@ -109,7 +109,7 @@
self.image_ref_alt)
@decorators.idempotent_id('d0ccac79-0091-4cf4-a1ce-26162d0cc55f')
- @test.services('volume')
+ @utils.services('volume')
@decorators.attr(type=['negative'])
def test_rescued_vm_attach_volume(self):
volume = self.create_volume()
@@ -129,7 +129,7 @@
device='/dev/%s' % self.device)
@decorators.idempotent_id('f56e465b-fe10-48bf-b75d-646cda3a8bc9')
- @test.services('volume')
+ @utils.services('volume')
@decorators.attr(type=['negative'])
def test_rescued_vm_detach_volume(self):
volume = self.create_volume()
diff --git a/tempest/api/compute/servers/test_server_tags.py b/tempest/api/compute/servers/test_server_tags.py
index 0370215..8d0a4e3 100644
--- a/tempest/api/compute/servers/test_server_tags.py
+++ b/tempest/api/compute/servers/test_server_tags.py
@@ -16,9 +16,9 @@
import six
from tempest.api.compute import base
+from tempest.common import utils
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
-from tempest import test
class ServerTagsTestJSON(base.BaseV2ComputeTest):
@@ -29,7 +29,7 @@
@classmethod
def skip_checks(cls):
super(ServerTagsTestJSON, cls).skip_checks()
- if not test.is_extension_enabled('os-server-tags', 'compute'):
+ if not utils.is_extension_enabled('os-server-tags', 'compute'):
msg = "os-server-tags extension is not enabled."
raise cls.skipException(msg)
diff --git a/tempest/api/compute/servers/test_servers_negative.py b/tempest/api/compute/servers/test_servers_negative.py
index 764767b..8170b28 100644
--- a/tempest/api/compute/servers/test_servers_negative.py
+++ b/tempest/api/compute/servers/test_servers_negative.py
@@ -19,12 +19,12 @@
from tempest.api.compute import base
from tempest.common import compute
+from tempest.common import utils
from tempest.common import waiters
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
-from tempest import test
CONF = config.CONF
@@ -217,7 +217,7 @@
@decorators.attr(type=['negative'])
@decorators.related_bug('1651064', status_code=500)
- @test.services('volume')
+ @utils.services('volume')
@decorators.idempotent_id('12146ac1-d7df-4928-ad25-b1f99e5286cd')
def test_create_server_invalid_bdm_in_2nd_dict(self):
volume = self.create_volume()
@@ -512,7 +512,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('74085be3-a370-4ca2-bc51-2d0e10e0f573')
- @test.services('volume', 'image')
+ @utils.services('volume', 'image')
def test_create_server_from_non_bootable_volume(self):
# Create a volume
volume = self.create_volume()
diff --git a/tempest/api/compute/servers/test_virtual_interfaces.py b/tempest/api/compute/servers/test_virtual_interfaces.py
index a42b968..90f04ff 100644
--- a/tempest/api/compute/servers/test_virtual_interfaces.py
+++ b/tempest/api/compute/servers/test_virtual_interfaces.py
@@ -17,10 +17,10 @@
import testtools
from tempest.api.compute import base
+from tempest.common import utils
from tempest import config
from tempest.lib import decorators
from tempest.lib import exceptions
-from tempest import test
CONF = config.CONF
@@ -44,7 +44,7 @@
cls.server = cls.create_test_server(wait_until='ACTIVE')
@decorators.idempotent_id('96c4e2ef-5e4d-4d7f-87f5-fed6dca18016')
- @test.services('network')
+ @utils.services('network')
def test_list_virtual_interfaces(self):
# Positive test:Should be able to GET the virtual interfaces list
# for a given server_id
@@ -56,11 +56,11 @@
self.client.list_virtual_interfaces(self.server['id'])
else:
output = self.client.list_virtual_interfaces(self.server['id'])
- virt_ifaces = output
- self.assertNotEmpty(virt_ifaces['virtual_interfaces'],
+ virt_ifaces = output['virtual_interfaces']
+ self.assertNotEmpty(virt_ifaces,
'Expected virtual interfaces, got 0 '
'interfaces.')
- for virt_iface in virt_ifaces['virtual_interfaces']:
+ for virt_iface in virt_ifaces:
mac_address = virt_iface['mac_address']
self.assertTrue(netaddr.valid_mac(mac_address),
"Invalid mac address detected. mac address: %s"
diff --git a/tempest/api/compute/servers/test_virtual_interfaces_negative.py b/tempest/api/compute/servers/test_virtual_interfaces_negative.py
index 173784a..20923a8 100644
--- a/tempest/api/compute/servers/test_virtual_interfaces_negative.py
+++ b/tempest/api/compute/servers/test_virtual_interfaces_negative.py
@@ -14,10 +14,10 @@
# under the License.
from tempest.api.compute import base
+from tempest.common import utils
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
-from tempest import test
class VirtualInterfacesNegativeTestJSON(base.BaseV2ComputeTest):
@@ -35,7 +35,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('64ebd03c-1089-4306-93fa-60f5eb5c803c')
- @test.services('network')
+ @utils.services('network')
def test_list_virtual_interfaces_invalid_server_id(self):
# Negative test: Should not be able to GET virtual interfaces
# for an invalid server_id
diff --git a/tempest/api/compute/test_extensions.py b/tempest/api/compute/test_extensions.py
index 42e13bd..34faf5f 100644
--- a/tempest/api/compute/test_extensions.py
+++ b/tempest/api/compute/test_extensions.py
@@ -16,9 +16,9 @@
from oslo_log import log as logging
from tempest.api.compute import base
+from tempest.common import utils
from tempest import config
from tempest.lib import decorators
-from tempest import test
CONF = config.CONF
@@ -26,7 +26,7 @@
LOG = logging.getLogger(__name__)
-class ExtensionsTestJSON(base.BaseV2ComputeTest):
+class ExtensionsTest(base.BaseV2ComputeTest):
@decorators.idempotent_id('3bb27738-b759-4e0d-a5fa-37d7a6df07d1')
def test_list_extensions(self):
@@ -48,7 +48,7 @@
raise self.skipException('There are not any extensions configured')
@decorators.idempotent_id('05762f39-bdfa-4cdb-9b46-b78f8e78e2fd')
- @test.requires_ext(extension='os-consoles', service='compute')
+ @utils.requires_ext(extension='os-consoles', service='compute')
def test_get_extension(self):
# get the specified extensions
extension = self.extensions_client.show_extension('os-consoles')
diff --git a/tempest/api/compute/test_quotas.py b/tempest/api/compute/test_quotas.py
index 9d83ee1..7cf90ae 100644
--- a/tempest/api/compute/test_quotas.py
+++ b/tempest/api/compute/test_quotas.py
@@ -15,8 +15,8 @@
from tempest.api.compute import base
from tempest.common import tempest_fixtures as fixtures
+from tempest.common import utils
from tempest.lib import decorators
-from tempest import test
class QuotasTestJSON(base.BaseV2ComputeTest):
@@ -24,7 +24,7 @@
@classmethod
def skip_checks(cls):
super(QuotasTestJSON, cls).skip_checks()
- if not test.is_extension_enabled('os-quota-sets', 'compute'):
+ if not utils.is_extension_enabled('os-quota-sets', 'compute'):
msg = "quotas extension not enabled."
raise cls.skipException(msg)
diff --git a/tempest/api/compute/test_tenant_networks.py b/tempest/api/compute/test_tenant_networks.py
index 18c5d38..b55e2c0 100644
--- a/tempest/api/compute/test_tenant_networks.py
+++ b/tempest/api/compute/test_tenant_networks.py
@@ -13,8 +13,8 @@
# under the License.
from tempest.api.compute import base
+from tempest.common import utils
from tempest.lib import decorators
-from tempest import test
class ComputeTenantNetworksTest(base.BaseV2ComputeTest):
@@ -31,7 +31,7 @@
super(ComputeTenantNetworksTest, cls).setup_credentials()
@decorators.idempotent_id('edfea98e-bbe3-4c7a-9739-87b986baff26')
- @test.services('network')
+ @utils.services('network')
def test_list_show_tenant_networks(self):
# Fetch all networks that are visible to the tenant: this may include
# shared and external networks
diff --git a/tempest/api/compute/volumes/test_attach_volume.py b/tempest/api/compute/volumes/test_attach_volume.py
index 502bc1b..e0fed58 100644
--- a/tempest/api/compute/volumes/test_attach_volume.py
+++ b/tempest/api/compute/volumes/test_attach_volume.py
@@ -13,8 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-import testtools
-
from tempest.api.compute import base
from tempest.common import compute
from tempest.common.utils.linux import remote_client
@@ -143,6 +141,10 @@
self.assertEqual(server['id'], body['serverId'])
self.assertEqual(attachment['volumeId'], body['volumeId'])
self.assertEqual(attachment['id'], body['id'])
+ self.servers_client.detach_volume(server['id'],
+ attachment['volumeId'])
+ waiters.wait_for_volume_resource_status(
+ self.volumes_client, attachment['volumeId'], 'available')
class AttachVolumeShelveTestJSON(AttachVolumeTestJSON):
@@ -155,6 +157,12 @@
min_microversion = '2.20'
max_microversion = 'latest'
+ @classmethod
+ def skip_checks(cls):
+ super(AttachVolumeShelveTestJSON, cls).skip_checks()
+ if not CONF.compute_feature_enabled.shelve:
+ raise cls.skipException('Shelve is not available.')
+
def _count_volumes(self, server):
# Count number of volumes on an instance
volumes = 0
@@ -202,8 +210,6 @@
self.assertEqual(number_of_volumes, counted_volumes)
@decorators.idempotent_id('13a940b6-3474-4c3c-b03f-29b89112bfee')
- @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
- 'Shelve is not available.')
def test_attach_volume_shelved_or_offload_server(self):
# Create server, count number of volumes on it, shelve
# server and attach pre-created volume to shelved server
@@ -229,8 +235,6 @@
self.assertIsNotNone(volume_attachment['device'])
@decorators.idempotent_id('b54e86dd-a070-49c4-9c07-59ae6dae15aa')
- @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
- 'Shelve is not available.')
def test_detach_volume_shelved_or_offload_server(self):
# Count number of volumes on instance, shelve
# server and attach pre-created volume to shelved server
diff --git a/tempest/api/compute/volumes/test_volume_snapshots.py b/tempest/api/compute/volumes/test_volume_snapshots.py
index 0f436eb..b8ca81d 100644
--- a/tempest/api/compute/volumes/test_volume_snapshots.py
+++ b/tempest/api/compute/volumes/test_volume_snapshots.py
@@ -13,8 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-import testtools
-
from tempest.api.compute import base
from tempest.common import waiters
from tempest import config
@@ -38,6 +36,9 @@
if not CONF.service_available.cinder:
skip_msg = ("%s skipped as Cinder is not available" % cls.__name__)
raise cls.skipException(skip_msg)
+ if not CONF.volume_feature_enabled.snapshot:
+ skip_msg = ("Cinder volume snapshots are disabled")
+ raise cls.skipException(skip_msg)
@classmethod
def setup_clients(cls):
@@ -46,8 +47,6 @@
cls.snapshots_client = cls.snapshots_extensions_client
@decorators.idempotent_id('cd4ec87d-7825-450d-8040-6e2068f2da8f')
- @testtools.skipUnless(CONF.volume_feature_enabled.snapshot,
- 'Cinder volume snapshots are disabled')
def test_volume_snapshot_create_get_list_delete(self):
volume = self.create_volume()
self.addCleanup(self.delete_volume, volume['id'])
diff --git a/tempest/api/identity/admin/v3/test_domains_negative.py b/tempest/api/identity/admin/v3/test_domains_negative.py
index 1a0b851..56f7d32 100644
--- a/tempest/api/identity/admin/v3/test_domains_negative.py
+++ b/tempest/api/identity/admin/v3/test_domains_negative.py
@@ -20,7 +20,6 @@
class DomainsNegativeTestJSON(base.BaseIdentityV3AdminTest):
- _interface = 'json'
@decorators.attr(type=['negative', 'gate'])
@decorators.idempotent_id('1f3fbff5-4e44-400d-9ca1-d953f05f609b')
diff --git a/tempest/api/identity/admin/v3/test_groups.py b/tempest/api/identity/admin/v3/test_groups.py
index 4bc987f..17db3ea 100644
--- a/tempest/api/identity/admin/v3/test_groups.py
+++ b/tempest/api/identity/admin/v3/test_groups.py
@@ -14,9 +14,12 @@
# under the License.
from tempest.api.identity import base
+from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
+CONF = config.CONF
+
class GroupsV3TestJSON(base.BaseIdentityV3AdminTest):
@@ -130,7 +133,14 @@
self.addCleanup(self.groups_client.delete_group, group['id'])
group_ids.append(group['id'])
# List and Verify Groups
- body = self.groups_client.list_groups()['groups']
+ # When domain specific drivers are enabled the operations
+ # of listing all users and listing all groups are not supported,
+ # they need a domain filter to be specified
+ if CONF.identity_feature_enabled.domain_specific_drivers:
+ body = self.groups_client.list_groups(
+ domain_id=self.domain['id'])['groups']
+ else:
+ body = self.groups_client.list_groups()['groups']
for g in body:
fetched_ids.append(g['id'])
missing_groups = [g for g in group_ids if g not in fetched_ids]
diff --git a/tempest/api/identity/admin/v3/test_inherits.py b/tempest/api/identity/admin/v3/test_inherits.py
index 49b6585..8b687cd 100644
--- a/tempest/api/identity/admin/v3/test_inherits.py
+++ b/tempest/api/identity/admin/v3/test_inherits.py
@@ -11,22 +11,22 @@
# under the License.
from tempest.api.identity import base
+from tempest.common import utils
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
-from tempest import test
-class BaseInheritsV3Test(base.BaseIdentityV3AdminTest):
+class InheritsV3TestJSON(base.BaseIdentityV3AdminTest):
@classmethod
def skip_checks(cls):
- super(BaseInheritsV3Test, cls).skip_checks()
- if not test.is_extension_enabled('OS-INHERIT', 'identity'):
+ super(InheritsV3TestJSON, cls).skip_checks()
+ if not utils.is_extension_enabled('OS-INHERIT', 'identity'):
raise cls.skipException("Inherits aren't enabled")
@classmethod
def resource_setup(cls):
- super(BaseInheritsV3Test, cls).resource_setup()
+ super(InheritsV3TestJSON, cls).resource_setup()
u_name = data_utils.rand_name('user-')
u_desc = '%s description' % u_name
u_email = '%s@testmail.tm' % u_name
@@ -51,15 +51,12 @@
cls.projects_client.delete_project(cls.project['id'])
cls.domains_client.update_domain(cls.domain['id'], enabled=False)
cls.domains_client.delete_domain(cls.domain['id'])
- super(BaseInheritsV3Test, cls).resource_cleanup()
+ super(InheritsV3TestJSON, cls).resource_cleanup()
def _list_assertions(self, body, fetched_role_ids, role_id):
self.assertEqual(len(body), 1)
self.assertIn(role_id, fetched_role_ids)
-
-class InheritsV3TestJSON(BaseInheritsV3Test):
-
@decorators.idempotent_id('4e6f0366-97c8-423c-b2be-41eae6ac91c8')
def test_inherit_assign_list_check_revoke_roles_on_domains_user(self):
# Create role
diff --git a/tempest/api/identity/admin/v3/test_list_users.py b/tempest/api/identity/admin/v3/test_list_users.py
index 47a3580..506c729 100644
--- a/tempest/api/identity/admin/v3/test_list_users.py
+++ b/tempest/api/identity/admin/v3/test_list_users.py
@@ -14,9 +14,12 @@
# under the License.
from tempest.api.identity import base
+from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
+CONF = config.CONF
+
class UsersV3TestJSON(base.BaseIdentityV3AdminTest):
@@ -82,6 +85,11 @@
def test_list_users_with_name(self):
# List users with name
params = {'name': self.domain_enabled_user['name']}
+ # When domain specific drivers are enabled the operations
+ # of listing all users and listing all groups are not supported,
+ # they need a domain filter to be specified
+ if CONF.identity_feature_enabled.domain_specific_drivers:
+ params['domain_id'] = self.domain_enabled_user['domain_id']
self._list_users_with_params(params, 'name',
self.domain_enabled_user,
self.non_domain_enabled_user)
@@ -89,7 +97,18 @@
@decorators.idempotent_id('b30d4651-a2ea-4666-8551-0c0e49692635')
def test_list_users(self):
# List users
- body = self.users_client.list_users()['users']
+ # When domain specific drivers are enabled the operations
+ # of listing all users and listing all groups are not supported,
+ # they need a domain filter to be specified
+ if CONF.identity_feature_enabled.domain_specific_drivers:
+ body_enabled_user = self.users_client.list_users(
+ domain_id=self.domain_enabled_user['domain_id'])['users']
+ body_non_enabled_user = self.users_client.list_users(
+ domain_id=self.non_domain_enabled_user['domain_id'])['users']
+ body = (body_enabled_user + body_non_enabled_user)
+ else:
+ body = self.users_client.list_users()['users']
+
fetched_ids = [u['id'] for u in body]
missing_users = [u['id'] for u in self.users
if u['id'] not in fetched_ids]
diff --git a/tempest/api/identity/admin/v3/test_tokens.py b/tempest/api/identity/admin/v3/test_tokens.py
index 5c3cd26..6343ea8 100644
--- a/tempest/api/identity/admin/v3/test_tokens.py
+++ b/tempest/api/identity/admin/v3/test_tokens.py
@@ -161,16 +161,14 @@
manager_project_id]
# Get available project scopes
- available_projects =\
- self.client.list_auth_projects()['projects']
+ available_projects = self.client.list_auth_projects()['projects']
# create list to save fetched project's id
fetched_project_ids = [i['id'] for i in available_projects]
# verifying the project ids in list
missing_project_ids = \
- [p for p in assigned_project_ids
- if p not in fetched_project_ids]
+ [p for p in assigned_project_ids if p not in fetched_project_ids]
self.assertEmpty(missing_project_ids,
"Failed to find project_id %s in fetched list" %
', '.join(missing_project_ids))
diff --git a/tempest/api/identity/admin/v3/test_trusts.py b/tempest/api/identity/admin/v3/test_trusts.py
index 850e549..2530072 100644
--- a/tempest/api/identity/admin/v3/test_trusts.py
+++ b/tempest/api/identity/admin/v3/test_trusts.py
@@ -26,25 +26,27 @@
CONF = config.CONF
-class BaseTrustsV3Test(base.BaseIdentityV3AdminTest):
+class TrustsV3TestJSON(base.BaseIdentityV3AdminTest):
@classmethod
def skip_checks(cls):
- super(BaseTrustsV3Test, cls).skip_checks()
+ super(TrustsV3TestJSON, cls).skip_checks()
if not CONF.identity_feature_enabled.trust:
raise cls.skipException("Trusts aren't enabled")
def setUp(self):
- super(BaseTrustsV3Test, self).setUp()
+ super(TrustsV3TestJSON, self).setUp()
# Use alt_username as the trustee
self.trust_id = None
+ self.create_trustor_and_roles()
+ self.addCleanup(self.cleanup_user_and_roles)
def tearDown(self):
if self.trust_id:
# Do the delete in tearDown not addCleanup - we want the test to
# fail in the event there is a bug which causes undeletable trusts
self.delete_trust()
- super(BaseTrustsV3Test, self).tearDown()
+ super(TrustsV3TestJSON, self).tearDown()
def create_trustor_and_roles(self):
# create a project that trusts will be granted on
@@ -193,14 +195,6 @@
self.trust_id)
self.trust_id = None
-
-class TrustsV3TestJSON(BaseTrustsV3Test):
-
- def setUp(self):
- super(TrustsV3TestJSON, self).setUp()
- self.create_trustor_and_roles()
- self.addCleanup(self.cleanup_user_and_roles)
-
@decorators.idempotent_id('5a0a91a4-baef-4a14-baba-59bf4d7fcace')
def test_trust_impersonate(self):
# Test case to check we can create, get and delete a trust
diff --git a/tempest/api/identity/v2/test_ec2_credentials.py b/tempest/api/identity/v2/test_ec2_credentials.py
index 599b784..237e728 100644
--- a/tempest/api/identity/v2/test_ec2_credentials.py
+++ b/tempest/api/identity/v2/test_ec2_credentials.py
@@ -14,9 +14,9 @@
# under the License.
from tempest.api.identity import base
+from tempest.common import utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
-from tempest import test
class EC2CredentialsTest(base.BaseIdentityV2Test):
@@ -24,7 +24,7 @@
@classmethod
def skip_checks(cls):
super(EC2CredentialsTest, cls).skip_checks()
- if not test.is_extension_enabled('OS-EC2', 'identity'):
+ if not utils.is_extension_enabled('OS-EC2', 'identity'):
msg = "OS-EC2 identity extension not enabled."
raise cls.skipException(msg)
diff --git a/tempest/api/identity/v3/test_projects.py b/tempest/api/identity/v3/test_projects.py
index 0ae35ea..bbb4013 100644
--- a/tempest/api/identity/v3/test_projects.py
+++ b/tempest/api/identity/v3/test_projects.py
@@ -24,8 +24,7 @@
@decorators.idempotent_id('86128d46-e170-4644-866a-cc487f699e1d')
def test_list_projects_returns_only_authorized_projects(self):
- alt_project_name =\
- self.os_alt.credentials.project_name
+ alt_project_name = self.os_alt.credentials.project_name
resp = self.non_admin_users_client.list_user_projects(
self.os_primary.credentials.user_id)
diff --git a/tempest/api/image/v2/test_images.py b/tempest/api/image/v2/test_images.py
index 2e68efd..c846f88 100644
--- a/tempest/api/image/v2/test_images.py
+++ b/tempest/api/image/v2/test_images.py
@@ -119,7 +119,7 @@
# Update Image
new_image_name = data_utils.rand_name('new-image')
- body = self.client.update_image(image['id'], [
+ self.client.update_image(image['id'], [
dict(replace='/name', value=new_image_name)])
# Verifying updating
diff --git a/tempest/api/network/admin/test_agent_management.py b/tempest/api/network/admin/test_agent_management.py
index 7304db9..5068fc4 100644
--- a/tempest/api/network/admin/test_agent_management.py
+++ b/tempest/api/network/admin/test_agent_management.py
@@ -14,8 +14,8 @@
from tempest.api.network import base
from tempest.common import tempest_fixtures as fixtures
+from tempest.common import utils
from tempest.lib import decorators
-from tempest import test
class AgentManagementTestJSON(base.BaseAdminNetworkTest):
@@ -23,7 +23,7 @@
@classmethod
def skip_checks(cls):
super(AgentManagementTestJSON, cls).skip_checks()
- if not test.is_extension_enabled('agent', 'network'):
+ if not utils.is_extension_enabled('agent', 'network'):
msg = "agent extension not enabled."
raise cls.skipException(msg)
diff --git a/tempest/api/network/admin/test_dhcp_agent_scheduler.py b/tempest/api/network/admin/test_dhcp_agent_scheduler.py
index 485c8f5..8315c5d 100644
--- a/tempest/api/network/admin/test_dhcp_agent_scheduler.py
+++ b/tempest/api/network/admin/test_dhcp_agent_scheduler.py
@@ -13,8 +13,8 @@
# under the License.
from tempest.api.network import base
+from tempest.common import utils
from tempest.lib import decorators
-from tempest import test
class DHCPAgentSchedulersTestJSON(base.BaseAdminNetworkTest):
@@ -22,7 +22,7 @@
@classmethod
def skip_checks(cls):
super(DHCPAgentSchedulersTestJSON, cls).skip_checks()
- if not test.is_extension_enabled('dhcp_agent_scheduler', 'network'):
+ if not utils.is_extension_enabled('dhcp_agent_scheduler', 'network'):
msg = "dhcp_agent_scheduler extension not enabled."
raise cls.skipException(msg)
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 7ee819e..5aa337c 100644
--- a/tempest/api/network/admin/test_floating_ips_admin_actions.py
+++ b/tempest/api/network/admin/test_floating_ips_admin_actions.py
@@ -14,9 +14,9 @@
# under the License.
from tempest.api.network import base
+from tempest.common import utils
from tempest import config
from tempest.lib import decorators
-from tempest import test
CONF = config.CONF
@@ -28,7 +28,7 @@
@classmethod
def skip_checks(cls):
super(FloatingIPAdminTestJSON, cls).skip_checks()
- if not test.is_extension_enabled('router', 'network'):
+ if not utils.is_extension_enabled('router', 'network'):
msg = "router extension not enabled."
raise cls.skipException(msg)
if not CONF.network.public_network_id:
diff --git a/tempest/api/network/admin/test_l3_agent_scheduler.py b/tempest/api/network/admin/test_l3_agent_scheduler.py
index 85b2472..1a7b0ec 100644
--- a/tempest/api/network/admin/test_l3_agent_scheduler.py
+++ b/tempest/api/network/admin/test_l3_agent_scheduler.py
@@ -13,10 +13,10 @@
# under the License.
from tempest.api.network import base
+from tempest.common import utils
from tempest import config
from tempest.lib import decorators
from tempest.lib import exceptions
-from tempest import test
CONF = config.CONF
AGENT_TYPE = 'L3 agent'
@@ -41,7 +41,7 @@
@classmethod
def skip_checks(cls):
super(L3AgentSchedulerTestJSON, cls).skip_checks()
- if not test.is_extension_enabled('l3_agent_scheduler', 'network'):
+ if not utils.is_extension_enabled('l3_agent_scheduler', 'network'):
msg = "L3 Agent Scheduler Extension not enabled."
raise cls.skipException(msg)
diff --git a/tempest/api/network/admin/test_metering_extensions.py b/tempest/api/network/admin/test_metering_extensions.py
index 21a7ab4..fd86782 100644
--- a/tempest/api/network/admin/test_metering_extensions.py
+++ b/tempest/api/network/admin/test_metering_extensions.py
@@ -13,9 +13,9 @@
# under the License.
from tempest.api.network import base
+from tempest.common import utils
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
-from tempest import test
class MeteringTestJSON(base.BaseAdminNetworkTest):
@@ -28,7 +28,7 @@
@classmethod
def skip_checks(cls):
super(MeteringTestJSON, cls).skip_checks()
- if not test.is_extension_enabled('metering', 'network'):
+ if not utils.is_extension_enabled('metering', 'network'):
msg = "metering extension not enabled."
raise cls.skipException(msg)
diff --git a/tempest/api/network/admin/test_negative_quotas.py b/tempest/api/network/admin/test_negative_quotas.py
index 21688d2..6849653 100644
--- a/tempest/api/network/admin/test_negative_quotas.py
+++ b/tempest/api/network/admin/test_negative_quotas.py
@@ -14,9 +14,9 @@
# under the License.
from tempest.api.network import base
+from tempest.common import utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
-from tempest import test
class QuotasNegativeTest(base.BaseAdminNetworkTest):
@@ -35,7 +35,7 @@
@classmethod
def skip_checks(cls):
super(QuotasNegativeTest, cls).skip_checks()
- if not test.is_extension_enabled('quotas', 'network'):
+ if not utils.is_extension_enabled('quotas', 'network'):
msg = "quotas extension not enabled."
raise cls.skipException(msg)
diff --git a/tempest/api/network/admin/test_quotas.py b/tempest/api/network/admin/test_quotas.py
index aa8b2dc..f69d7c5 100644
--- a/tempest/api/network/admin/test_quotas.py
+++ b/tempest/api/network/admin/test_quotas.py
@@ -14,10 +14,10 @@
# under the License.
from tempest.api.network import base
+from tempest.common import utils
from tempest.lib.common.utils import data_utils
from tempest.lib.common.utils import test_utils
from tempest.lib import decorators
-from tempest import test
class QuotasTest(base.BaseAdminNetworkTest):
@@ -38,7 +38,7 @@
@classmethod
def skip_checks(cls):
super(QuotasTest, cls).skip_checks()
- if not test.is_extension_enabled('quotas', 'network'):
+ if not utils.is_extension_enabled('quotas', 'network'):
msg = "quotas extension not enabled."
raise cls.skipException(msg)
diff --git a/tempest/api/network/admin/test_routers.py b/tempest/api/network/admin/test_routers.py
index f180cda..c97efe9 100644
--- a/tempest/api/network/admin/test_routers.py
+++ b/tempest/api/network/admin/test_routers.py
@@ -16,10 +16,10 @@
import testtools
from tempest.api.network import base
+from tempest.common import utils
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
-from tempest import test
CONF = config.CONF
@@ -57,7 +57,7 @@
@classmethod
def skip_checks(cls):
super(RoutersAdminTest, cls).skip_checks()
- if not test.is_extension_enabled('router', 'network'):
+ if not utils.is_extension_enabled('router', 'network'):
msg = "router extension not enabled."
raise cls.skipException(msg)
@@ -79,7 +79,7 @@
self.assertEqual(project_id, create_body['router']['tenant_id'])
@decorators.idempotent_id('847257cc-6afd-4154-b8fb-af49f5670ce8')
- @test.requires_ext(extension='ext-gw-mode', service='network')
+ @utils.requires_ext(extension='ext-gw-mode', service='network')
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
def test_create_router_with_default_snat_value(self):
@@ -91,7 +91,7 @@
'enable_snat': True})
@decorators.idempotent_id('ea74068d-09e9-4fd7-8995-9b6a1ace920f')
- @test.requires_ext(extension='ext-gw-mode', service='network')
+ @utils.requires_ext(extension='ext-gw-mode', service='network')
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
def test_create_router_with_snat_explicit(self):
@@ -153,7 +153,7 @@
self._verify_gateway_port(router['id'])
@decorators.idempotent_id('b386c111-3b21-466d-880c-5e72b01e1a33')
- @test.requires_ext(extension='ext-gw-mode', service='network')
+ @utils.requires_ext(extension='ext-gw-mode', service='network')
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
def test_update_router_set_gateway_with_snat_explicit(self):
@@ -170,7 +170,7 @@
self._verify_gateway_port(router['id'])
@decorators.idempotent_id('96536bc7-8262-4fb2-9967-5c46940fa279')
- @test.requires_ext(extension='ext-gw-mode', service='network')
+ @utils.requires_ext(extension='ext-gw-mode', service='network')
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
def test_update_router_set_gateway_without_snat(self):
@@ -202,7 +202,7 @@
self.assertFalse(list_body['ports'])
@decorators.idempotent_id('f2faf994-97f4-410b-a831-9bc977b64374')
- @test.requires_ext(extension='ext-gw-mode', service='network')
+ @utils.requires_ext(extension='ext-gw-mode', service='network')
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
def test_update_router_reset_gateway_without_snat(self):
diff --git a/tempest/api/network/admin/test_routers_dvr.py b/tempest/api/network/admin/test_routers_dvr.py
index b6772b1..93478e6 100644
--- a/tempest/api/network/admin/test_routers_dvr.py
+++ b/tempest/api/network/admin/test_routers_dvr.py
@@ -16,9 +16,9 @@
import testtools
from tempest.api.network import base
+from tempest.common import utils
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
-from tempest import test
class RoutersTestDVR(base.BaseAdminNetworkTest):
@@ -27,7 +27,7 @@
def skip_checks(cls):
super(RoutersTestDVR, cls).skip_checks()
for ext in ['router', 'dvr']:
- if not test.is_extension_enabled(ext, 'network'):
+ if not utils.is_extension_enabled(ext, 'network'):
msg = "%s extension not enabled." % ext
raise cls.skipException(msg)
# The check above will pass if api_extensions=all, which does
@@ -87,7 +87,7 @@
self.assertFalse(router['router']['distributed'])
@decorators.idempotent_id('acd43596-c1fb-439d-ada8-31ad48ae3c2e')
- @testtools.skipUnless(test.is_extension_enabled('l3-ha', 'network'),
+ @testtools.skipUnless(utils.is_extension_enabled('l3-ha', 'network'),
'HA routers are not available.')
def test_centralized_router_update_to_dvr(self):
"""Test centralized router update
diff --git a/tempest/api/network/admin/test_routers_negative.py b/tempest/api/network/admin/test_routers_negative.py
index f350a15..9356bcc 100644
--- a/tempest/api/network/admin/test_routers_negative.py
+++ b/tempest/api/network/admin/test_routers_negative.py
@@ -16,10 +16,10 @@
import testtools
from tempest.api.network import base
+from tempest.common import utils
from tempest import config
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
-from tempest import test
CONF = config.CONF
@@ -29,13 +29,13 @@
@classmethod
def skip_checks(cls):
super(RoutersAdminNegativeTest, cls).skip_checks()
- if not test.is_extension_enabled('router', 'network'):
+ if not utils.is_extension_enabled('router', 'network'):
msg = "router extension not enabled."
raise cls.skipException(msg)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('7101cc02-058a-11e7-93e1-fa163e4fa634')
- @test.requires_ext(extension='ext-gw-mode', service='network')
+ @utils.requires_ext(extension='ext-gw-mode', service='network')
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
def test_router_set_gateway_used_ip_returns_409(self):
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index 6bec0d7..8308e34 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -96,6 +96,12 @@
cls.metering_labels = []
cls.metering_label_rules = []
cls.ethertype = "IPv" + str(cls._ip_version)
+ if cls._ip_version == 4:
+ cls.cidr = netaddr.IPNetwork(CONF.network.project_network_cidr)
+ cls.mask_bits = CONF.network.project_network_mask_bits
+ elif cls._ip_version == 6:
+ cls.cidr = netaddr.IPNetwork(CONF.network.project_network_v6_cidr)
+ cls.mask_bits = CONF.network.project_network_v6_mask_bits
@classmethod
def resource_cleanup(cls):
diff --git a/tempest/api/network/test_allowed_address_pair.py b/tempest/api/network/test_allowed_address_pair.py
index a90e4bf..3075047 100644
--- a/tempest/api/network/test_allowed_address_pair.py
+++ b/tempest/api/network/test_allowed_address_pair.py
@@ -13,13 +13,12 @@
# License for the specific language governing permissions and limitations
# under the License.
-import netaddr
import six
from tempest.api.network import base
+from tempest.common import utils
from tempest import config
from tempest.lib import decorators
-from tempest import test
CONF = config.CONF
@@ -44,7 +43,7 @@
@classmethod
def skip_checks(cls):
super(AllowedAddressPairTestJSON, cls).skip_checks()
- if not test.is_extension_enabled('allowed-address-pairs', 'network'):
+ if not utils.is_extension_enabled('allowed-address-pairs', 'network'):
msg = "Allowed Address Pairs extension not enabled."
raise cls.skipException(msg)
@@ -103,8 +102,7 @@
@decorators.idempotent_id('4d6d178f-34f6-4bff-a01c-0a2f8fe909e4')
def test_update_port_with_cidr_address_pair(self):
# Update allowed address pair with cidr
- cidr = str(netaddr.IPNetwork(CONF.network.project_network_cidr))
- self._update_port_with_address(cidr)
+ self._update_port_with_address(str(self.cidr))
@decorators.idempotent_id('b3f20091-6cd5-472b-8487-3516137df933')
def test_update_port_with_multiple_ip_mac_address_pair(self):
diff --git a/tempest/api/network/test_extensions.py b/tempest/api/network/test_extensions.py
index 014d064..4804ada 100644
--- a/tempest/api/network/test_extensions.py
+++ b/tempest/api/network/test_extensions.py
@@ -15,8 +15,8 @@
from tempest.api.network import base
+from tempest.common import utils
from tempest.lib import decorators
-from tempest import test
class ExtensionsTestJSON(base.BaseNetworkTest):
@@ -40,7 +40,7 @@
'allowed-address-pairs', 'extra_dhcp_opt',
'metering', 'dvr']
expected_alias = [ext for ext in expected_alias if
- test.is_extension_enabled(ext, 'network')]
+ utils.is_extension_enabled(ext, 'network')]
actual_alias = list()
extensions = self.network_extensions_client.list_extensions()
list_extensions = extensions['extensions']
@@ -66,5 +66,5 @@
# of extensions returned, but only for those that have been
# enabled via configuration
for e in expected_alias:
- if test.is_extension_enabled(e, 'network'):
+ if utils.is_extension_enabled(e, 'network'):
self.assertIn(e, actual_alias)
diff --git a/tempest/api/network/test_extra_dhcp_options.py b/tempest/api/network/test_extra_dhcp_options.py
index dc9042e..0d42033 100644
--- a/tempest/api/network/test_extra_dhcp_options.py
+++ b/tempest/api/network/test_extra_dhcp_options.py
@@ -14,9 +14,9 @@
# under the License.
from tempest.api.network import base
+from tempest.common import utils
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
-from tempest import test
class ExtraDHCPOptionsTestJSON(base.BaseNetworkTest):
@@ -35,7 +35,7 @@
@classmethod
def skip_checks(cls):
super(ExtraDHCPOptionsTestJSON, cls).skip_checks()
- if not test.is_extension_enabled('extra_dhcp_opt', 'network'):
+ if not utils.is_extension_enabled('extra_dhcp_opt', 'network'):
msg = "Extra DHCP Options extension not enabled."
raise cls.skipException(msg)
@@ -75,7 +75,7 @@
def test_update_show_port_with_extra_dhcp_options(self):
# Update port with extra dhcp options
name = data_utils.rand_name('new-port-name')
- body = self.ports_client.update_port(
+ self.ports_client.update_port(
self.port['id'],
name=name,
extra_dhcp_opts=self.extra_dhcp_opts)
diff --git a/tempest/api/network/test_floating_ips.py b/tempest/api/network/test_floating_ips.py
index c799b15..ef4a23a 100644
--- a/tempest/api/network/test_floating_ips.py
+++ b/tempest/api/network/test_floating_ips.py
@@ -14,10 +14,10 @@
# under the License.
from tempest.api.network import base
+from tempest.common import utils
from tempest.common.utils import net_utils
from tempest import config
from tempest.lib import decorators
-from tempest import test
CONF = config.CONF
@@ -43,7 +43,7 @@
@classmethod
def skip_checks(cls):
super(FloatingIPTestJSON, cls).skip_checks()
- if not test.is_extension_enabled('router', 'network'):
+ if not utils.is_extension_enabled('router', 'network'):
msg = "router extension not enabled."
raise cls.skipException(msg)
if not CONF.network.public_network_id:
diff --git a/tempest/api/network/test_floating_ips_negative.py b/tempest/api/network/test_floating_ips_negative.py
index 5ca17fe..e904a81 100644
--- a/tempest/api/network/test_floating_ips_negative.py
+++ b/tempest/api/network/test_floating_ips_negative.py
@@ -15,10 +15,10 @@
# under the License.
from tempest.api.network import base
+from tempest.common import utils
from tempest import config
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
-from tempest import test
CONF = config.CONF
@@ -34,7 +34,7 @@
@classmethod
def skip_checks(cls):
super(FloatingIPNegativeTestJSON, cls).skip_checks()
- if not test.is_extension_enabled('router', 'network'):
+ if not utils.is_extension_enabled('router', 'network'):
msg = "router extension not enabled."
raise cls.skipException(msg)
if not CONF.network.public_network_id:
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index 269f2c2..1c59556 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -18,12 +18,12 @@
from tempest.api.network import base
from tempest.common import custom_matchers
+from tempest.common import utils
from tempest import config
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
-from tempest import test
CONF = config.CONF
@@ -34,8 +34,7 @@
def resource_setup(cls):
super(BaseNetworkTestResources, cls).resource_setup()
cls.network = cls.create_network()
- cls.subnet = cls._create_subnet_with_last_subnet_block(cls.network,
- cls._ip_version)
+ cls.subnet = cls._create_subnet_with_last_subnet_block(cls.network)
cls._subnet_data = {6: {'gateway':
str(cls._get_gateway_from_tempest_conf(6)),
'allocation_pools':
@@ -64,20 +63,13 @@
'new_dns_nameservers': ['7.8.8.8', '7.8.4.4']}}
@classmethod
- def _create_subnet_with_last_subnet_block(cls, network, ip_version):
+ def _create_subnet_with_last_subnet_block(cls, network):
# Derive last subnet CIDR block from project CIDR and
# create the subnet with that derived CIDR
- if ip_version == 4:
- cidr = netaddr.IPNetwork(CONF.network.project_network_cidr)
- mask_bits = CONF.network.project_network_mask_bits
- elif ip_version == 6:
- cidr = netaddr.IPNetwork(CONF.network.project_network_v6_cidr)
- mask_bits = CONF.network.project_network_v6_mask_bits
-
- subnet_cidr = list(cidr.subnet(mask_bits))[-1]
+ subnet_cidr = list(cls.cidr.subnet(cls.mask_bits))[-1]
gateway_ip = str(netaddr.IPAddress(subnet_cidr) + 1)
return cls.create_subnet(network, gateway=gateway_ip,
- cidr=subnet_cidr, mask_bits=mask_bits)
+ cidr=subnet_cidr, mask_bits=cls.mask_bits)
@classmethod
def _get_gateway_from_tempest_conf(cls, ip_version):
@@ -209,7 +201,7 @@
def test_show_network_fields(self):
# Verify specific fields of a network
fields = ['id', 'name']
- if test.is_extension_enabled('net-mtu', 'network'):
+ if utils.is_extension_enabled('net-mtu', 'network'):
fields.append('mtu')
body = self.networks_client.show_network(self.network['id'],
fields=fields)
@@ -233,7 +225,7 @@
def test_list_networks_fields(self):
# Verify specific fields of the networks
fields = ['id', 'name']
- if test.is_extension_enabled('net-mtu', 'network'):
+ if utils.is_extension_enabled('net-mtu', 'network'):
fields.append('mtu')
body = self.networks_client.list_networks(fields=fields)
networks = body['networks']
@@ -370,30 +362,44 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('af774677-42a9-4e4b-bb58-16fe6a5bc1ec')
- @test.requires_ext(extension='external-net', service='network')
+ @utils.requires_ext(extension='external-net', service='network')
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
def test_external_network_visibility(self):
- """Verifies user can see external networks but not subnets."""
+ public_network_id = CONF.network.public_network_id
+
+ # find external network matching public_network_id
body = self.networks_client.list_networks(**{'router:external': True})
- networks = [network['id'] for network in body['networks']]
- self.assertNotEmpty(networks, "No external networks found")
+ external_network = next((network for network in body['networks']
+ if network['id'] == public_network_id), None)
+ self.assertIsNotNone(external_network, "Public network %s not found "
+ "in external network list"
+ % public_network_id)
nonexternal = [net for net in body['networks'] if
not net['router:external']]
self.assertEmpty(nonexternal, "Found non-external networks"
" in filtered list (%s)." % nonexternal)
- self.assertIn(CONF.network.public_network_id, networks)
+
# only check the public network ID because the other networks may
# belong to other tests and their state may have changed during this
# test
- body = self.subnets_client.list_subnets(
- network_id=CONF.network.public_network_id)
- self.assertEmpty(body['subnets'], "Public subnets visible")
+ body = self.subnets_client.list_subnets(network_id=public_network_id)
+
+ # check subnet visibility of external_network
+ if external_network['shared']:
+ self.assertNotEmpty(body['subnets'], "Subnets should be visible "
+ "for shared public network %s"
+ % public_network_id)
+ else:
+ self.assertEmpty(body['subnets'], "Subnets should not be visible "
+ "for non-shared public "
+ "network %s"
+ % public_network_id)
@decorators.idempotent_id('c72c1c0c-2193-4aca-ccc4-b1442640bbbb')
- @test.requires_ext(extension="standard-attr-description",
- service="network")
+ @utils.requires_ext(extension="standard-attr-description",
+ service="network")
def test_create_update_network_description(self):
body = self.create_network(description='d1')
self.assertEqual('d1', body['description'])
@@ -473,14 +479,8 @@
def test_bulk_create_delete_subnet(self):
networks = [self.create_network(), self.create_network()]
# Creates 2 subnets in one request
- if self._ip_version == 4:
- cidr = netaddr.IPNetwork(CONF.network.project_network_cidr)
- mask_bits = CONF.network.project_network_mask_bits
- else:
- cidr = netaddr.IPNetwork(CONF.network.project_network_v6_cidr)
- mask_bits = CONF.network.project_network_v6_mask_bits
-
- cidrs = [subnet_cidr for subnet_cidr in cidr.subnet(mask_bits)]
+ cidrs = [subnet_cidr
+ for subnet_cidr in self.cidr.subnet(self.mask_bits)]
names = [data_utils.rand_name('subnet-') for i in range(len(networks))]
subnets_list = []
diff --git a/tempest/api/network/test_ports.py b/tempest/api/network/test_ports.py
index f81927d..eb53fbb 100644
--- a/tempest/api/network/test_ports.py
+++ b/tempest/api/network/test_ports.py
@@ -18,11 +18,11 @@
from tempest.api.network import base_security_groups as sec_base
from tempest.common import custom_matchers
+from tempest.common import utils
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions
-from tempest import test
CONF = config.CONF
@@ -84,25 +84,13 @@
self.assertTrue(port1['admin_state_up'])
self.assertTrue(port2['admin_state_up'])
- @classmethod
- def _get_ipaddress_from_tempest_conf(cls):
- """Return subnet with mask bits for configured CIDR """
- if cls._ip_version == 4:
- cidr = netaddr.IPNetwork(CONF.network.project_network_cidr)
- cidr.prefixlen = CONF.network.project_network_mask_bits
-
- elif cls._ip_version == 6:
- cidr = netaddr.IPNetwork(CONF.network.project_network_v6_cidr)
- cidr.prefixlen = CONF.network.project_network_v6_mask_bits
-
- return cidr
-
@decorators.attr(type='smoke')
@decorators.idempotent_id('0435f278-40ae-48cb-a404-b8a087bc09b1')
def test_create_port_in_allowed_allocation_pools(self):
network = self.create_network()
net_id = network['id']
- address = self._get_ipaddress_from_tempest_conf()
+ address = self.cidr
+ address.prefixlen = self.mask_bits
if ((address.version == 4 and address.prefixlen >= 30) or
(address.version == 6 and address.prefixlen >= 126)):
msg = ("Subnet %s isn't large enough for the test" % address.cidr)
@@ -307,7 +295,7 @@
@decorators.idempotent_id('58091b66-4ff4-4cc1-a549-05d60c7acd1a')
@testtools.skipUnless(
- test.is_extension_enabled('security-group', 'network'),
+ utils.is_extension_enabled('security-group', 'network'),
'security-group extension not enabled.')
def test_update_port_with_security_group_and_extra_attributes(self):
self._update_port_with_security_groups(
@@ -315,7 +303,7 @@
@decorators.idempotent_id('edf6766d-3d40-4621-bc6e-2521a44c257d')
@testtools.skipUnless(
- test.is_extension_enabled('security-group', 'network'),
+ utils.is_extension_enabled('security-group', 'network'),
'security-group extension not enabled.')
def test_update_port_with_two_security_groups_and_extra_attributes(self):
self._update_port_with_security_groups(
@@ -342,7 +330,7 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('4179dcb9-1382-4ced-84fe-1b91c54f5735')
@testtools.skipUnless(
- test.is_extension_enabled('security-group', 'network'),
+ utils.is_extension_enabled('security-group', 'network'),
'security-group extension not enabled.')
def test_create_port_with_no_securitygroups(self):
network = self.create_network()
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index 128544b..99ffaa8 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -17,10 +17,10 @@
import testtools
from tempest.api.network import base
+from tempest.common import utils
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
-from tempest import test
CONF = config.CONF
@@ -55,17 +55,10 @@
@classmethod
def skip_checks(cls):
super(RoutersTest, cls).skip_checks()
- if not test.is_extension_enabled('router', 'network'):
+ if not utils.is_extension_enabled('router', 'network'):
msg = "router extension not enabled."
raise cls.skipException(msg)
- @classmethod
- def resource_setup(cls):
- super(RoutersTest, cls).resource_setup()
- cls.tenant_cidr = (CONF.network.project_network_cidr
- if cls._ip_version == 4 else
- CONF.network.project_network_v6_cidr)
-
@decorators.attr(type='smoke')
@decorators.idempotent_id('f64403e2-8483-4b34-8ccd-b09a87bcc68c')
@testtools.skipUnless(CONF.network.public_network_id,
@@ -139,35 +132,8 @@
self.assertEqual(show_port_body['port']['device_id'],
router['id'])
- def _verify_router_gateway(self, router_id, exp_ext_gw_info=None):
- show_body = self.admin_routers_client.show_router(router_id)
- actual_ext_gw_info = show_body['router']['external_gateway_info']
- if exp_ext_gw_info is None:
- self.assertIsNone(actual_ext_gw_info)
- return
- # Verify only keys passed in exp_ext_gw_info
- for k, v in exp_ext_gw_info.items():
- self.assertEqual(v, actual_ext_gw_info[k])
-
- def _verify_gateway_port(self, router_id):
- list_body = self.admin_ports_client.list_ports(
- network_id=CONF.network.public_network_id,
- device_id=router_id)
- self.assertEqual(len(list_body['ports']), 1)
- gw_port = list_body['ports'][0]
- fixed_ips = gw_port['fixed_ips']
- self.assertNotEmpty(fixed_ips)
- # Assert that all of the IPs from the router gateway port
- # are allocated from a valid public subnet.
- public_net_body = self.admin_networks_client.show_network(
- CONF.network.public_network_id)
- public_subnet_ids = public_net_body['network']['subnets']
- for fixed_ip in fixed_ips:
- subnet_id = fixed_ip['subnet_id']
- self.assertIn(subnet_id, public_subnet_ids)
-
@decorators.idempotent_id('cbe42f84-04c2-11e7-8adb-fa163e4fa634')
- @test.requires_ext(extension='ext-gw-mode', service='network')
+ @utils.requires_ext(extension='ext-gw-mode', service='network')
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
@decorators.skip_because(bug='1676207')
@@ -198,11 +164,11 @@
fixed_ip['ip_address'])
@decorators.idempotent_id('c86ac3a8-50bd-4b00-a6b8-62af84a0765c')
- @test.requires_ext(extension='extraroute', service='network')
+ @utils.requires_ext(extension='extraroute', service='network')
def test_update_delete_extra_route(self):
# Create different cidr for each subnet to avoid cidr duplicate
# The cidr starts from project_cidr
- next_cidr = netaddr.IPNetwork(self.tenant_cidr)
+ next_cidr = self.cidr
# Prepare to build several routes
test_routes = []
routes_num = 4
@@ -278,7 +244,7 @@
network02 = self.create_network(
network_name=data_utils.rand_name('router-network02-'))
subnet01 = self.create_subnet(network01)
- sub02_cidr = netaddr.IPNetwork(self.tenant_cidr).next()
+ sub02_cidr = self.cidr.next()
subnet02 = self.create_subnet(network02, cidr=sub02_cidr)
router = self._create_router()
interface01 = self._add_router_interface_with_subnet_id(router['id'],
diff --git a/tempest/api/network/test_routers_negative.py b/tempest/api/network/test_routers_negative.py
index 72face8..c9ce55c 100644
--- a/tempest/api/network/test_routers_negative.py
+++ b/tempest/api/network/test_routers_negative.py
@@ -13,14 +13,12 @@
# License for the specific language governing permissions and limitations
# under the License.
-import netaddr
-
from tempest.api.network import base
+from tempest.common import utils
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
-from tempest import test
CONF = config.CONF
@@ -30,7 +28,7 @@
@classmethod
def skip_checks(cls):
super(RoutersNegativeTest, cls).skip_checks()
- if not test.is_extension_enabled('router', 'network'):
+ if not utils.is_extension_enabled('router', 'network'):
msg = "router extension not enabled."
raise cls.skipException(msg)
@@ -40,9 +38,6 @@
cls.router = cls.create_router()
cls.network = cls.create_network()
cls.subnet = cls.create_subnet(cls.network)
- cls.tenant_cidr = (CONF.network.project_network_cidr
- if cls._ip_version == 4 else
- CONF.network.project_network_v6_cidr)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('37a94fc0-a834-45b9-bd23-9a81d2fd1e22')
@@ -57,7 +52,7 @@
@decorators.idempotent_id('11836a18-0b15-4327-a50b-f0d9dc66bddd')
def test_router_add_gateway_net_not_external_returns_400(self):
alt_network = self.create_network()
- sub_cidr = netaddr.IPNetwork(self.tenant_cidr).next()
+ sub_cidr = self.cidr.next()
self.create_subnet(alt_network, cidr=sub_cidr)
self.assertRaises(lib_exc.BadRequest,
self.routers_client.update_router,
@@ -124,17 +119,10 @@
@classmethod
def skip_checks(cls):
super(DvrRoutersNegativeTest, cls).skip_checks()
- if not test.is_extension_enabled('dvr', 'network'):
+ if not utils.is_extension_enabled('dvr', 'network'):
msg = "DVR extension not enabled."
raise cls.skipException(msg)
- @classmethod
- def resource_setup(cls):
- super(DvrRoutersNegativeTest, cls).resource_setup()
- cls.router = cls.create_router()
- cls.network = cls.create_network()
- cls.subnet = cls.create_subnet(cls.network)
-
@decorators.attr(type=['negative'])
@decorators.idempotent_id('4990b055-8fc7-48ab-bba7-aa28beaad0b9')
def test_router_create_tenant_distributed_returns_forbidden(self):
diff --git a/tempest/api/network/test_security_groups.py b/tempest/api/network/test_security_groups.py
index a121864..97ccee9 100644
--- a/tempest/api/network/test_security_groups.py
+++ b/tempest/api/network/test_security_groups.py
@@ -14,10 +14,10 @@
# under the License.
from tempest.api.network import base_security_groups as base
+from tempest.common import utils
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
-from tempest import test
CONF = config.CONF
@@ -28,7 +28,7 @@
@classmethod
def skip_checks(cls):
super(SecGroupTest, cls).skip_checks()
- if not test.is_extension_enabled('security-group', 'network'):
+ if not utils.is_extension_enabled('security-group', 'network'):
msg = "security-group extension not enabled."
raise cls.skipException(msg)
diff --git a/tempest/api/network/test_security_groups_negative.py b/tempest/api/network/test_security_groups_negative.py
index f51fb33..435673b 100644
--- a/tempest/api/network/test_security_groups_negative.py
+++ b/tempest/api/network/test_security_groups_negative.py
@@ -14,11 +14,11 @@
# under the License.
from tempest.api.network import base_security_groups as base
+from tempest.common import utils
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
-from tempest import test
CONF = config.CONF
@@ -29,7 +29,7 @@
@classmethod
def skip_checks(cls):
super(NegativeSecGroupTest, cls).skip_checks()
- if not test.is_extension_enabled('security-group', 'network'):
+ if not utils.is_extension_enabled('security-group', 'network'):
msg = "security-group extension not enabled."
raise cls.skipException(msg)
diff --git a/tempest/api/network/test_service_providers.py b/tempest/api/network/test_service_providers.py
index b90c81b..9ebcd89 100644
--- a/tempest/api/network/test_service_providers.py
+++ b/tempest/api/network/test_service_providers.py
@@ -13,15 +13,15 @@
import testtools
from tempest.api.network import base
+from tempest.common import utils
from tempest.lib import decorators
-from tempest import test
class ServiceProvidersTest(base.BaseNetworkTest):
@decorators.idempotent_id('2cbbeea9-f010-40f6-8df5-4eaa0c918ea6')
@testtools.skipUnless(
- test.is_extension_enabled('service-type', 'network'),
+ utils.is_extension_enabled('service-type', 'network'),
'service-type extension not enabled.')
def test_service_providers_list(self):
body = self.service_providers_client.list_service_providers()
diff --git a/tempest/api/network/test_subnetpools_extensions.py b/tempest/api/network/test_subnetpools_extensions.py
index 01d7db2..bfc2609 100644
--- a/tempest/api/network/test_subnetpools_extensions.py
+++ b/tempest/api/network/test_subnetpools_extensions.py
@@ -13,12 +13,12 @@
# under the License.
from tempest.api.network import base
+from tempest.common import utils
from tempest import config
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
-from tempest import test
CONF = config.CONF
@@ -42,7 +42,7 @@
@classmethod
def skip_checks(cls):
super(SubnetPoolsTestJSON, cls).skip_checks()
- if not test.is_extension_enabled('subnet_allocation', 'network'):
+ if not utils.is_extension_enabled('subnet_allocation', 'network'):
msg = "subnet_allocation extension not enabled."
raise cls.skipException(msg)
diff --git a/tempest/api/network/test_tags.py b/tempest/api/network/test_tags.py
index 567a462..409d556 100644
--- a/tempest/api/network/test_tags.py
+++ b/tempest/api/network/test_tags.py
@@ -14,11 +14,11 @@
# under the License.
from tempest.api.network import base
+from tempest.common import utils
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
-from tempest import test
CONF = config.CONF
@@ -40,7 +40,7 @@
@classmethod
def skip_checks(cls):
super(TagsTest, cls).skip_checks()
- if not test.is_extension_enabled('tag', 'network'):
+ if not utils.is_extension_enabled('tag', 'network'):
msg = "tag extension not enabled."
raise cls.skipException(msg)
@@ -115,7 +115,7 @@
@classmethod
def skip_checks(cls):
super(TagsExtTest, cls).skip_checks()
- if not test.is_extension_enabled('tag-ext', 'network'):
+ if not utils.is_extension_enabled('tag-ext', 'network'):
msg = "tag-ext extension not enabled."
raise cls.skipException(msg)
diff --git a/tempest/api/object_storage/base.py b/tempest/api/object_storage/base.py
index 11273e4..4c49b2a 100644
--- a/tempest/api/object_storage/base.py
+++ b/tempest/api/object_storage/base.py
@@ -71,9 +71,6 @@
def setup_credentials(cls):
cls.set_network_resources()
super(BaseObjectTest, cls).setup_credentials()
- # credentials may be overwritten by children classes
- if hasattr(cls, 'os_roles_operator'):
- cls.os = cls.os_roles_operator
@classmethod
def setup_clients(cls):
diff --git a/tempest/api/object_storage/test_account_bulk.py b/tempest/api/object_storage/test_account_bulk.py
index 7c538e8..9abd59e 100644
--- a/tempest/api/object_storage/test_account_bulk.py
+++ b/tempest/api/object_storage/test_account_bulk.py
@@ -17,8 +17,8 @@
from tempest.api.object_storage import base
from tempest.common import custom_matchers
+from tempest.common import utils
from tempest.lib import decorators
-from tempest import test
class BulkTest(base.BaseObjectTest):
@@ -69,7 +69,7 @@
self.assertNotIn(container_name, body)
@decorators.idempotent_id('a407de51-1983-47cc-9f14-47c2b059413c')
- @test.requires_ext(extension='bulk_upload', service='object')
+ @utils.requires_ext(extension='bulk_upload', service='object')
def test_extract_archive(self):
# Test bulk operation of file upload with an archived file
filepath, container_name, object_name = self._create_archive()
@@ -104,7 +104,7 @@
self.assertIn(object_name, [c['name'] for c in contents_list])
@decorators.idempotent_id('c075e682-0d2a-43b2-808d-4116200d736d')
- @test.requires_ext(extension='bulk_delete', service='object')
+ @utils.requires_ext(extension='bulk_delete', service='object')
def test_bulk_delete(self):
# Test bulk operation of deleting multiple files
filepath, container_name, object_name = self._create_archive()
@@ -129,7 +129,7 @@
self._check_contents_deleted(container_name)
@decorators.idempotent_id('dbea2bcb-efbb-4674-ac8a-a5a0e33d1d79')
- @test.requires_ext(extension='bulk_delete', service='object')
+ @utils.requires_ext(extension='bulk_delete', service='object')
def test_bulk_delete_by_POST(self):
# Test bulk operation of deleting multiple files
filepath, container_name, object_name = self._create_archive()
diff --git a/tempest/api/object_storage/test_account_quotas.py b/tempest/api/object_storage/test_account_quotas.py
index 092d369..48f42ec 100644
--- a/tempest/api/object_storage/test_account_quotas.py
+++ b/tempest/api/object_storage/test_account_quotas.py
@@ -13,10 +13,10 @@
# under the License.
from tempest.api.object_storage import base
+from tempest.common import utils
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
-from tempest import test
CONF = config.CONF
@@ -29,7 +29,6 @@
@classmethod
def setup_credentials(cls):
super(AccountQuotasTest, cls).setup_credentials()
- cls.os = cls.os_roles_operator
cls.os_reselleradmin = cls.os_roles_reseller
@classmethod
@@ -78,7 +77,7 @@
@decorators.attr(type="smoke")
@decorators.idempotent_id('a22ef352-a342-4587-8f47-3bbdb5b039c4')
- @test.requires_ext(extension='account_quotas', service='object')
+ @utils.requires_ext(extension='account_quotas', service='object')
def test_upload_valid_object(self):
object_name = data_utils.rand_name(name="TestObject")
data = data_utils.arbitrary_string()
@@ -89,7 +88,7 @@
@decorators.attr(type=["smoke"])
@decorators.idempotent_id('63f51f9f-5f1d-4fc6-b5be-d454d70949d6')
- @test.requires_ext(extension='account_quotas', service='object')
+ @utils.requires_ext(extension='account_quotas', service='object')
def test_admin_modify_quota(self):
"""Test ResellerAdmin can modify/remove the quota on a user's account
diff --git a/tempest/api/object_storage/test_account_quotas_negative.py b/tempest/api/object_storage/test_account_quotas_negative.py
index 60233b4..798926b 100644
--- a/tempest/api/object_storage/test_account_quotas_negative.py
+++ b/tempest/api/object_storage/test_account_quotas_negative.py
@@ -13,10 +13,10 @@
# under the License.
from tempest.api.object_storage import base
+from tempest.common import utils
from tempest import config
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
-from tempest import test
CONF = config.CONF
@@ -29,7 +29,6 @@
@classmethod
def setup_credentials(cls):
super(AccountQuotasNegativeTest, cls).setup_credentials()
- cls.os = cls.os_roles_operator
cls.os_reselleradmin = cls.os_roles_reseller
@classmethod
@@ -77,7 +76,7 @@
@decorators.attr(type=["negative"])
@decorators.idempotent_id('d1dc5076-555e-4e6d-9697-28f1fe976324')
- @test.requires_ext(extension='account_quotas', service='object')
+ @utils.requires_ext(extension='account_quotas', service='object')
def test_user_modify_quota(self):
"""Test that a user cannot modify or remove a quota on its account."""
diff --git a/tempest/api/object_storage/test_account_services.py b/tempest/api/object_storage/test_account_services.py
index 2fb676f..0f86540 100644
--- a/tempest/api/object_storage/test_account_services.py
+++ b/tempest/api/object_storage/test_account_services.py
@@ -36,14 +36,13 @@
@classmethod
def setup_credentials(cls):
super(AccountTest, cls).setup_credentials()
- cls.os = cls.os_roles_operator
cls.os_operator = cls.os_roles_operator_alt
@classmethod
def resource_setup(cls):
super(AccountTest, cls).resource_setup()
for i in range(ord('a'), ord('f') + 1):
- name = data_utils.rand_name(name='%s-' % chr(i))
+ name = data_utils.rand_name(name='%s-' % six.int2byte(i))
cls.container_client.create_container(name)
cls.containers.append(name)
cls.containers_count = len(cls.containers)
diff --git a/tempest/api/object_storage/test_account_services_negative.py b/tempest/api/object_storage/test_account_services_negative.py
index e98a4f5..3e664d7 100644
--- a/tempest/api/object_storage/test_account_services_negative.py
+++ b/tempest/api/object_storage/test_account_services_negative.py
@@ -28,7 +28,6 @@
@classmethod
def setup_credentials(cls):
super(AccountNegativeTest, cls).setup_credentials()
- cls.os = cls.os_roles_operator
cls.os_operator = cls.os_roles_operator_alt
@decorators.attr(type=['negative'])
diff --git a/tempest/api/object_storage/test_container_acl_negative.py b/tempest/api/object_storage/test_container_acl_negative.py
index 655626c..e064753 100644
--- a/tempest/api/object_storage/test_container_acl_negative.py
+++ b/tempest/api/object_storage/test_container_acl_negative.py
@@ -29,7 +29,6 @@
@classmethod
def setup_credentials(cls):
super(ObjectACLsNegativeTest, cls).setup_credentials()
- cls.os = cls.os_roles_operator
cls.os_operator = cls.os_roles_operator_alt
@classmethod
diff --git a/tempest/api/object_storage/test_container_quotas.py b/tempest/api/object_storage/test_container_quotas.py
index 8266341..c87bed5 100644
--- a/tempest/api/object_storage/test_container_quotas.py
+++ b/tempest/api/object_storage/test_container_quotas.py
@@ -14,10 +14,10 @@
# under the License.
from tempest.api.object_storage import base
+from tempest.common import utils
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
-from tempest import test
QUOTA_BYTES = 10
QUOTA_COUNT = 3
@@ -49,7 +49,7 @@
super(ContainerQuotasTest, self).tearDown()
@decorators.idempotent_id('9a0fb034-86af-4df0-86fa-f8bd7db21ae0')
- @test.requires_ext(extension='container_quotas', service='object')
+ @utils.requires_ext(extension='container_quotas', service='object')
@decorators.attr(type="smoke")
def test_upload_valid_object(self):
"""Attempts to uploads an object smaller than the bytes quota."""
@@ -66,7 +66,7 @@
self.assertEqual(nbefore + len(data), nafter)
@decorators.idempotent_id('22eeeb2b-3668-4160-baef-44790f65a5a0')
- @test.requires_ext(extension='container_quotas', service='object')
+ @utils.requires_ext(extension='container_quotas', service='object')
@decorators.attr(type="smoke")
def test_upload_large_object(self):
"""Attempts to upload an object larger than the bytes quota."""
@@ -83,7 +83,7 @@
self.assertEqual(nbefore, nafter)
@decorators.idempotent_id('3a387039-697a-44fc-a9c0-935de31f426b')
- @test.requires_ext(extension='container_quotas', service='object')
+ @utils.requires_ext(extension='container_quotas', service='object')
@decorators.attr(type="smoke")
def test_upload_too_many_objects(self):
"""Attempts to upload many objects that exceeds the count limit."""
diff --git a/tempest/api/object_storage/test_container_staticweb.py b/tempest/api/object_storage/test_container_staticweb.py
index 943011d..92fa690 100644
--- a/tempest/api/object_storage/test_container_staticweb.py
+++ b/tempest/api/object_storage/test_container_staticweb.py
@@ -14,10 +14,10 @@
from tempest.api.object_storage import base
from tempest.common import custom_matchers
+from tempest.common import utils
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
-from tempest import test
class StaticWebTest(base.BaseObjectTest):
@@ -45,7 +45,7 @@
super(StaticWebTest, cls).resource_cleanup()
@decorators.idempotent_id('c1f055ab-621d-4a6a-831f-846fcb578b8b')
- @test.requires_ext(extension='staticweb', service='object')
+ @utils.requires_ext(extension='staticweb', service='object')
def test_web_index(self):
headers = {'web-index': self.object_name}
@@ -76,7 +76,7 @@
self.assertNotIn('x-container-meta-web-index', body)
@decorators.idempotent_id('941814cf-db9e-4b21-8112-2b6d0af10ee5')
- @test.requires_ext(extension='staticweb', service='object')
+ @utils.requires_ext(extension='staticweb', service='object')
def test_web_listing(self):
headers = {'web-listings': 'true'}
@@ -108,7 +108,7 @@
self.assertNotIn('x-container-meta-web-listings', body)
@decorators.idempotent_id('bc37ec94-43c8-4990-842e-0e5e02fc8926')
- @test.requires_ext(extension='staticweb', service='object')
+ @utils.requires_ext(extension='staticweb', service='object')
def test_web_listing_css(self):
headers = {'web-listings': 'true',
'web-listings-css': 'listings.css'}
@@ -131,7 +131,7 @@
self.assertIn(css, body.decode())
@decorators.idempotent_id('f18b4bef-212e-45e7-b3ca-59af3a465f82')
- @test.requires_ext(extension='staticweb', service='object')
+ @utils.requires_ext(extension='staticweb', service='object')
def test_web_error(self):
headers = {'web-listings': 'true',
'web-error': self.object_name}
diff --git a/tempest/api/object_storage/test_container_sync.py b/tempest/api/object_storage/test_container_sync.py
index 4cb1914..7665b48 100644
--- a/tempest/api/object_storage/test_container_sync.py
+++ b/tempest/api/object_storage/test_container_sync.py
@@ -41,7 +41,6 @@
@classmethod
def setup_credentials(cls):
super(ContainerSyncTest, cls).setup_credentials()
- cls.os = cls.os_roles_operator
cls.os_alt = cls.os_roles_operator_alt
@classmethod
diff --git a/tempest/api/object_storage/test_container_sync_middleware.py b/tempest/api/object_storage/test_container_sync_middleware.py
index 9eae138..e77b079 100644
--- a/tempest/api/object_storage/test_container_sync_middleware.py
+++ b/tempest/api/object_storage/test_container_sync_middleware.py
@@ -13,9 +13,9 @@
# under the License.
from tempest.api.object_storage import test_container_sync
+from tempest.common import utils
from tempest import config
from tempest.lib import decorators
-from tempest import test
CONF = config.CONF
@@ -39,7 +39,7 @@
@decorators.attr(type='slow')
@decorators.idempotent_id('ea4645a1-d147-4976-82f7-e5a7a3065f80')
- @test.requires_ext(extension='container_sync', service='object')
+ @utils.requires_ext(extension='container_sync', service='object')
def test_container_synchronization(self):
def make_headers(cont, cont_client):
# tell first container to synchronize to a second
diff --git a/tempest/api/object_storage/test_crossdomain.py b/tempest/api/object_storage/test_crossdomain.py
index c47aa93..f61d9f8 100644
--- a/tempest/api/object_storage/test_crossdomain.py
+++ b/tempest/api/object_storage/test_crossdomain.py
@@ -14,8 +14,8 @@
from tempest.api.object_storage import base
from tempest.common import custom_matchers
+from tempest.common import utils
from tempest.lib import decorators
-from tempest import test
class CrossdomainTest(base.BaseObjectTest):
@@ -38,7 +38,7 @@
self.account_client.skip_path()
@decorators.idempotent_id('d1b8b031-b622-4010-82f9-ff78a9e915c7')
- @test.requires_ext(extension='crossdomain', service='object')
+ @utils.requires_ext(extension='crossdomain', service='object')
def test_get_crossdomain_policy(self):
resp, body = self.account_client.get("crossdomain.xml", {})
body = body.decode()
diff --git a/tempest/api/object_storage/test_object_formpost.py b/tempest/api/object_storage/test_object_formpost.py
index 3a2233a..cd834bf 100644
--- a/tempest/api/object_storage/test_object_formpost.py
+++ b/tempest/api/object_storage/test_object_formpost.py
@@ -19,9 +19,9 @@
from six.moves.urllib import parse as urlparse
from tempest.api.object_storage import base
+from tempest.common import utils
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
-from tempest import test
class ObjectFormPostTest(base.BaseObjectTest):
@@ -108,7 +108,7 @@
return body, content_type
@decorators.idempotent_id('80fac02b-6e54-4f7b-be0d-a965b5cbef76')
- @test.requires_ext(extension='formpost', service='object')
+ @utils.requires_ext(extension='formpost', service='object')
def test_post_object_using_form(self):
body, content_type = self.get_multipart_form()
diff --git a/tempest/api/object_storage/test_object_formpost_negative.py b/tempest/api/object_storage/test_object_formpost_negative.py
index c56d91a..df6a0fd 100644
--- a/tempest/api/object_storage/test_object_formpost_negative.py
+++ b/tempest/api/object_storage/test_object_formpost_negative.py
@@ -19,10 +19,10 @@
from six.moves.urllib import parse as urlparse
from tempest.api.object_storage import base
+from tempest.common import utils
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
-from tempest import test
class ObjectFormPostNegativeTest(base.BaseObjectTest):
@@ -109,7 +109,7 @@
return body, content_type
@decorators.idempotent_id('d3fb3c4d-e627-48ce-9379-a1631f21336d')
- @test.requires_ext(extension='formpost', service='object')
+ @utils.requires_ext(extension='formpost', service='object')
@decorators.attr(type=['negative'])
def test_post_object_using_form_expired(self):
body, content_type = self.get_multipart_form(expires=1)
@@ -126,7 +126,7 @@
self.assertIn('FormPost: Form Expired', str(exc))
@decorators.idempotent_id('b277257f-113c-4499-b8d1-5fead79f7360')
- @test.requires_ext(extension='formpost', service='object')
+ @utils.requires_ext(extension='formpost', service='object')
@decorators.attr(type=['negative'])
def test_post_object_using_form_invalid_signature(self):
self.key = "Wrong"
diff --git a/tempest/api/object_storage/test_object_services.py b/tempest/api/object_storage/test_object_services.py
index 556ca2f..d3cdb72 100644
--- a/tempest/api/object_storage/test_object_services.py
+++ b/tempest/api/object_storage/test_object_services.py
@@ -967,7 +967,6 @@
@classmethod
def setup_credentials(cls):
super(PublicObjectTest, cls).setup_credentials()
- cls.os = cls.os_roles_operator
cls.os_alt = cls.os_roles_operator_alt
@classmethod
diff --git a/tempest/api/object_storage/test_object_slo.py b/tempest/api/object_storage/test_object_slo.py
index 894e42d..65da63d 100644
--- a/tempest/api/object_storage/test_object_slo.py
+++ b/tempest/api/object_storage/test_object_slo.py
@@ -18,10 +18,10 @@
from tempest.api.object_storage import base
from tempest.common import custom_matchers
+from tempest.common import utils
from tempest.lib.common.utils import data_utils
from tempest.lib.common.utils import test_utils
from tempest.lib import decorators
-from tempest import test
# Each segment, except for the final one, must be at least 1 megabyte
MIN_SEGMENT_SIZE = 1024 * 1024
@@ -107,7 +107,7 @@
self.assertHeaders(resp, 'Object', method)
@decorators.idempotent_id('2c3f24a6-36e8-4711-9aa2-800ee1fc7b5b')
- @test.requires_ext(extension='slo', service='object')
+ @utils.requires_ext(extension='slo', service='object')
def test_upload_manifest(self):
# create static large object from multipart manifest
manifest = self._create_manifest()
@@ -122,7 +122,7 @@
self._assertHeadersSLO(resp, 'PUT')
@decorators.idempotent_id('e69ad766-e1aa-44a2-bdd2-bf62c09c1456')
- @test.requires_ext(extension='slo', service='object')
+ @utils.requires_ext(extension='slo', service='object')
def test_list_large_object_metadata(self):
# list static large object metadata using multipart manifest
object_name = self._create_large_object()
@@ -134,7 +134,7 @@
self._assertHeadersSLO(resp, 'HEAD')
@decorators.idempotent_id('49bc49bc-dd1b-4c0f-904e-d9f10b830ee8')
- @test.requires_ext(extension='slo', service='object')
+ @utils.requires_ext(extension='slo', service='object')
def test_retrieve_large_object(self):
# list static large object using multipart manifest
object_name = self._create_large_object()
@@ -149,7 +149,7 @@
self.assertEqual(body, sum_data)
@decorators.idempotent_id('87b6dfa1-abe9-404d-8bf0-6c3751e6aa77')
- @test.requires_ext(extension='slo', service='object')
+ @utils.requires_ext(extension='slo', service='object')
def test_delete_large_object(self):
# delete static large object using multipart manifest
object_name = self._create_large_object()
diff --git a/tempest/api/object_storage/test_object_temp_url.py b/tempest/api/object_storage/test_object_temp_url.py
index 91bc677..b99f93a 100644
--- a/tempest/api/object_storage/test_object_temp_url.py
+++ b/tempest/api/object_storage/test_object_temp_url.py
@@ -19,9 +19,9 @@
from six.moves.urllib import parse as urlparse
from tempest.api.object_storage import base
+from tempest.common import utils
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
-from tempest import test
class ObjectTempUrlTest(base.BaseObjectTest):
@@ -88,7 +88,7 @@
return url
@decorators.idempotent_id('f91c96d4-1230-4bba-8eb9-84476d18d991')
- @test.requires_ext(extension='tempurl', service='object')
+ @utils.requires_ext(extension='tempurl', service='object')
def test_get_object_using_temp_url(self):
expires = self._get_expiry_date()
@@ -103,11 +103,11 @@
self.assertEqual(body, self.content)
# Testing a HEAD on this Temp URL
- resp, body = self.object_client.head(url)
+ resp, _ = self.object_client.head(url)
self.assertHeaders(resp, 'Object', 'HEAD')
@decorators.idempotent_id('671f9583-86bd-4128-a034-be282a68c5d8')
- @test.requires_ext(extension='tempurl', service='object')
+ @utils.requires_ext(extension='tempurl', service='object')
def test_get_object_using_temp_url_key_2(self):
key2 = 'Meta2-'
metadata = {'Temp-URL-Key-2': key2}
@@ -132,7 +132,7 @@
self.assertEqual(body, self.content)
@decorators.idempotent_id('9b08dade-3571-4152-8a4f-a4f2a873a735')
- @test.requires_ext(extension='tempurl', service='object')
+ @utils.requires_ext(extension='tempurl', service='object')
def test_put_object_using_temp_url(self):
new_data = data_utils.random_bytes(size=len(self.object_name))
@@ -142,11 +142,11 @@
expires, self.key)
# trying to put random data in the object using temp url
- resp, body = self.object_client.put(url, new_data, None)
+ resp, _ = self.object_client.put(url, new_data, None)
self.assertHeaders(resp, 'Object', 'PUT')
# Testing a HEAD on this Temp URL
- resp, body = self.object_client.head(url)
+ resp, _ = self.object_client.head(url)
self.assertHeaders(resp, 'Object', 'HEAD')
# Validate that the content of the object has been modified
@@ -158,7 +158,7 @@
self.assertEqual(body, new_data)
@decorators.idempotent_id('249a0111-5ad3-4534-86a7-1993d55f9185')
- @test.requires_ext(extension='tempurl', service='object')
+ @utils.requires_ext(extension='tempurl', service='object')
def test_head_object_using_temp_url(self):
expires = self._get_expiry_date()
@@ -172,7 +172,7 @@
self.assertHeaders(resp, 'Object', 'HEAD')
@decorators.idempotent_id('9d9cfd90-708b-465d-802c-e4a8090b823d')
- @test.requires_ext(extension='tempurl', service='object')
+ @utils.requires_ext(extension='tempurl', service='object')
def test_get_object_using_temp_url_with_inline_query_parameter(self):
expires = self._get_expiry_date()
diff --git a/tempest/api/object_storage/test_object_temp_url_negative.py b/tempest/api/object_storage/test_object_temp_url_negative.py
index c7d1fd5..17ae6c1 100644
--- a/tempest/api/object_storage/test_object_temp_url_negative.py
+++ b/tempest/api/object_storage/test_object_temp_url_negative.py
@@ -19,10 +19,10 @@
from six.moves.urllib import parse as urlparse
from tempest.api.object_storage import base
+from tempest.common import utils
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
-from tempest import test
class ObjectTempUrlNegativeTest(base.BaseObjectTest):
@@ -94,7 +94,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('5a583aca-c804-41ba-9d9a-e7be132bdf0b')
- @test.requires_ext(extension='tempurl', service='object')
+ @utils.requires_ext(extension='tempurl', service='object')
def test_get_object_after_expiration_time(self):
expires = self._get_expiry_date(1)
diff --git a/tempest/api/object_storage/test_object_version.py b/tempest/api/object_storage/test_object_version.py
index dc0d179..4799053 100644
--- a/tempest/api/object_storage/test_object_version.py
+++ b/tempest/api/object_storage/test_object_version.py
@@ -51,7 +51,7 @@
def test_versioned_container(self):
# create container
vers_container_name = data_utils.rand_name(name='TestVersionContainer')
- resp, body = self.container_client.create_container(
+ resp, _ = self.container_client.create_container(
vers_container_name)
self.containers.append(vers_container_name)
self.assertHeaders(resp, 'Container', 'PUT')
@@ -59,7 +59,7 @@
base_container_name = data_utils.rand_name(name='TestBaseContainer')
headers = {'X-versions-Location': vers_container_name}
- resp, body = self.container_client.create_container(
+ resp, _ = self.container_client.create_container(
base_container_name,
metadata=headers,
metadata_prefix='')
@@ -76,20 +76,20 @@
data_2 = data_utils.random_bytes()
resp, _ = self.object_client.create_object(base_container_name,
object_name, data_2)
- resp, body = self.object_client.get_object(base_container_name,
- object_name)
+ _, body = self.object_client.get_object(base_container_name,
+ object_name)
self.assertEqual(body, data_2)
# delete object version 2
resp, _ = self.object_client.delete_object(base_container_name,
object_name)
self.assertContainer(base_container_name, '1', '1024',
vers_container_name)
- resp, body = self.object_client.get_object(base_container_name,
- object_name)
+ _, body = self.object_client.get_object(base_container_name,
+ object_name)
self.assertEqual(body, data_1)
# delete object version 1
- resp, _ = self.object_client.delete_object(base_container_name,
- object_name)
+ self.object_client.delete_object(base_container_name,
+ object_name)
# containers should be empty
self.assertContainer(base_container_name, '0', '0',
vers_container_name)
diff --git a/tempest/api/volume/admin/test_groups.py b/tempest/api/volume/admin/test_groups.py
index 3f8664c..baea37b 100644
--- a/tempest/api/volume/admin/test_groups.py
+++ b/tempest/api/volume/admin/test_groups.py
@@ -270,19 +270,20 @@
# Create Group
grp = self._create_group(group_type, volume_type)
- # Create a volume in the group
- vol1 = self.create_volume(volume_type=volume_type['id'],
- group_id=grp['id'])
- # Create a volume not in the group
- vol2 = self.create_volume(volume_type=volume_type['id'])
+ # Create volumes
+ grp_vols = []
+ for _ in range(2):
+ vol = self.create_volume(volume_type=volume_type['id'],
+ group_id=grp['id'])
+ grp_vols.append(vol)
+ vol2 = grp_vols[1]
# Remove a volume from group and update name and description
new_grp_name = 'new_group'
new_desc = 'This is a new group'
grp_params = {'name': new_grp_name,
'description': new_desc,
- 'remove_volumes': vol1['id'],
- 'add_volumes': vol2['id']}
+ 'remove_volumes': vol2['id']}
self.groups_client.update_group(grp['id'], **grp_params)
# Wait for group status to become available
@@ -302,5 +303,20 @@
if vol['group_id'] == grp['id']:
grp_vols.append(vol)
self.assertEqual(1, len(grp_vols))
- self.assertEqual(vol2['id'], grp_vols[0]['id'])
- self.assertNotEqual(vol1['id'], grp_vols[0]['id'])
+
+ # Add a volume to the group
+ grp_params = {'add_volumes': vol2['id']}
+ self.groups_client.update_group(grp['id'], **grp_params)
+
+ # Wait for group status to become available
+ waiters.wait_for_volume_resource_status(
+ self.groups_client, grp['id'], 'available')
+
+ # Get volumes in the group
+ vols = self.volumes_client.list_volumes(
+ detail=True)['volumes']
+ grp_vols = []
+ for vol in vols:
+ if vol['group_id'] == grp['id']:
+ grp_vols.append(vol)
+ self.assertEqual(2, len(grp_vols))
diff --git a/tempest/api/volume/admin/test_multi_backend.py b/tempest/api/volume/admin/test_multi_backend.py
index 2db8010..c0891e4 100644
--- a/tempest/api/volume/admin/test_multi_backend.py
+++ b/tempest/api/volume/admin/test_multi_backend.py
@@ -66,8 +66,7 @@
params = {'name': vol_name, 'volume_type': type_name,
'size': CONF.volume.volume_size}
- cls.volume = cls.admin_volume_client.create_volume(
- **params)['volume']
+ cls.volume = cls.create_volume(**params)
if with_prefix:
cls.volume_id_list_with_prefix.append(cls.volume['id'])
else:
@@ -76,21 +75,6 @@
waiters.wait_for_volume_resource_status(cls.admin_volume_client,
cls.volume['id'], 'available')
- @classmethod
- def resource_cleanup(cls):
- # volumes deletion
- vid_prefix = getattr(cls, 'volume_id_list_with_prefix', [])
- for volume_id in vid_prefix:
- cls.admin_volume_client.delete_volume(volume_id)
- cls.admin_volume_client.wait_for_resource_deletion(volume_id)
-
- vid_no_pre = getattr(cls, 'volume_id_list_without_prefix', [])
- for volume_id in vid_no_pre:
- cls.admin_volume_client.delete_volume(volume_id)
- cls.admin_volume_client.wait_for_resource_deletion(volume_id)
-
- super(VolumeMultiBackendTest, cls).resource_cleanup()
-
@decorators.idempotent_id('c1a41f3f-9dad-493e-9f09-3ff197d477cc')
def test_backend_name_reporting(self):
# get volume id which created by type without prefix
diff --git a/tempest/api/volume/admin/test_snapshots_actions.py b/tempest/api/volume/admin/test_snapshots_actions.py
index 471f39a..41849bc 100644
--- a/tempest/api/volume/admin/test_snapshots_actions.py
+++ b/tempest/api/volume/admin/test_snapshots_actions.py
@@ -14,6 +14,7 @@
# under the License.
from tempest.api.volume import base
+from tempest.common import waiters
from tempest import config
from tempest.lib import decorators
@@ -43,6 +44,8 @@
snapshot_id = self.snapshot['id']
self.admin_snapshots_client.reset_snapshot_status(snapshot_id,
status)
+ waiters.wait_for_volume_resource_status(self.snapshots_client,
+ snapshot_id, status)
super(SnapshotsActionsTest, self).tearDown()
def _create_reset_and_force_delete_temp_snapshot(self, status=None):
@@ -50,10 +53,11 @@
# and force delete temp snapshot
temp_snapshot = self.create_snapshot(volume_id=self.volume['id'])
if status:
- self.admin_snapshots_client.\
- reset_snapshot_status(temp_snapshot['id'], status)
- self.admin_snapshots_client.\
- force_delete_snapshot(temp_snapshot['id'])
+ self.admin_snapshots_client.reset_snapshot_status(
+ temp_snapshot['id'], status)
+ waiters.wait_for_volume_resource_status(
+ self.snapshots_client, temp_snapshot['id'], status)
+ self.admin_snapshots_client.force_delete_snapshot(temp_snapshot['id'])
self.snapshots_client.wait_for_resource_deletion(temp_snapshot['id'])
def _get_progress_alias(self):
@@ -63,18 +67,19 @@
def test_reset_snapshot_status(self):
# Reset snapshot status to creating
status = 'creating'
- self.admin_snapshots_client.\
- reset_snapshot_status(self.snapshot['id'], status)
- snapshot_get = self.admin_snapshots_client.show_snapshot(
- self.snapshot['id'])['snapshot']
- self.assertEqual(status, snapshot_get['status'])
+ self.admin_snapshots_client.reset_snapshot_status(
+ self.snapshot['id'], status)
+ waiters.wait_for_volume_resource_status(self.snapshots_client,
+ self.snapshot['id'], status)
@decorators.idempotent_id('41288afd-d463-485e-8f6e-4eea159413eb')
def test_update_snapshot_status(self):
# Reset snapshot status to creating
status = 'creating'
- self.admin_snapshots_client.\
- reset_snapshot_status(self.snapshot['id'], status)
+ self.admin_snapshots_client.reset_snapshot_status(
+ self.snapshot['id'], status)
+ waiters.wait_for_volume_resource_status(self.snapshots_client,
+ self.snapshot['id'], status)
# Update snapshot status to error
progress = '80%'
diff --git a/tempest/api/volume/admin/test_volume_hosts.py b/tempest/api/volume/admin/test_volume_hosts.py
index e4ec442..ce0cbd2 100644
--- a/tempest/api/volume/admin/test_volume_hosts.py
+++ b/tempest/api/volume/admin/test_volume_hosts.py
@@ -13,8 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-import random
-
from tempest.api.volume import base
from tempest.lib import decorators
@@ -42,20 +40,25 @@
"The count of volume hosts is < 2, "
"response of list hosts is: %s" % hosts)
- # Note(jeremyZ): Host in volume is always presented in two formats:
- # <host-name> or <host-name>@<driver-name>. Since Mitaka is EOL,
- # both formats can be chosen for test.
- host_names = [host['host_name'] for host in hosts]
- self.assertNotEmpty(host_names, "No available volume host is found, "
- "all hosts that found are: %s" % hosts)
+ # Note(jeremyZ): The show host API is to show volume usage info on the
+ # specified cinder-volume host. If the host does not run cinder-volume
+ # service, or the cinder-volume service is disabled on the host, the
+ # show host API should fail (return code: 404). The cinder-volume host
+ # is presented in format: <host-name>@driver-name.
+ c_vol_hosts = [host['host_name'] for host in hosts
+ if (host['service'] == 'cinder-volume'
+ and host['service-state'] == 'enabled')]
+ self.assertNotEmpty(c_vol_hosts,
+ "No available cinder-volume host is found, "
+ "all hosts that found are: %s" % hosts)
- # Choose a random host to get and check its elements
- host_details = self.admin_hosts_client.show_host(
- random.choice(host_names))['host']
- self.assertNotEmpty(host_details)
+ # Check each cinder-volume host.
host_detail_keys = ['project', 'volume_count', 'snapshot_count',
'host', 'total_volume_gb', 'total_snapshot_gb']
- for detail in host_details:
- self.assertIn('resource', detail)
- for key in host_detail_keys:
- self.assertIn(key, detail['resource'])
+ for host in c_vol_hosts:
+ host_details = self.admin_hosts_client.show_host(host)['host']
+ self.assertNotEmpty(host_details)
+ for detail in host_details:
+ self.assertIn('resource', detail)
+ for key in host_detail_keys:
+ self.assertIn(key, detail['resource'])
diff --git a/tempest/api/volume/admin/test_volume_retype_with_migration.py b/tempest/api/volume/admin/test_volume_retype_with_migration.py
index 94d5299..f0b3a4f 100644
--- a/tempest/api/volume/admin/test_volume_retype_with_migration.py
+++ b/tempest/api/volume/admin/test_volume_retype_with_migration.py
@@ -85,9 +85,7 @@
volume_source = self.admin_volume_client.show_volume(
self.src_vol['id'])['volume']
- # TODO(erlon): change this to volumes_client client after Bug
- # #1657806 is fixed
- self.admin_volume_client.retype_volume(
+ self.volumes_client.retype_volume(
self.src_vol['id'],
new_type=self.dst_vol_type['name'],
migration_policy='on-demand')
diff --git a/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py b/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py
index 4fa934e..fe249d6 100644
--- a/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py
+++ b/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py
@@ -61,7 +61,7 @@
@decorators.idempotent_id('a77dfda2-9100-448e-9076-ed1711f4bdfc')
def test_update_multiple_extra_spec(self):
# Should not update volume type extra specs with multiple specs as
- # body.
+ # body.
extra_spec = {"spec1": "val2", "spec2": "val1"}
self.assertRaises(
lib_exc.BadRequest,
@@ -73,7 +73,7 @@
@decorators.idempotent_id('49d5472c-a53d-4eab-a4d3-450c4db1c545')
def test_create_nonexistent_type_id(self):
# Should not create volume type extra spec for nonexistent volume
- # type id.
+ # type id.
extra_specs = {"spec2": "val1"}
self.assertRaises(
lib_exc.NotFound,
@@ -128,10 +128,10 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('c881797d-12ff-4f1a-b09d-9f6212159753')
- def test_get_nonexistent_extra_spec_id(self):
+ def test_get_nonexistent_extra_spec_name(self):
# Should not get volume type extra spec for nonexistent extra spec
- # id.
+ # name.
self.assertRaises(
lib_exc.NotFound,
self.admin_volume_types_client.show_volume_type_extra_specs,
- self.volume_type['id'], data_utils.rand_uuid())
+ self.volume_type['id'], "nonexistent_extra_spec_name")
diff --git a/tempest/api/volume/admin/test_volume_types_negative.py b/tempest/api/volume/admin/test_volume_types_negative.py
index 4cad52a..ae29049 100644
--- a/tempest/api/volume/admin/test_volume_types_negative.py
+++ b/tempest/api/volume/admin/test_volume_types_negative.py
@@ -22,15 +22,6 @@
class VolumeTypesNegativeTest(base.BaseVolumeAdminTest):
@decorators.attr(type=['negative'])
- @decorators.idempotent_id('b48c98f2-e662-4885-9b71-032256906314')
- def test_create_with_nonexistent_volume_type(self):
- # Should not be able to create volume with nonexistent volume_type.
- params = {'name': data_utils.rand_uuid(),
- 'volume_type': data_utils.rand_uuid()}
- self.assertRaises(lib_exc.NotFound,
- self.volumes_client.create_volume, **params)
-
- @decorators.attr(type=['negative'])
@decorators.idempotent_id('878b4e57-faa2-4659-b0d1-ce740a06ae81')
def test_create_with_empty_name(self):
# Should not be able to create volume type with an empty name.
diff --git a/tempest/api/volume/admin/test_volumes_actions.py b/tempest/api/volume/admin/test_volumes_actions.py
index b81a477..8d09217 100644
--- a/tempest/api/volume/admin/test_volumes_actions.py
+++ b/tempest/api/volume/admin/test_volumes_actions.py
@@ -14,10 +14,10 @@
# under the License.
from tempest.api.volume import base
+from tempest.common import utils
from tempest.common import waiters
from tempest import config
from tempest.lib import decorators
-from tempest import test
CONF = config.CONF
@@ -30,6 +30,8 @@
if status:
self.admin_volume_client.reset_volume_status(
temp_volume['id'], status=status)
+ waiters.wait_for_volume_resource_status(
+ self.volumes_client, temp_volume['id'], status)
self.admin_volume_client.force_delete_volume(temp_volume['id'])
self.volumes_client.wait_for_resource_deletion(temp_volume['id'])
@@ -37,14 +39,15 @@
def test_volume_reset_status(self):
# test volume reset status : available->error->available
volume = self.create_volume()
+ self.addCleanup(waiters.wait_for_volume_resource_status,
+ self.volumes_client, volume['id'], 'available')
self.addCleanup(self.admin_volume_client.reset_volume_status,
volume['id'], status='available')
for status in ['error', 'available', 'maintenance']:
self.admin_volume_client.reset_volume_status(
volume['id'], status=status)
- volume_get = self.admin_volume_client.show_volume(
- volume['id'])['volume']
- self.assertEqual(status, volume_get['status'])
+ waiters.wait_for_volume_resource_status(
+ self.volumes_client, volume['id'], status)
@decorators.idempotent_id('21737d5a-92f2-46d7-b009-a0cc0ee7a570')
def test_volume_force_delete_when_volume_is_creating(self):
@@ -67,7 +70,7 @@
self._create_reset_and_force_delete_temp_volume('maintenance')
@decorators.idempotent_id('d38285d9-929d-478f-96a5-00e66a115b81')
- @test.services('compute')
+ @utils.services('compute')
def test_force_detach_volume(self):
# Create a server and a volume
server_id = self.create_server()['id']
@@ -88,6 +91,8 @@
# Reset volume's status to error
self.admin_volume_client.reset_volume_status(volume_id, status='error')
+ waiters.wait_for_volume_resource_status(self.volumes_client,
+ volume_id, 'error')
# Force detach volume
self.admin_volume_client.force_detach_volume(
diff --git a/tempest/api/volume/admin/test_volumes_backup.py b/tempest/api/volume/admin/test_volumes_backup.py
index afc3281..375aacb 100644
--- a/tempest/api/volume/admin/test_volumes_backup.py
+++ b/tempest/api/volume/admin/test_volumes_backup.py
@@ -99,8 +99,7 @@
'available')
# Verify Import Backup
- backups = self.admin_backups_client.list_backups(
- detail=True)['backups']
+ backups = self.admin_backups_client.list_backups()['backups']
self.assertIn(new_id, [b['id'] for b in backups])
# Restore backup
diff --git a/tempest/api/volume/admin/test_volumes_list.py b/tempest/api/volume/admin/test_volumes_list.py
index 9d98b7a..6ce4a85 100644
--- a/tempest/api/volume/admin/test_volumes_list.py
+++ b/tempest/api/volume/admin/test_volumes_list.py
@@ -45,9 +45,9 @@
# Create a volume in admin tenant
adm_vol = self.admin_volume_client.create_volume(
size=CONF.volume.volume_size)['volume']
+ self.addCleanup(self.admin_volume_client.delete_volume, adm_vol['id'])
waiters.wait_for_volume_resource_status(self.admin_volume_client,
adm_vol['id'], 'available')
- self.addCleanup(self.admin_volume_client.delete_volume, adm_vol['id'])
params = {'all_tenants': 1,
'project_id': self.volumes_client.tenant_id}
# Getting volume list from primary tenant using admin credentials
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index 9142dc3..63ef85b 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -72,6 +72,11 @@
if cls._api_version == 3:
cls.backups_client = cls.os_primary.backups_v3_client
cls.volumes_client = cls.os_primary.volumes_v3_client
+ cls.messages_client = cls.os_primary.volume_v3_messages_client
+ cls.versions_client = cls.os_primary.volume_v3_versions_client
+ cls.groups_client = cls.os_primary.groups_v3_client
+ cls.group_snapshots_client = (
+ cls.os_primary.group_snapshots_v3_client)
else:
cls.backups_client = cls.os_primary.backups_v2_client
cls.volumes_client = cls.os_primary.volumes_v2_client
@@ -82,10 +87,6 @@
cls.availability_zone_client = (
cls.os_primary.volume_v2_availability_zone_client)
cls.volume_limits_client = cls.os_primary.volume_v2_limits_client
- cls.messages_client = cls.os_primary.volume_v3_messages_client
- cls.versions_client = cls.os_primary.volume_v3_versions_client
- cls.groups_client = cls.os_primary.groups_v3_client
- cls.group_snapshots_client = cls.os_primary.group_snapshots_v3_client
def setUp(self):
super(BaseVolumeTest, self).setUp()
@@ -259,6 +260,11 @@
cls.admin_volume_client = cls.os_admin.volumes_v2_client
if cls._api_version == 3:
cls.admin_volume_client = cls.os_admin.volumes_v3_client
+ cls.admin_groups_client = cls.os_admin.groups_v3_client
+ cls.admin_messages_client = cls.os_admin.volume_v3_messages_client
+ cls.admin_group_snapshots_client = \
+ cls.os_admin.group_snapshots_v3_client
+ cls.admin_group_types_client = cls.os_admin.group_types_v3_client
cls.admin_hosts_client = cls.os_admin.volume_hosts_v2_client
cls.admin_snapshot_manage_client = \
cls.os_admin.snapshot_manage_v2_client
@@ -274,11 +280,6 @@
cls.os_admin.volume_capabilities_v2_client
cls.admin_scheduler_stats_client = \
cls.os_admin.volume_scheduler_stats_v2_client
- cls.admin_messages_client = cls.os_admin.volume_v3_messages_client
- cls.admin_groups_client = cls.os_admin.groups_v3_client
- cls.admin_group_snapshots_client = \
- cls.os_admin.group_snapshots_v3_client
- cls.admin_group_types_client = cls.os_admin.group_types_v3_client
@classmethod
def resource_setup(cls):
diff --git a/tempest/api/volume/test_image_metadata.py b/tempest/api/volume/test_image_metadata.py
index 129981b..53b3acc 100644
--- a/tempest/api/volume/test_image_metadata.py
+++ b/tempest/api/volume/test_image_metadata.py
@@ -16,9 +16,9 @@
from testtools import matchers
from tempest.api.volume import base
+from tempest.common import utils
from tempest import config
from tempest.lib import decorators
-from tempest import test
CONF = config.CONF
@@ -39,7 +39,7 @@
cls.volume = cls.create_volume(imageRef=CONF.compute.image_ref)
@decorators.idempotent_id('03efff0b-5c75-4822-8f10-8789ac15b13e')
- @test.services('image')
+ @utils.services('image')
def test_update_show_delete_image_metadata(self):
# Update image metadata
image_metadata = {'image_id': '5137a025-3c5f-43c1-bc64-5f41270040a5',
diff --git a/tempest/api/volume/test_versions.py b/tempest/api/volume/test_versions.py
index 0083a3b..b4d48db 100644
--- a/tempest/api/volume/test_versions.py
+++ b/tempest/api/volume/test_versions.py
@@ -26,4 +26,4 @@
# NOTE: The version data is checked on service client side
# with JSON-Schema validation. It is enough to just call
# the API here.
- self.versions_client.list_versions()['versions']
+ self.versions_client.list_versions()
diff --git a/tempest/api/volume/test_volumes_actions.py b/tempest/api/volume/test_volumes_actions.py
index c4d10c3..be5638e 100644
--- a/tempest/api/volume/test_volumes_actions.py
+++ b/tempest/api/volume/test_volumes_actions.py
@@ -14,12 +14,12 @@
# under the License.
from tempest.api.volume import base
+from tempest.common import utils
from tempest.common import waiters
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib.common.utils import test_utils
from tempest.lib import decorators
-from tempest import test
CONF = config.CONF
@@ -35,7 +35,7 @@
@decorators.idempotent_id('fff42874-7db5-4487-a8e1-ddda5fb5288d')
@decorators.attr(type='smoke')
- @test.services('compute')
+ @utils.services('compute')
def test_attach_detach_volume_to_instance(self):
# Create a server
server = self.create_server()
@@ -66,7 +66,7 @@
fetched_volume['bootable'])
@decorators.idempotent_id('9516a2c8-9135-488c-8dd6-5677a7e5f371')
- @test.services('compute')
+ @utils.services('compute')
def test_get_volume_attachment(self):
# Create a server
server = self.create_server()
@@ -94,7 +94,7 @@
self.assertEqual(self.volume['id'], attachment['volume_id'])
@decorators.idempotent_id('d8f1ca95-3d5b-44a3-b8ca-909691c9532d')
- @test.services('image')
+ @utils.services('image')
def test_volume_upload(self):
# NOTE(gfidente): the volume uploaded in Glance comes from setUpClass,
# it is shared with the other tests. After it is uploaded in Glance,
@@ -112,6 +112,10 @@
waiters.wait_for_volume_resource_status(self.volumes_client,
self.volume['id'], 'available')
+ image_info = self.images_client.show_image(image_id)
+ self.assertEqual(image_name, image_info['name'])
+ self.assertEqual(CONF.volume.disk_format, image_info['disk_format'])
+
@decorators.idempotent_id('92c4ef64-51b2-40c0-9f7e-4749fbaaba33')
def test_reserve_unreserve_volume(self):
# Mark volume as reserved.
diff --git a/tempest/api/volume/test_volumes_backup.py b/tempest/api/volume/test_volumes_backup.py
index 1f91db6..1e240b8 100644
--- a/tempest/api/volume/test_volumes_backup.py
+++ b/tempest/api/volume/test_volumes_backup.py
@@ -17,11 +17,11 @@
from testtools import matchers
from tempest.api.volume import base
+from tempest.common import utils
from tempest.common import waiters
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
-from tempest import test
CONF = config.CONF
@@ -83,6 +83,9 @@
# Get all backups with detail
backups = self.backups_client.list_backups(
detail=True)['backups']
+ for backup_info in backups:
+ self.assertIn('created_at', backup_info)
+ self.assertIn('links', backup_info)
self.assertIn((backup['name'], backup['id']),
[(m['name'], m['id']) for m in backups])
@@ -97,7 +100,7 @@
matchers.ContainsAll(metadata.items()))
@decorators.idempotent_id('07af8f6d-80af-44c9-a5dc-c8427b1b62e6')
- @test.services('compute')
+ @utils.services('compute')
def test_backup_create_attached_volume(self):
"""Test backup create using force flag.
@@ -119,7 +122,7 @@
self.assertEqual(backup_name, backup['name'])
@decorators.idempotent_id('2a8ba340-dff2-4511-9db7-646f07156b15')
- @test.services('image')
+ @utils.services('image')
def test_bootable_volume_backup_and_restore(self):
# Create volume from image
img_uuid = CONF.compute.image_ref
diff --git a/tempest/api/volume/test_volumes_clone.py b/tempest/api/volume/test_volumes_clone.py
index 927bfa5..ea39a21 100644
--- a/tempest/api/volume/test_volumes_clone.py
+++ b/tempest/api/volume/test_volumes_clone.py
@@ -14,9 +14,9 @@
# under the License.
from tempest.api.volume import base
+from tempest.common import utils
from tempest import config
from tempest.lib import decorators
-from tempest import test
CONF = config.CONF
@@ -56,7 +56,7 @@
self._verify_volume_clone(src_vol, dst_vol, extra_size=1)
@decorators.idempotent_id('cbbcd7c6-5a6c-481a-97ac-ca55ab715d16')
- @test.services('image')
+ @utils.services('image')
def test_create_from_bootable_volume(self):
# Create volume from image
img_uuid = CONF.compute.image_ref
diff --git a/tempest/api/volume/test_volumes_get.py b/tempest/api/volume/test_volumes_get.py
index ec9a0dd..71db95c 100644
--- a/tempest/api/volume/test_volumes_get.py
+++ b/tempest/api/volume/test_volumes_get.py
@@ -17,11 +17,11 @@
from testtools import matchers
from tempest.api.volume import base
+from tempest.common import utils
from tempest.common import waiters
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
-from tempest import test
CONF = config.CONF
@@ -122,7 +122,7 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('54a01030-c7fc-447c-86ee-c1182beae638')
- @test.services('image')
+ @utils.services('image')
def test_volume_create_get_update_delete_from_image(self):
image = self.images_client.show_image(CONF.compute.image_ref)
min_disk = image['min_disk']
diff --git a/tempest/api/volume/test_volumes_list.py b/tempest/api/volume/test_volumes_list.py
index 8593d3a..b5f98ea 100644
--- a/tempest/api/volume/test_volumes_list.py
+++ b/tempest/api/volume/test_volumes_list.py
@@ -50,7 +50,7 @@
return
def str_vol(vol):
- return "%s:%s" % (vol['id'], vol[self.name])
+ return "%s:%s" % (vol['id'], vol['name'])
raw_msg = "Could not find volumes %s in expected list %s; fetched %s"
self.fail(raw_msg % ([str_vol(v) for v in missing_vols],
@@ -60,7 +60,6 @@
@classmethod
def resource_setup(cls):
super(VolumesListTestJSON, cls).resource_setup()
- cls.name = cls.VOLUME_FIELDS[1]
existing_volumes = cls.volumes_client.list_volumes()['volumes']
cls.volume_id_list = [vol['id'] for vol in existing_volumes]
@@ -117,22 +116,20 @@
@decorators.idempotent_id('a28e8da4-0b56-472f-87a8-0f4d3f819c02')
def test_volume_list_by_name(self):
volume = self.volume_list[data_utils.rand_int_id(0, 2)]
- params = {self.name: volume[self.name]}
+ params = {'name': volume['name']}
fetched_vol = self.volumes_client.list_volumes(
params=params)['volumes']
self.assertEqual(1, len(fetched_vol), str(fetched_vol))
- self.assertEqual(fetched_vol[0][self.name],
- volume[self.name])
+ self.assertEqual(fetched_vol[0]['name'], volume['name'])
@decorators.idempotent_id('2de3a6d4-12aa-403b-a8f2-fdeb42a89623')
def test_volume_list_details_by_name(self):
volume = self.volume_list[data_utils.rand_int_id(0, 2)]
- params = {self.name: volume[self.name]}
+ params = {'name': volume['name']}
fetched_vol = self.volumes_client.list_volumes(
detail=True, params=params)['volumes']
self.assertEqual(1, len(fetched_vol), str(fetched_vol))
- self.assertEqual(fetched_vol[0][self.name],
- volume[self.name])
+ self.assertEqual(fetched_vol[0]['name'], volume['name'])
@decorators.idempotent_id('39654e13-734c-4dab-95ce-7613bf8407ce')
def test_volumes_list_by_status(self):
@@ -213,7 +210,7 @@
def test_volume_list_param_display_name_and_status(self):
# Test to list volume when display name and status param is given
volume = self.volume_list[data_utils.rand_int_id(0, 2)]
- params = {self.name: volume[self.name],
+ params = {'name': volume['name'],
'status': 'available'}
self._list_by_param_value_and_assert(params)
@@ -221,7 +218,7 @@
def test_volume_list_with_detail_param_display_name_and_status(self):
# Test to list volume when name and status param is given
volume = self.volume_list[data_utils.rand_int_id(0, 2)]
- params = {self.name: volume[self.name],
+ params = {'name': volume['name'],
'status': 'available'}
self._list_by_param_value_and_assert(params, with_detail=True)
diff --git a/tempest/api/volume/test_volumes_negative.py b/tempest/api/volume/test_volumes_negative.py
index 4e19e62..f139283 100644
--- a/tempest/api/volume/test_volumes_negative.py
+++ b/tempest/api/volume/test_volumes_negative.py
@@ -16,13 +16,13 @@
import six
from tempest.api.volume import base
+from tempest.common import utils
from tempest.common import waiters
from tempest import config
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
-from tempest import test
CONF = config.CONF
@@ -35,7 +35,6 @@
# Create a test shared instance and volume for attach/detach tests
cls.volume = cls.create_volume()
- cls.mountpoint = "/dev/vdc"
def create_image(self):
# Create image
@@ -168,7 +167,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('f5e56b0a-5d02-43c1-a2a7-c9b792c2e3f6')
- @test.services('compute')
+ @utils.services('compute')
def test_attach_volumes_with_nonexistent_volume_id(self):
server = self.create_server()
@@ -176,7 +175,7 @@
self.volumes_client.attach_volume,
data_utils.rand_uuid(),
instance_uuid=server['id'],
- mountpoint=self.mountpoint)
+ mountpoint="/dev/vdc")
@decorators.attr(type=['negative'])
@decorators.idempotent_id('9f9c24e4-011d-46b5-b992-952140ce237a')
@@ -292,7 +291,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('5b810c91-0ad1-47ce-aee8-615f789be78f')
- @test.services('image')
+ @utils.services('image')
def test_create_volume_from_image_with_decreasing_size(self):
# Create image
image = self.create_image()
@@ -307,7 +306,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('d15e7f35-2cfc-48c8-9418-c8223a89bcbb')
- @test.services('image')
+ @utils.services('image')
def test_create_volume_from_deactivated_image(self):
# Create image
image = self.create_image()
diff --git a/tempest/api/volume/test_volumes_snapshots.py b/tempest/api/volume/test_volumes_snapshots.py
index e68ab7e..dcd3518 100644
--- a/tempest/api/volume/test_volumes_snapshots.py
+++ b/tempest/api/volume/test_volumes_snapshots.py
@@ -14,11 +14,11 @@
from testtools import matchers
from tempest.api.volume import base
+from tempest.common import utils
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
-from tempest import test
CONF = config.CONF
@@ -37,7 +37,7 @@
cls.volume_origin = cls.create_volume()
@decorators.idempotent_id('8567b54c-4455-446d-a1cf-651ddeaa3ff2')
- @test.services('compute')
+ @utils.services('compute')
def test_snapshot_create_delete_with_volume_in_use(self):
# Create a test instance
server = self.create_server()
@@ -59,7 +59,7 @@
self.delete_snapshot(snapshot2['id'])
@decorators.idempotent_id('5210a1de-85a0-11e6-bb21-641c676a5d61')
- @test.services('compute')
+ @utils.services('compute')
def test_snapshot_create_offline_delete_online(self):
# Create a snapshot while it is not attached
diff --git a/tempest/cmd/cleanup.py b/tempest/cmd/cleanup.py
index ac73cbf..a128b3f 100644
--- a/tempest/cmd/cleanup.py
+++ b/tempest/cmd/cleanup.py
@@ -104,7 +104,8 @@
def init(self, parsed_args):
cleanup_service.init_conf()
self.options = parsed_args
- self.admin_mgr = credentials.AdminManager()
+ self.admin_mgr = clients.Manager(
+ credentials.get_configured_admin_credentials())
self.dry_run_data = {}
self.json_data = {}
@@ -263,9 +264,10 @@
def _remove_admin_role(self, tenant_id):
LOG.debug("Remove admin user role for tenant: %s", tenant_id)
- # Must initialize AdminManager for each user role
+ # Must initialize Admin Manager for each user role
# Otherwise authentication exception is thrown, weird
- id_cl = credentials.AdminManager().identity_client
+ id_cl = clients.Manager(
+ credentials.get_configured_admin_credentials()).identity_client
if (self._tenant_exists(tenant_id)):
try:
id_cl.delete_role_from_user_on_project(tenant_id,
diff --git a/tempest/cmd/cleanup_service.py b/tempest/cmd/cleanup_service.py
index 11cd4bb..c75bc85 100644
--- a/tempest/cmd/cleanup_service.py
+++ b/tempest/cmd/cleanup_service.py
@@ -16,11 +16,12 @@
from oslo_log import log as logging
+from tempest import clients
from tempest.common import credentials_factory as credentials
from tempest.common import identity
+from tempest.common import utils
from tempest.common.utils import net_info
from tempest import config
-from tempest import test
LOG = logging.getLogger(__name__)
CONF = config.CONF
@@ -78,7 +79,8 @@
def _get_network_id(net_name, project_name):
- am = credentials.AdminManager()
+ am = clients.Manager(
+ credentials.get_configured_admin_credentials())
net_cl = am.networks_client
tn_cl = am.tenants_client
@@ -962,7 +964,7 @@
tenant_services.append(StackService)
if IS_NEUTRON:
tenant_services.append(NetworkFloatingIpService)
- if test.is_extension_enabled('metering', 'network'):
+ if utils.is_extension_enabled('metering', 'network'):
tenant_services.append(NetworkMeteringLabelRuleService)
tenant_services.append(NetworkMeteringLabelService)
tenant_services.append(NetworkRouterService)
diff --git a/tempest/cmd/run.py b/tempest/cmd/run.py
index 350dd0b..e71032a 100644
--- a/tempest/cmd/run.py
+++ b/tempest/cmd/run.py
@@ -101,6 +101,7 @@
import six
from testrepository.commands import run_argv
+from tempest import clients
from tempest.cmd import cleanup_service
from tempest.cmd import init
from tempest.cmd import workspace
@@ -216,7 +217,8 @@
print("Initializing saved state.")
data = {}
self.global_services = cleanup_service.get_global_cleanup_services()
- self.admin_mgr = credentials.AdminManager()
+ self.admin_mgr = clients.Manager(
+ credentials.get_configured_admin_credentials())
admin_mgr = self.admin_mgr
kwargs = {'data': data,
'is_dry_run': False,
diff --git a/tempest/common/compute.py b/tempest/common/compute.py
index 47196ec..df0f5a5 100644
--- a/tempest/common/compute.py
+++ b/tempest/common/compute.py
@@ -198,9 +198,27 @@
body = rest_client.ResponseBody(body.response, body['server'])
servers = [body]
- # The name of the method to associate a floating IP to as server is too
- # long for PEP8 compliance so:
- assoc = clients.compute_floating_ips_client.associate_floating_ip_to_server
+ def _setup_validation_fip():
+ if CONF.service_available.neutron:
+ ifaces = clients.interfaces_client.list_interfaces(server['id'])
+ validation_port = None
+ for iface in ifaces['interfaceAttachments']:
+ if iface['net_id'] == tenant_network['id']:
+ validation_port = iface['port_id']
+ break
+ if not validation_port:
+ # NOTE(artom) This will get caught by the catch-all clause in
+ # the wait_until loop below
+ raise ValueError('Unable to setup floating IP for validation: '
+ 'port not found on tenant network')
+ clients.floating_ips_client.update_floatingip(
+ validation_resources['floating_ip']['id'],
+ port_id=validation_port)
+ else:
+ fip_client = clients.compute_floating_ips_client
+ fip_client.associate_floating_ip_to_server(
+ floating_ip=validation_resources['floating_ip']['ip'],
+ server_id=servers[0]['id'])
if wait_until:
for server in servers:
@@ -212,9 +230,7 @@
# creation will fail with the condition above (l.58).
if CONF.validation.run_validation and validatable:
if CONF.validation.connect_method == 'floating':
- assoc(floating_ip=validation_resources[
- 'floating_ip']['ip'],
- server_id=servers[0]['id'])
+ _setup_validation_fip()
except Exception:
with excutils.save_and_reraise_exception():
diff --git a/tempest/common/utils/__init__.py b/tempest/common/utils/__init__.py
index 84e31d0..5a86caa 100644
--- a/tempest/common/utils/__init__.py
+++ b/tempest/common/utils/__init__.py
@@ -12,10 +12,16 @@
# License for the specific language governing permissions and limitations
# under the License.
+import functools
from functools import partial
+import testtools
+
from tempest import config
+from tempest.exceptions import InvalidServiceTag
from tempest.lib.common.utils import data_utils as lib_data_utils
+from tempest.lib import decorators
+
CONF = config.CONF
@@ -36,3 +42,89 @@
return attr_obj
data_utils = DataUtils()
+
+
+def get_service_list():
+ service_list = {
+ 'compute': CONF.service_available.nova,
+ 'image': CONF.service_available.glance,
+ 'volume': CONF.service_available.cinder,
+ # NOTE(masayukig): We have two network services which are neutron and
+ # nova-network. And we have no way to know whether nova-network is
+ # available or not. After the pending removal of nova-network from
+ # nova, we can treat the network/neutron case in the same manner as
+ # the other services.
+ 'network': True,
+ # NOTE(masayukig): Tempest tests always require the identity service.
+ # So we should set this True here.
+ 'identity': True,
+ 'object_storage': CONF.service_available.swift,
+ }
+ return service_list
+
+
+def services(*args):
+ """A decorator used to set an attr for each service used in a test case
+
+ This decorator applies a testtools attr for each service that gets
+ exercised by a test case.
+ """
+ def decorator(f):
+ known_services = get_service_list()
+
+ for service in args:
+ if service not in known_services:
+ raise InvalidServiceTag('%s is not a valid service' % service)
+ decorators.attr(type=list(args))(f)
+
+ @functools.wraps(f)
+ def wrapper(self, *func_args, **func_kwargs):
+ service_list = get_service_list()
+
+ for service in args:
+ if not service_list[service]:
+ msg = 'Skipped because the %s service is not available' % (
+ service)
+ raise testtools.TestCase.skipException(msg)
+ return f(self, *func_args, **func_kwargs)
+ return wrapper
+ return decorator
+
+
+def requires_ext(**kwargs):
+ """A decorator to skip tests if an extension is not enabled
+
+ @param extension
+ @param service
+ """
+ def decorator(func):
+ @functools.wraps(func)
+ def wrapper(*func_args, **func_kwargs):
+ if not is_extension_enabled(kwargs['extension'],
+ kwargs['service']):
+ msg = "Skipped because %s extension: %s is not enabled" % (
+ kwargs['service'], kwargs['extension'])
+ raise testtools.TestCase.skipException(msg)
+ return func(*func_args, **func_kwargs)
+ return wrapper
+ return decorator
+
+
+def is_extension_enabled(extension_name, service):
+ """A function that will check the list of enabled extensions from config
+
+ """
+ config_dict = {
+ 'compute': CONF.compute_feature_enabled.api_extensions,
+ 'volume': CONF.volume_feature_enabled.api_extensions,
+ 'network': CONF.network_feature_enabled.api_extensions,
+ 'object': CONF.object_storage_feature_enabled.discoverable_apis,
+ 'identity': CONF.identity_feature_enabled.api_extensions
+ }
+ if not config_dict[service]:
+ return False
+ if config_dict[service][0] == 'all':
+ return True
+ if extension_name in config_dict[service]:
+ return True
+ return False
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index 99a628e..52ccfa9 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -70,7 +70,7 @@
if selected:
return "\n".join(selected)
else:
- msg = "'TYPE' column is requred but the output doesn't have it: "
+ msg = "'TYPE' column is required but the output doesn't have it: "
raise tempest.lib.exceptions.TempestException(msg + output)
def get_boot_time(self):
diff --git a/tempest/common/validation_resources.py b/tempest/common/validation_resources.py
index 9e83a07..3a04b9a 100644
--- a/tempest/common/validation_resources.py
+++ b/tempest/common/validation_resources.py
@@ -1,4 +1,5 @@
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
+# Copyright (c) 2017 IBM Corp.
# 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
@@ -12,77 +13,191 @@
# limitations under the License.
from oslo_log import log as logging
-
-from tempest import config
+from oslo_utils import excutils
from tempest.lib.common.utils import data_utils
from tempest.lib import exceptions as lib_exc
-CONF = config.CONF
LOG = logging.getLogger(__name__)
-def _create_neutron_sec_group_rules(os, sec_group):
- sec_group_rules_client = os.security_group_rules_client
- ethertype = 'IPv4'
- if CONF.validation.ip_version_for_ssh == 6:
- ethertype = 'IPv6'
-
- sec_group_rules_client.create_security_group_rule(
- security_group_id=sec_group['id'],
- protocol='tcp',
- ethertype=ethertype,
- port_range_min=22,
- port_range_max=22,
- direction='ingress')
- sec_group_rules_client.create_security_group_rule(
- security_group_id=sec_group['id'],
- protocol='icmp',
- ethertype=ethertype,
- direction='ingress')
+def _network_service(clients, use_neutron):
+ # Internal helper to select the right network clients
+ if use_neutron:
+ return clients.network
+ else:
+ return clients.compute
-def create_ssh_security_group(os, add_rule=False):
- security_groups_client = os.compute_security_groups_client
- security_group_rules_client = os.compute_security_group_rules_client
+def create_ssh_security_group(clients, add_rule=False, ethertype='IPv4',
+ use_neutron=True):
+ """Create a security group for ping/ssh testing
+
+ Create a security group to be attached to a VM using the nova or neutron
+ clients. If rules are added, the group can be attached to a VM to enable
+ connectivity validation over ICMP and further testing over SSH.
+
+ :param clients: Instance of `tempest.lib.services.clients.ServiceClients`
+ or of a subclass of it. Resources are provisioned using clients from
+ `clients`.
+ :param add_rule: Whether security group rules are provisioned or not.
+ Defaults to `False`.
+ :param ethertype: 'IPv4' or 'IPv6'. Honoured only in case neutron is used.
+ :param use_neutron: When True resources are provisioned via neutron, when
+ False resources are provisioned via nova.
+ :returns: A dictionary with the security group as returned by the API.
+
+ Examples::
+
+ from tempest.common import validation_resources as vr
+ from tempest.lib import auth
+ from tempest.lib.services import clients
+
+ creds = auth.get_credentials('http://mycloud/identity/v3',
+ username='me', project_name='me',
+ password='secret', domain_name='Default')
+ osclients = clients.ServiceClients(creds, 'http://mycloud/identity/v3')
+ # Security group for IPv4 tests
+ sg4 = vr.create_ssh_security_group(osclients, add_rule=True)
+ # Security group for IPv6 tests
+ sg6 = vr.create_ssh_security_group(osclients, ethertype='IPv6',
+ add_rule=True)
+ """
+ network_service = _network_service(clients, use_neutron)
+ security_groups_client = network_service.SecurityGroupsClient()
+ security_group_rules_client = network_service.SecurityGroupRulesClient()
+ # Security Group clients for nova and neutron behave the same
sg_name = data_utils.rand_name('securitygroup-')
sg_description = data_utils.rand_name('description-')
security_group = security_groups_client.create_security_group(
name=sg_name, description=sg_description)['security_group']
+ # Security Group Rules clients require different parameters depending on
+ # the network service in use
if add_rule:
- if CONF.service_available.neutron:
- _create_neutron_sec_group_rules(os, security_group)
- else:
- security_group_rules_client.create_security_group_rule(
- parent_group_id=security_group['id'], ip_protocol='tcp',
- from_port=22, to_port=22)
- security_group_rules_client.create_security_group_rule(
- parent_group_id=security_group['id'], ip_protocol='icmp',
- from_port=-1, to_port=-1)
+ try:
+ if use_neutron:
+ security_group_rules_client.create_security_group_rule(
+ security_group_id=security_group['id'],
+ protocol='tcp',
+ ethertype=ethertype,
+ port_range_min=22,
+ port_range_max=22,
+ direction='ingress')
+ security_group_rules_client.create_security_group_rule(
+ security_group_id=security_group['id'],
+ protocol='icmp',
+ ethertype=ethertype,
+ direction='ingress')
+ else:
+ security_group_rules_client.create_security_group_rule(
+ parent_group_id=security_group['id'], ip_protocol='tcp',
+ from_port=22, to_port=22)
+ security_group_rules_client.create_security_group_rule(
+ parent_group_id=security_group['id'], ip_protocol='icmp',
+ from_port=-1, to_port=-1)
+ except Exception as sgc_exc:
+ # If adding security group rules fails, we cleanup the SG before
+ # re-raising the failure up
+ with excutils.save_and_reraise_exception():
+ try:
+ msg = ('Error while provisioning security group rules in '
+ 'security group %s. Trying to cleanup.')
+ # The exceptions logging is already handled, so using
+ # debug here just to provide more context
+ LOG.debug(msg, sgc_exc)
+ clear_validation_resources(
+ clients, keypair=None, floating_ip=None,
+ security_group=security_group,
+ use_neutron=use_neutron)
+ except Exception as cleanup_exc:
+ msg = ('Error during cleanup of a security group. '
+ 'The cleanup was triggered by an exception during '
+ 'the provisioning of security group rules.\n'
+ 'Provisioning exception: %s\n'
+ 'First cleanup exception: %s')
+ LOG.exception(msg, sgc_exc, cleanup_exc)
LOG.debug("SSH Validation resource security group with tcp and icmp "
"rules %s created", sg_name)
return security_group
-def create_validation_resources(os, validation_resources=None):
+def create_validation_resources(clients, keypair=False, floating_ip=False,
+ security_group=False,
+ security_group_rules=False,
+ ethertype='IPv4', use_neutron=True,
+ floating_network_id=None,
+ floating_network_name=None):
+ """Provision resources for VM ping/ssh testing
+
+ Create resources required to be able to ping / ssh a virtual machine:
+ keypair, security group, security group rules and a floating IP.
+ Which of those resources are required may depend on the cloud setup and on
+ the specific test and it can be controlled via the corresponding
+ arguments.
+
+ Provisioned resources are returned in a dictionary.
+
+ :param clients: Instance of `tempest.lib.services.clients.ServiceClients`
+ or of a subclass of it. Resources are provisioned using clients from
+ `clients`.
+ :param keypair: Whether to provision a keypair. Defaults to False.
+ :param floating_ip: Whether to provision a floating IP. Defaults to False.
+ :param security_group: Whether to provision a security group. Defaults to
+ False.
+ :param security_group_rules: Whether to provision security group rules.
+ Defaults to False.
+ :param ethertype: 'IPv4' or 'IPv6'. Honoured only in case neutron is used.
+ :param use_neutron: When True resources are provisioned via neutron, when
+ False resources are provisioned via nova.
+ :param floating_network_id: The id of the network used to provision a
+ floating IP. Only used if a floating IP is requested and with neutron.
+ :param floating_network_name: The name of the floating IP pool used to
+ provision the floating IP. Only used if a floating IP is requested and
+ with nova-net.
+ :returns: A dictionary with the resources in the format they are returned
+ by the API. Valid keys are 'keypair', 'floating_ip' and
+ 'security_group'.
+
+ Examples::
+
+ from tempest.common import validation_resources as vr
+ from tempest.lib import auth
+ from tempest.lib.services import clients
+
+ creds = auth.get_credentials('http://mycloud/identity/v3',
+ username='me', project_name='me',
+ password='secret', domain_name='Default')
+ osclients = clients.ServiceClients(creds, 'http://mycloud/identity/v3')
+ # Request keypair and floating IP
+ resources = dict(keypair=True, security_group=False,
+ security_group_rules=False, floating_ip=True)
+ resources = vr.create_validation_resources(
+ osclients, use_neutron=True,
+ floating_network_id='4240E68E-23DA-4C82-AC34-9FEFAA24521C',
+ **resources)
+
+ # The floating IP to be attached to the VM
+ floating_ip = resources['floating_ip']['ip']
+ """
# Create and Return the validation resources required to validate a VM
validation_data = {}
- if validation_resources:
- if validation_resources['keypair']:
+ try:
+ if keypair:
keypair_name = data_utils.rand_name('keypair')
- validation_data.update(os.keypairs_client.create_keypair(
- name=keypair_name))
+ validation_data.update(
+ clients.compute.KeyPairsClient().create_keypair(
+ name=keypair_name))
LOG.debug("Validation resource key %s created", keypair_name)
- add_rule = False
- if validation_resources['security_group']:
- if validation_resources['security_group_rules']:
- add_rule = True
- validation_data['security_group'] = \
- create_ssh_security_group(os, add_rule)
- if validation_resources['floating_ip']:
- if CONF.service_available.neutron:
- floatingip = os.floating_ips_client.create_floatingip(
- floating_network_id=CONF.network.public_network_id)
+ if security_group:
+ validation_data['security_group'] = create_ssh_security_group(
+ clients, add_rule=security_group_rules,
+ use_neutron=use_neutron, ethertype=ethertype)
+ if floating_ip:
+ floating_ip_client = _network_service(
+ clients, use_neutron).FloatingIPsClient()
+ if use_neutron:
+ floatingip = floating_ip_client.create_floatingip(
+ floating_network_id=floating_network_id)
# validation_resources['floating_ip'] has historically looked
# like a compute API POST /os-floating-ips response, so we need
# to mangle it a bit for a Neutron response with different
@@ -94,61 +209,134 @@
# NOTE(mriedem): The os-floating-ips compute API was deprecated
# in the 2.36 microversion. Any tests for CRUD operations on
# floating IPs using the compute API should be capped at 2.35.
- validation_data.update(
- os.compute_floating_ips_client.create_floating_ip(
- pool=CONF.network.floating_network_name))
+ validation_data.update(floating_ip_client.create_floating_ip(
+ pool=floating_network_name))
+ LOG.debug("Validation resource floating IP %s created",
+ validation_data['floating_ip'])
+ except Exception as prov_exc:
+ # If something goes wrong, cleanup as much as possible before we
+ # re-raise the exception
+ with excutils.save_and_reraise_exception():
+ if validation_data:
+ # Cleanup may fail as well
+ try:
+ msg = ('Error while provisioning validation resources %s. '
+ 'Trying to cleanup what we provisioned so far: %s')
+ # The exceptions logging is already handled, so using
+ # debug here just to provide more context
+ LOG.debug(msg, prov_exc, str(validation_data))
+ clear_validation_resources(
+ clients,
+ keypair=validation_data.get('keypair', None),
+ floating_ip=validation_data.get('floating_ip', None),
+ security_group=validation_data.get('security_group',
+ None),
+ use_neutron=use_neutron)
+ except Exception as cleanup_exc:
+ msg = ('Error during cleanup of validation resources. '
+ 'The cleanup was triggered by an exception during '
+ 'the provisioning step.\n'
+ 'Provisioning exception: %s\n'
+ 'First cleanup exception: %s')
+ LOG.exception(msg, prov_exc, cleanup_exc)
return validation_data
-def clear_validation_resources(os, validation_data=None):
- # Cleanup the vm validation resources
+def clear_validation_resources(clients, keypair=None, floating_ip=None,
+ security_group=None, use_neutron=True):
+ """Cleanup resources for VM ping/ssh testing
+
+ Cleanup a set of resources provisioned via `create_validation_resources`.
+ In case of errors during cleanup, the exception is logged and the cleanup
+ process is continued. The first exception that was raised is re-raised
+ after the cleanup is complete.
+
+ :param clients: Instance of `tempest.lib.services.clients.ServiceClients`
+ or of a subclass of it. Resources are provisioned using clients from
+ `clients`.
+ :param keypair: A dictionary with the keypair to be deleted. Defaults to
+ None.
+ :param floating_ip: A dictionary with the floating_ip to be deleted.
+ Defaults to None.
+ :param security_group: A dictionary with the security_group to be deleted.
+ Defaults to None.
+ :param use_neutron: When True resources are provisioned via neutron, when
+ False resources are provisioned via nova.
+
+ Examples::
+
+ from tempest.common import validation_resources as vr
+ from tempest.lib import auth
+ from tempest.lib.services import clients
+
+ creds = auth.get_credentials('http://mycloud/identity/v3',
+ username='me', project_name='me',
+ password='secret', domain_name='Default')
+ osclients = clients.ServiceClients(creds, 'http://mycloud/identity/v3')
+ # Request keypair and floating IP
+ resources = dict(keypair=True, security_group=False,
+ security_group_rules=False, floating_ip=True)
+ resources = vr.create_validation_resources(
+ osclients, validation_resources=resources, use_neutron=True,
+ floating_network_id='4240E68E-23DA-4C82-AC34-9FEFAA24521C')
+
+ # Now cleanup the resources
+ try:
+ vr.clear_validation_resources(osclients, use_neutron=True,
+ **resources)
+ except Exception as e:
+ LOG.exception('Something went wrong during cleanup, ignoring')
+ """
has_exception = None
- if validation_data:
- if 'keypair' in validation_data:
- keypair_client = os.keypairs_client
- keypair_name = validation_data['keypair']['name']
- try:
- keypair_client.delete_keypair(keypair_name)
- except lib_exc.NotFound:
- LOG.warning(
- "Keypair %s is not found when attempting to delete",
- keypair_name
- )
- except Exception as exc:
- LOG.exception('Exception raised while deleting key %s',
- keypair_name)
- if not has_exception:
- has_exception = exc
- if 'security_group' in validation_data:
- security_group_client = os.compute_security_groups_client
- sec_id = validation_data['security_group']['id']
- try:
- security_group_client.delete_security_group(sec_id)
- security_group_client.wait_for_resource_deletion(sec_id)
- except lib_exc.NotFound:
- LOG.warning("Security group %s is not found when attempting "
- "to delete", sec_id)
- except lib_exc.Conflict as exc:
- LOG.exception('Conflict while deleting security '
- 'group %s VM might not be deleted', sec_id)
- if not has_exception:
- has_exception = exc
- except Exception as exc:
- LOG.exception('Exception raised while deleting security '
- 'group %s', sec_id)
- if not has_exception:
- has_exception = exc
- if 'floating_ip' in validation_data:
- floating_client = os.compute_floating_ips_client
- fip_id = validation_data['floating_ip']['id']
- try:
- floating_client.delete_floating_ip(fip_id)
- except lib_exc.NotFound:
- LOG.warning('Floating ip %s not found while attempting to '
- 'delete', fip_id)
- except Exception as exc:
- LOG.exception('Exception raised while deleting ip %s', fip_id)
- if not has_exception:
- has_exception = exc
+ if keypair:
+ keypair_client = clients.compute.KeyPairsClient()
+ keypair_name = keypair['name']
+ try:
+ keypair_client.delete_keypair(keypair_name)
+ except lib_exc.NotFound:
+ LOG.warning(
+ "Keypair %s is not found when attempting to delete",
+ keypair_name
+ )
+ except Exception as exc:
+ LOG.exception('Exception raised while deleting key %s',
+ keypair_name)
+ if not has_exception:
+ has_exception = exc
+ network_service = _network_service(clients, use_neutron)
+ if security_group:
+ security_group_client = network_service.SecurityGroupsClient()
+ sec_id = security_group['id']
+ try:
+ security_group_client.delete_security_group(sec_id)
+ security_group_client.wait_for_resource_deletion(sec_id)
+ except lib_exc.NotFound:
+ LOG.warning("Security group %s is not found when attempting "
+ "to delete", sec_id)
+ except lib_exc.Conflict as exc:
+ LOG.exception('Conflict while deleting security '
+ 'group %s VM might not be deleted', sec_id)
+ if not has_exception:
+ has_exception = exc
+ except Exception as exc:
+ LOG.exception('Exception raised while deleting security '
+ 'group %s', sec_id)
+ if not has_exception:
+ has_exception = exc
+ if floating_ip:
+ floating_ip_client = network_service.FloatingIPsClient()
+ fip_id = floating_ip['id']
+ try:
+ if use_neutron:
+ floating_ip_client.delete_floatingip(fip_id)
+ else:
+ floating_ip_client.delete_floating_ip(fip_id)
+ except lib_exc.NotFound:
+ LOG.warning('Floating ip %s not found while attempting to '
+ 'delete', fip_id)
+ except Exception as exc:
+ LOG.exception('Exception raised while deleting ip %s', fip_id)
+ if not has_exception:
+ has_exception = exc
if has_exception:
raise has_exception
diff --git a/tempest/common/waiters.py b/tempest/common/waiters.py
index f4c2866..10afee0 100644
--- a/tempest/common/waiters.py
+++ b/tempest/common/waiters.py
@@ -211,6 +211,8 @@
(resource_name, resource_id, statuses, resource_status,
client.build_timeout))
raise lib_exc.TimeoutException(message)
+ LOG.info('%s %s reached %s after waiting for %f seconds',
+ resource_name, resource_id, statuses, time.time() - start)
def wait_for_volume_retype(client, volume_id, new_volume_type):
diff --git a/tempest/config.py b/tempest/config.py
index af9eefc..e78a07f 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -234,6 +234,12 @@
deprecated_reason="This feature flag was introduced to "
"support testing of old OpenStack versions, "
"which are not supported anymore"),
+ cfg.BoolOpt('domain_specific_drivers',
+ default=False,
+ help='Are domain specific drivers enabled? '
+ 'This configuration value should be same as '
+ '[identity]->domain_specific_drivers_enabled '
+ 'in keystone.conf.'),
cfg.BoolOpt('security_compliance',
default=False,
help='Does the environment have the security compliance '
diff --git a/tempest/exceptions.py b/tempest/exceptions.py
index b5b2d71..a8a6ff0 100644
--- a/tempest/exceptions.py
+++ b/tempest/exceptions.py
@@ -54,3 +54,7 @@
class RFCViolation(exceptions.RestClientException):
message = "RFC Violation"
+
+
+class InvalidServiceTag(exceptions.TempestException):
+ message = "Invalid service tag"
diff --git a/tempest/lib/api_schema/response/compute/v2_1/parameter_types.py b/tempest/lib/api_schema/response/compute/v2_1/parameter_types.py
index a3c9099..28ed816 100644
--- a/tempest/lib/api_schema/response/compute/v2_1/parameter_types.py
+++ b/tempest/lib/api_schema/response/compute/v2_1/parameter_types.py
@@ -65,7 +65,7 @@
'items': {
'type': 'object',
'properties': {
- 'version': {'type': 'integer'},
+ 'version': {'enum': [4, 6]},
'addr': {
'type': 'string',
'oneOf': [
diff --git a/tempest/lib/common/api_version_utils.py b/tempest/lib/common/api_version_utils.py
index 1371b3c..98f174d 100644
--- a/tempest/lib/common/api_version_utils.py
+++ b/tempest/lib/common/api_version_utils.py
@@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+from oslo_log import log as logging
import testtools
from tempest.lib.common import api_version_request
@@ -19,6 +20,7 @@
LATEST_MICROVERSION = 'latest'
+LOG = logging.getLogger(__name__)
class BaseMicroversionTest(object):
@@ -120,3 +122,60 @@
api_microversion,
response_header))
raise exceptions.InvalidHTTPResponseHeader(msg)
+
+
+def compare_version_header_to_response(api_microversion_header_name,
+ api_microversion,
+ response_header,
+ operation='eq'):
+ """Compares API microversion in response header to ``api_microversion``.
+
+ Compare the ``api_microversion`` value in response header if microversion
+ header is present in response, otherwise return false.
+
+ To make this function work for APIs which do not return microversion
+ header in response (example compute v2.0), this function does *not* raise
+ InvalidHTTPResponseHeader.
+
+ :param api_microversion_header_name: Microversion header name. Example:
+ 'Openstack-Api-Version'.
+ :param api_microversion: Microversion number. Example:
+
+ * '2.10' for the old-style header name, 'X-OpenStack-Nova-API-Version'
+ * 'Compute 2.10' for the new-style header name, 'Openstack-Api-Version'
+
+ :param response_header: Response header where microversion is
+ expected to be present.
+ :param operation: The boolean operation to use to compare the
+ ``api_microversion`` to the microversion in ``response_header``.
+ Can be 'lt', 'eq', 'gt', 'le', 'ne', 'ge'. Default is 'eq'. The
+ operation type should be based on the order of the arguments:
+ ``api_microversion`` <operation> ``response_header`` microversion.
+ :returns: True if the comparison is logically true, else False if the
+ comparison is logically false or if ``api_microversion_header_name`` is
+ missing in the ``response_header``.
+ :raises InvalidParam: If the operation is not lt, eq, gt, le, ne or ge.
+ """
+ api_microversion_header_name = api_microversion_header_name.lower()
+ if api_microversion_header_name not in response_header:
+ return False
+
+ op = getattr(api_version_request.APIVersionRequest,
+ '__%s__' % operation, None)
+
+ if op is None:
+ msg = ("Operation %s is invalid. Valid options include: lt, eq, gt, "
+ "le, ne, ge." % operation)
+ LOG.debug(msg)
+ raise exceptions.InvalidParam(invalid_param=msg)
+
+ # Remove "volume" from "volume <microversion>", for example, so that the
+ # microversion can be converted to `APIVersionRequest`.
+ api_version = api_microversion.split(' ')[-1]
+ resp_version = response_header[api_microversion_header_name].split(' ')[-1]
+ if not op(
+ api_version_request.APIVersionRequest(api_version),
+ api_version_request.APIVersionRequest(resp_version)):
+ return False
+
+ return True
diff --git a/tempest/lib/common/dynamic_creds.py b/tempest/lib/common/dynamic_creds.py
index 90e67b4..4f1a883 100644
--- a/tempest/lib/common/dynamic_creds.py
+++ b/tempest/lib/common/dynamic_creds.py
@@ -28,6 +28,43 @@
class DynamicCredentialProvider(cred_provider.CredentialProvider):
+ """Creates credentials dynamically for tests
+
+ A credential provider that, based on an initial set of
+ admin credentials, creates new credentials on the fly for
+ tests to use and then discard.
+
+ :param str identity_version: identity API version to use `v2` or `v3`
+ :param str admin_role: name of the admin role added to admin users
+ :param str name: names of dynamic resources include this parameter
+ when specified
+ :param str credentials_domain: name of the domain where the users
+ are created. If not defined, the project
+ domain from admin_credentials is used
+ :param dict network_resources: network resources to be created for
+ the created credentials
+ :param Credentials admin_creds: initial admin credentials
+ :param bool identity_admin_domain_scope: Set to true if admin should be
+ scoped to the domain. By
+ default this is False and the
+ admin role is scoped to the
+ project.
+ :param str identity_admin_role: The role name to use for admin
+ :param list extra_roles: A list of strings for extra roles that should
+ be assigned to all created users
+ :param bool neutron_available: Whether we are running in an environemnt
+ with neutron
+ :param bool create_networks: Whether dynamic project networks should be
+ created or not
+ :param project_network_cidr: The CIDR to use for created project
+ networks
+ :param project_network_mask_bits: The network mask bits to use for
+ created project networks
+ :param public_network_id: The id for the public network to use
+ :param identity_admin_endpoint_type: The endpoint type for identity
+ admin clients. Defaults to public.
+ :param identity_uri: Identity URI of the target cloud
+ """
def __init__(self, identity_version, name=None, network_resources=None,
credentials_domain=None, admin_role=None, admin_creds=None,
@@ -37,43 +74,6 @@
project_network_cidr=None, project_network_mask_bits=None,
public_network_id=None, resource_prefix=None,
identity_admin_endpoint_type='public', identity_uri=None):
- """Creates credentials dynamically for tests
-
- A credential provider that, based on an initial set of
- admin credentials, creates new credentials on the fly for
- tests to use and then discard.
-
- :param str identity_version: identity API version to use `v2` or `v3`
- :param str admin_role: name of the admin role added to admin users
- :param str name: names of dynamic resources include this parameter
- when specified
- :param str credentials_domain: name of the domain where the users
- are created. If not defined, the project
- domain from admin_credentials is used
- :param dict network_resources: network resources to be created for
- the created credentials
- :param Credentials admin_creds: initial admin credentials
- :param bool identity_admin_domain_scope: Set to true if admin should be
- scoped to the domain. By
- default this is False and the
- admin role is scoped to the
- project.
- :param str identity_admin_role: The role name to use for admin
- :param list extra_roles: A list of strings for extra roles that should
- be assigned to all created users
- :param bool neutron_available: Whether we are running in an environemnt
- with neutron
- :param bool create_networks: Whether dynamic project networks should be
- created or not
- :param project_network_cidr: The CIDR to use for created project
- networks
- :param project_network_mask_bits: The network mask bits to use for
- created project networks
- :param public_network_id: The id for the public network to use
- :param identity_admin_endpoint_type: The endpoint type for identity
- admin clients. Defaults to public.
- :param identity_uri: Identity URI of the target cloud
- """
super(DynamicCredentialProvider, self).__init__(
identity_version=identity_version, identity_uri=identity_uri,
admin_role=admin_role, name=name,
@@ -451,7 +451,7 @@
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
+ # here cannot use test_utils.is_extension_enabled for it will cause
# "circular dependency". So here just use try...except to
# ensure tenant deletion without big changes.
try:
diff --git a/tempest/lib/common/http.py b/tempest/lib/common/http.py
index 8a47d44..b4b1fc9 100644
--- a/tempest/lib/common/http.py
+++ b/tempest/lib/common/http.py
@@ -25,8 +25,7 @@
if disable_ssl_certificate_validation:
urllib3.disable_warnings()
kwargs['cert_reqs'] = 'CERT_NONE'
-
- if ca_certs:
+ elif ca_certs:
kwargs['cert_reqs'] = 'CERT_REQUIRED'
kwargs['ca_certs'] = ca_certs
diff --git a/tempest/lib/common/preprov_creds.py b/tempest/lib/common/preprov_creds.py
index cd3a10e..83db513 100644
--- a/tempest/lib/common/preprov_creds.py
+++ b/tempest/lib/common/preprov_creds.py
@@ -41,6 +41,35 @@
class PreProvisionedCredentialProvider(cred_provider.CredentialProvider):
+ """Credentials provider using pre-provisioned accounts
+
+ This credentials provider loads the details of pre-provisioned
+ accounts from a YAML file, in the format specified by
+ ``etc/accounts.yaml.sample``. It locks accounts while in use, using the
+ external locking mechanism, allowing for multiple python processes
+ to share a single account file, and thus running tests in parallel.
+
+ The accounts_lock_dir must be generated using `lockutils.get_lock_path`
+ from the oslo.concurrency library. For instance::
+
+ accounts_lock_dir = os.path.join(lockutils.get_lock_path(CONF),
+ 'test_accounts')
+
+ Role names for object storage are optional as long as the
+ `operator` and `reseller_admin` credential types are not used in the
+ accounts file.
+
+ :param identity_version: identity version of the credentials
+ :param admin_role: name of the admin role
+ :param test_accounts_file: path to the accounts YAML file
+ :param accounts_lock_dir: the directory for external locking
+ :param name: name of the hash file (optional)
+ :param credentials_domain: name of the domain credentials belong to
+ (if no domain is configured)
+ :param object_storage_operator_role: name of the role
+ :param object_storage_reseller_admin_role: name of the role
+ :param identity_uri: Identity URI of the target cloud
+ """
# Exclude from the hash fields specific to v2 or v3 identity API
# i.e. only include user*, project*, tenant* and password
@@ -51,35 +80,6 @@
accounts_lock_dir, name=None, credentials_domain=None,
admin_role=None, object_storage_operator_role=None,
object_storage_reseller_admin_role=None, identity_uri=None):
- """Credentials provider using pre-provisioned accounts
-
- This credentials provider loads the details of pre-provisioned
- accounts from a YAML file, in the format specified by
- `etc/accounts.yaml.sample`. It locks accounts while in use, using the
- external locking mechanism, allowing for multiple python processes
- to share a single account file, and thus running tests in parallel.
-
- The accounts_lock_dir must be generated using `lockutils.get_lock_path`
- from the oslo.concurrency library. For instance:
-
- accounts_lock_dir = os.path.join(lockutils.get_lock_path(CONF),
- 'test_accounts')
-
- Role names for object storage are optional as long as the
- `operator` and `reseller_admin` credential types are not used in the
- accounts file.
-
- :param identity_version: identity version of the credentials
- :param admin_role: name of the admin role
- :param test_accounts_file: path to the accounts YAML file
- :param accounts_lock_dir: the directory for external locking
- :param name: name of the hash file (optional)
- :param credentials_domain: name of the domain credentials belong to
- (if no domain is configured)
- :param object_storage_operator_role: name of the role
- :param object_storage_reseller_admin_role: name of the role
- :param identity_uri: Identity URI of the target cloud
- """
super(PreProvisionedCredentialProvider, self).__init__(
identity_version=identity_version, name=name,
admin_role=admin_role, credentials_domain=credentials_domain,
diff --git a/tempest/lib/common/utils/linux/remote_client.py b/tempest/lib/common/utils/linux/remote_client.py
index aef2ff3..cd4092b 100644
--- a/tempest/lib/common/utils/linux/remote_client.py
+++ b/tempest/lib/common/utils/linux/remote_client.py
@@ -67,7 +67,7 @@
def __init__(self, ip_address, username, password=None, pkey=None,
server=None, servers_client=None, ssh_timeout=300,
connect_timeout=60, console_output_enabled=True,
- ssh_shell_prologue="set -eu -o pipefail; PATH=$$PATH:/sbin;",
+ ssh_shell_prologue="set -eu -o pipefail; PATH=$PATH:/sbin;",
ping_count=1, ping_size=56):
"""Executes commands in a VM over ssh
diff --git a/tempest/lib/exceptions.py b/tempest/lib/exceptions.py
index c538c72..9b2e87e 100644
--- a/tempest/lib/exceptions.py
+++ b/tempest/lib/exceptions.py
@@ -276,3 +276,7 @@
class InvalidTestResource(TempestException):
message = "%(name)s is not a valid %(type)s, or the name is ambiguous"
+
+
+class InvalidParam(TempestException):
+ message = ("Invalid Parameter passed: %(invalid_param)s")
diff --git a/tempest/lib/services/network/security_groups_client.py b/tempest/lib/services/network/security_groups_client.py
index 1f30216..d3ebf20 100644
--- a/tempest/lib/services/network/security_groups_client.py
+++ b/tempest/lib/services/network/security_groups_client.py
@@ -10,6 +10,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+from tempest.lib import exceptions as lib_exc
from tempest.lib.services.network import base
@@ -66,3 +67,10 @@
"""
uri = '/security-groups'
return self.list_resources(uri, **filters)
+
+ def is_resource_deleted(self, id):
+ try:
+ self.show_security_group(id)
+ except lib_exc.NotFound:
+ return True
+ return False
diff --git a/tempest/lib/services/volume/v2/volumes_client.py b/tempest/lib/services/volume/v2/volumes_client.py
index e932adc..d13e449 100644
--- a/tempest/lib/services/volume/v2/volumes_client.py
+++ b/tempest/lib/services/volume/v2/volumes_client.py
@@ -197,10 +197,18 @@
return rest_client.ResponseBody(resp, body)
def is_resource_deleted(self, id):
+ """Check the specified resource is deleted or not.
+
+ :param id: A checked resource id
+ :raises lib_exc.DeleteErrorException: If the specified resource is on
+ the status the delete was failed.
+ """
try:
- self.show_volume(id)
+ volume = self.show_volume(id)
except lib_exc.NotFound:
return True
+ if volume["volume"]["status"] == "error_deleting":
+ raise lib_exc.DeleteErrorException(resource_id=id)
return False
@property
diff --git a/tempest/scenario/test_aggregates_basic_ops.py b/tempest/scenario/test_aggregates_basic_ops.py
index 25227be..9ff6227 100644
--- a/tempest/scenario/test_aggregates_basic_ops.py
+++ b/tempest/scenario/test_aggregates_basic_ops.py
@@ -14,10 +14,10 @@
# under the License.
from tempest.common import tempest_fixtures as fixtures
+from tempest.common import utils
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.scenario import manager
-from tempest import test
class TestAggregatesBasicOps(manager.ScenarioTest):
@@ -97,7 +97,7 @@
@decorators.idempotent_id('cb2b4c4f-0c7c-4164-bdde-6285b302a081')
@decorators.attr(type='slow')
- @test.services('compute')
+ @utils.services('compute')
def test_aggregate_basic_ops(self):
self.useFixture(fixtures.LockFixture('availability_zone'))
az = 'foo_zone'
diff --git a/tempest/scenario/test_encrypted_cinder_volumes.py b/tempest/scenario/test_encrypted_cinder_volumes.py
index cbdf307..b5220e9 100644
--- a/tempest/scenario/test_encrypted_cinder_volumes.py
+++ b/tempest/scenario/test_encrypted_cinder_volumes.py
@@ -13,10 +13,10 @@
# License for the specific language governing permissions and limitations
# under the License.
+from tempest.common import utils
from tempest import config
from tempest.lib import decorators
from tempest.scenario import manager
-from tempest import test
CONF = config.CONF
@@ -54,7 +54,7 @@
@decorators.idempotent_id('79165fb4-5534-4b9d-8429-97ccffb8f86e')
@decorators.attr(type='slow')
- @test.services('compute', 'volume', 'image')
+ @utils.services('compute', 'volume', 'image')
def test_encrypted_cinder_volumes_luks(self):
server = self.launch_instance()
volume = self.create_encrypted_volume('nova.volume.encryptors.'
@@ -64,7 +64,7 @@
@decorators.idempotent_id('cbc752ed-b716-4717-910f-956cce965722')
@decorators.attr(type='slow')
- @test.services('compute', 'volume', 'image')
+ @utils.services('compute', 'volume', 'image')
def test_encrypted_cinder_volumes_cryptsetup(self):
server = self.launch_instance()
volume = self.create_encrypted_volume('nova.volume.encryptors.'
diff --git a/tempest/scenario/test_minimum_basic.py b/tempest/scenario/test_minimum_basic.py
index 26a834b..29f1743 100644
--- a/tempest/scenario/test_minimum_basic.py
+++ b/tempest/scenario/test_minimum_basic.py
@@ -16,13 +16,13 @@
import testtools
from tempest.common import custom_matchers
+from tempest.common import utils
from tempest.common import waiters
from tempest import config
from tempest.lib.common.utils import test_utils
from tempest.lib import decorators
from tempest.lib import exceptions
from tempest.scenario import manager
-from tempest import test
CONF = config.CONF
@@ -105,7 +105,7 @@
'The public_network_id option must be specified.')
@testtools.skipUnless(CONF.network_feature_enabled.floating_ips,
'Floating ips are not available')
- @test.services('compute', 'volume', 'image', 'network')
+ @utils.services('compute', 'volume', 'image', 'network')
def test_minimum_basic_scenario(self):
image = self.glance_image_create()
keypair = self.create_keypair()
diff --git a/tempest/scenario/test_network_advanced_server_ops.py b/tempest/scenario/test_network_advanced_server_ops.py
index c8add8b..340c3c9 100644
--- a/tempest/scenario/test_network_advanced_server_ops.py
+++ b/tempest/scenario/test_network_advanced_server_ops.py
@@ -15,11 +15,11 @@
import testtools
+from tempest.common import utils
from tempest.common import waiters
from tempest import config
from tempest.lib import decorators
from tempest.scenario import manager
-from tempest import test
CONF = config.CONF
@@ -59,7 +59,7 @@
def _setup_server(self, keypair):
security_groups = []
- if test.is_extension_enabled('security-group', 'network'):
+ if utils.is_extension_enabled('security-group', 'network'):
security_group = self._create_security_group()
security_groups = [{'name': security_group['name']}]
network, _, _ = self.create_networks()
@@ -107,7 +107,7 @@
@decorators.idempotent_id('61f1aa9a-1573-410e-9054-afa557cab021')
@decorators.attr(type='slow')
- @test.services('compute', 'network')
+ @utils.services('compute', 'network')
def test_server_connectivity_stop_start(self):
keypair = self.create_keypair()
server = self._setup_server(keypair)
@@ -122,7 +122,7 @@
server, keypair, floating_ip)
@decorators.idempotent_id('7b6860c2-afa3-4846-9522-adeb38dfbe08')
- @test.services('compute', 'network')
+ @utils.services('compute', 'network')
def test_server_connectivity_reboot(self):
keypair = self.create_keypair()
server = self._setup_server(keypair)
@@ -133,7 +133,7 @@
@decorators.idempotent_id('88a529c2-1daa-4c85-9aec-d541ba3eb699')
@decorators.attr(type='slow')
- @test.services('compute', 'network')
+ @utils.services('compute', 'network')
def test_server_connectivity_rebuild(self):
keypair = self.create_keypair()
server = self._setup_server(keypair)
@@ -148,7 +148,7 @@
@testtools.skipUnless(CONF.compute_feature_enabled.pause,
'Pause is not available.')
@decorators.attr(type='slow')
- @test.services('compute', 'network')
+ @utils.services('compute', 'network')
def test_server_connectivity_pause_unpause(self):
keypair = self.create_keypair()
server = self._setup_server(keypair)
@@ -166,7 +166,7 @@
@testtools.skipUnless(CONF.compute_feature_enabled.suspend,
'Suspend is not available.')
@decorators.attr(type='slow')
- @test.services('compute', 'network')
+ @utils.services('compute', 'network')
def test_server_connectivity_suspend_resume(self):
keypair = self.create_keypair()
server = self._setup_server(keypair)
@@ -184,7 +184,7 @@
@testtools.skipUnless(CONF.compute_feature_enabled.resize,
'Resize is not available.')
@decorators.attr(type='slow')
- @test.services('compute', 'network')
+ @utils.services('compute', 'network')
def test_server_connectivity_resize(self):
resize_flavor = CONF.compute.flavor_ref_alt
keypair = self.create_keypair()
@@ -205,7 +205,7 @@
'Less than 2 compute nodes, skipping multinode '
'tests.')
@decorators.attr(type='slow')
- @test.services('compute', 'network')
+ @utils.services('compute', 'network')
def test_server_connectivity_cold_migration(self):
keypair = self.create_keypair()
server = self._setup_server(keypair)
@@ -231,7 +231,7 @@
'Less than 2 compute nodes, skipping multinode '
'tests.')
@decorators.attr(type='slow')
- @test.services('compute', 'network')
+ @utils.services('compute', 'network')
def test_server_connectivity_cold_migration_revert(self):
keypair = self.create_keypair()
server = self._setup_server(keypair)
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index 48ddac6..2d38b06 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -19,13 +19,13 @@
from oslo_log import log as logging
import testtools
+from tempest.common import utils
from tempest.common import waiters
from tempest import config
from tempest.lib.common.utils import test_utils
from tempest.lib import decorators
from tempest.lib import exceptions
from tempest.scenario import manager
-from tempest import test
CONF = config.CONF
LOG = logging.getLogger(__name__)
@@ -87,7 +87,7 @@
'public_network_id must be defined.')
raise cls.skipException(msg)
for ext in ['router', 'security-group']:
- if not test.is_extension_enabled(ext, 'network'):
+ if not utils.is_extension_enabled(ext, 'network'):
msg = "%s extension not enabled." % ext
raise cls.skipException(msg)
if not CONF.network_feature_enabled.floating_ips:
@@ -357,7 +357,7 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('f323b3ba-82f8-4db7-8ea6-6a895869ec49')
- @test.services('compute', 'network')
+ @utils.services('compute', 'network')
def test_network_basic_ops(self):
"""Basic network operation test
@@ -409,10 +409,10 @@
"floating ip")
@decorators.idempotent_id('b158ea55-472e-4086-8fa9-c64ac0c6c1d0')
- @testtools.skipUnless(test.is_extension_enabled('net-mtu', 'network'),
+ @testtools.skipUnless(utils.is_extension_enabled('net-mtu', 'network'),
'No way to calculate MTU for networks')
@decorators.attr(type='slow')
- @test.services('compute', 'network')
+ @utils.services('compute', 'network')
def test_mtu_sized_frames(self):
"""Validate that network MTU sized frames fit through."""
self._setup_network_and_servers()
@@ -425,7 +425,7 @@
'multitenant network environment')
@decorators.skip_because(bug="1610994")
@decorators.attr(type='slow')
- @test.services('compute', 'network')
+ @utils.services('compute', 'network')
def test_connectivity_between_vms_on_different_networks(self):
"""Test connectivity between VMs on different networks
@@ -479,7 +479,7 @@
@testtools.skipIf(CONF.network.port_vnic_type in ['direct', 'macvtap'],
'NIC hotplug not supported for '
'vnic_type direct or macvtap')
- @test.services('compute', 'network')
+ @utils.services('compute', 'network')
def test_hotplug_nic(self):
"""Test hotplug network interface
@@ -501,7 +501,7 @@
'Router state can be altered only with multitenant '
'networks capabilities')
@decorators.attr(type='slow')
- @test.services('compute', 'network')
+ @utils.services('compute', 'network')
def test_update_router_admin_state(self):
"""Test to update admin state up of router
@@ -535,7 +535,7 @@
@testtools.skipUnless(CONF.scenario.dhcp_client,
"DHCP client is not available.")
@decorators.attr(type='slow')
- @test.services('compute', 'network')
+ @utils.services('compute', 'network')
def test_subnet_details(self):
"""Tests that subnet's extra configuration details are affecting VMs.
@@ -619,7 +619,7 @@
"Changing a port's admin state is not supported "
"by the test environment")
@decorators.attr(type='slow')
- @test.services('compute', 'network')
+ @utils.services('compute', 'network')
def test_update_instance_port_admin_state(self):
"""Test to update admin_state_up attribute of instance port
@@ -666,7 +666,7 @@
@decorators.idempotent_id('759462e1-8535-46b0-ab3a-33aa45c55aaa')
@decorators.attr(type='slow')
- @test.services('compute', 'network')
+ @utils.services('compute', 'network')
def test_preserve_preexisting_port(self):
"""Test preserve pre-existing port
@@ -715,10 +715,10 @@
'server %s.' % server['id'])
self.assertEqual(port['id'], port_list[0]['id'])
- @test.requires_ext(service='network', extension='l3_agent_scheduler')
+ @utils.requires_ext(service='network', extension='l3_agent_scheduler')
@decorators.idempotent_id('2e788c46-fb3f-4ac9-8f82-0561555bea73')
@decorators.attr(type='slow')
- @test.services('compute', 'network')
+ @utils.services('compute', 'network')
def test_router_rescheduling(self):
"""Tests that router can be removed from agent and add to a new agent.
@@ -793,12 +793,12 @@
should_connect=True,
msg='After router rescheduling')
- @test.requires_ext(service='network', extension='port-security')
+ @utils.requires_ext(service='network', extension='port-security')
@testtools.skipUnless(CONF.compute_feature_enabled.interface_attach,
'NIC hotplug not available')
@decorators.idempotent_id('7c0bb1a2-d053-49a4-98f9-ca1a1d849f63')
@decorators.attr(type='slow')
- @test.services('compute', 'network')
+ @utils.services('compute', 'network')
def test_port_security_macspoofing_port(self):
"""Tests port_security extension enforces mac spoofing
diff --git a/tempest/scenario/test_network_v6.py b/tempest/scenario/test_network_v6.py
index bf26c2e..b687aa0 100644
--- a/tempest/scenario/test_network_v6.py
+++ b/tempest/scenario/test_network_v6.py
@@ -14,11 +14,11 @@
# under the License.
import functools
+from tempest.common import utils
from tempest import config
from tempest.lib.common.utils import test_utils
from tempest.lib import decorators
from tempest.scenario import manager
-from tempest import test
CONF = config.CONF
@@ -210,49 +210,49 @@
@decorators.attr(type='slow')
@decorators.idempotent_id('2c92df61-29f0-4eaa-bee3-7c65bef62a43')
- @test.services('compute', 'network')
+ @utils.services('compute', 'network')
def test_slaac_from_os(self):
self._prepare_and_test(address6_mode='slaac')
@decorators.attr(type='slow')
@decorators.idempotent_id('d7e1f858-187c-45a6-89c9-bdafde619a9f')
- @test.services('compute', 'network')
+ @utils.services('compute', 'network')
def test_dhcp6_stateless_from_os(self):
self._prepare_and_test(address6_mode='dhcpv6-stateless')
@decorators.attr(type='slow')
@decorators.idempotent_id('7ab23f41-833b-4a16-a7c9-5b42fe6d4123')
- @test.services('compute', 'network')
+ @utils.services('compute', 'network')
def test_multi_prefix_dhcpv6_stateless(self):
self._prepare_and_test(address6_mode='dhcpv6-stateless', n_subnets6=2)
@decorators.attr(type='slow')
@decorators.idempotent_id('dec222b1-180c-4098-b8c5-cc1b8342d611')
- @test.services('compute', 'network')
+ @utils.services('compute', 'network')
def test_multi_prefix_slaac(self):
self._prepare_and_test(address6_mode='slaac', n_subnets6=2)
@decorators.attr(type='slow')
@decorators.idempotent_id('b6399d76-4438-4658-bcf5-0d6c8584fde2')
- @test.services('compute', 'network')
+ @utils.services('compute', 'network')
def test_dualnet_slaac_from_os(self):
self._prepare_and_test(address6_mode='slaac', dualnet=True)
@decorators.attr(type='slow')
@decorators.idempotent_id('76f26acd-9688-42b4-bc3e-cd134c4cb09e')
- @test.services('compute', 'network')
+ @utils.services('compute', 'network')
def test_dualnet_dhcp6_stateless_from_os(self):
self._prepare_and_test(address6_mode='dhcpv6-stateless', dualnet=True)
@decorators.attr(type='slow')
@decorators.idempotent_id('cf1c4425-766b-45b8-be35-e2959728eb00')
- @test.services('compute', 'network')
+ @utils.services('compute', 'network')
def test_dualnet_multi_prefix_dhcpv6_stateless(self):
self._prepare_and_test(address6_mode='dhcpv6-stateless', n_subnets6=2,
dualnet=True)
@decorators.idempotent_id('9178ad42-10e4-47e9-8987-e02b170cc5cd')
- @test.services('compute', 'network')
+ @utils.services('compute', 'network')
def test_dualnet_multi_prefix_slaac(self):
self._prepare_and_test(address6_mode='slaac', n_subnets6=2,
dualnet=True)
diff --git a/tempest/scenario/test_object_storage_basic_ops.py b/tempest/scenario/test_object_storage_basic_ops.py
index 25e9f5c..da0b1e8 100644
--- a/tempest/scenario/test_object_storage_basic_ops.py
+++ b/tempest/scenario/test_object_storage_basic_ops.py
@@ -13,14 +13,14 @@
# License for the specific language governing permissions and limitations
# under the License.
+from tempest.common import utils
from tempest.lib import decorators
from tempest.scenario import manager
-from tempest import test
class TestObjectStorageBasicOps(manager.ObjectStorageScenarioTest):
@decorators.idempotent_id('b920faf1-7b8a-4657-b9fe-9c4512bfb381')
- @test.services('object_storage')
+ @utils.services('object_storage')
def test_swift_basic_ops(self):
"""Test swift basic ops.
@@ -47,7 +47,7 @@
@decorators.idempotent_id('916c7111-cb1f-44b2-816d-8f760e4ea910')
@decorators.attr(type='slow')
- @test.services('object_storage')
+ @utils.services('object_storage')
def test_swift_acl_anonymous_download(self):
"""This test will cover below steps:
diff --git a/tempest/scenario/test_security_groups_basic_ops.py b/tempest/scenario/test_security_groups_basic_ops.py
index 51716e8..e39afe0 100644
--- a/tempest/scenario/test_security_groups_basic_ops.py
+++ b/tempest/scenario/test_security_groups_basic_ops.py
@@ -16,12 +16,12 @@
import testtools
from tempest.common import compute
+from tempest.common import utils
from tempest.common.utils import net_info
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.scenario import manager
-from tempest import test
CONF = config.CONF
LOG = log.getLogger(__name__)
@@ -142,7 +142,7 @@
msg = ('Either project_networks_reachable must be "true", or '
'public_network_id must be defined.')
raise cls.skipException(msg)
- if not test.is_extension_enabled('security-group', 'network'):
+ if not utils.is_extension_enabled('security-group', 'network'):
msg = "security-group extension not enabled."
raise cls.skipException(msg)
if CONF.network.shared_physical_network:
@@ -471,7 +471,7 @@
servers=[tenant.access_point], client=client)
@decorators.idempotent_id('e79f879e-debb-440c-a7e4-efeda05b6848')
- @test.services('compute', 'network')
+ @utils.services('compute', 'network')
def test_cross_tenant_traffic(self):
if not self.credentials_provider.is_multi_tenant():
raise self.skipException("No secondary tenant defined")
@@ -491,7 +491,7 @@
raise
@decorators.idempotent_id('63163892-bbf6-4249-aa12-d5ea1f8f421b')
- @test.services('compute', 'network')
+ @utils.services('compute', 'network')
def test_in_tenant_traffic(self):
try:
self._create_tenant_servers(self.primary_tenant, num=1)
@@ -505,7 +505,7 @@
@decorators.idempotent_id('f4d556d7-1526-42ad-bafb-6bebf48568f6')
@decorators.attr(type='slow')
- @test.services('compute', 'network')
+ @utils.services('compute', 'network')
def test_port_update_new_security_group(self):
"""Verifies the traffic after updating the vm port
@@ -559,7 +559,7 @@
@decorators.idempotent_id('d2f77418-fcc4-439d-b935-72eca704e293')
@decorators.attr(type='slow')
- @test.services('compute', 'network')
+ @utils.services('compute', 'network')
def test_multiple_security_groups(self):
"""Verify multiple security groups and checks that rules
@@ -591,9 +591,9 @@
should_connect=True)
@decorators.attr(type='slow')
- @test.requires_ext(service='network', extension='port-security')
+ @utils.requires_ext(service='network', extension='port-security')
@decorators.idempotent_id('7c811dcc-263b-49a3-92d2-1b4d8405f50c')
- @test.services('compute', 'network')
+ @utils.services('compute', 'network')
def test_port_security_disable_security_group(self):
"""Verify the default security group rules is disabled."""
new_tenant = self.primary_tenant
@@ -631,7 +631,7 @@
raise
@decorators.attr(type='slow')
- @test.requires_ext(service='network', extension='port-security')
+ @utils.requires_ext(service='network', extension='port-security')
@decorators.idempotent_id('13ccf253-e5ad-424b-9c4a-97b88a026699')
# TODO(mriedem): We shouldn't actually need to check this since neutron
# disables the port_security extension by default, but the problem is nova
@@ -641,7 +641,7 @@
@testtools.skipUnless(
CONF.network_feature_enabled.port_security,
'Port security must be enabled.')
- @test.services('compute', 'network')
+ @utils.services('compute', 'network')
def test_boot_into_disabled_port_security_network_without_secgroup(self):
tenant = self.primary_tenant
self._create_tenant_network(tenant, port_security_enabled=False)
diff --git a/tempest/scenario/test_server_advanced_ops.py b/tempest/scenario/test_server_advanced_ops.py
index 6d6318c..d4f29ad 100644
--- a/tempest/scenario/test_server_advanced_ops.py
+++ b/tempest/scenario/test_server_advanced_ops.py
@@ -16,11 +16,11 @@
from oslo_log import log as logging
import testtools
+from tempest.common import utils
from tempest.common import waiters
from tempest import config
from tempest.lib import decorators
from tempest.scenario import manager
-from tempest import test
CONF = config.CONF
@@ -45,7 +45,7 @@
@decorators.idempotent_id('e6c28180-7454-4b59-b188-0257af08a63b')
@testtools.skipUnless(CONF.compute_feature_enabled.resize,
'Resize is not available.')
- @test.services('compute', 'volume')
+ @utils.services('compute', 'volume')
def test_resize_volume_backed_server_confirm(self):
# We create an instance for use in this test
instance = self.create_server(volume_backed=True)
@@ -67,7 +67,7 @@
@decorators.idempotent_id('949da7d5-72c8-4808-8802-e3d70df98e2c')
@testtools.skipUnless(CONF.compute_feature_enabled.suspend,
'Suspend is not available.')
- @test.services('compute')
+ @utils.services('compute')
def test_server_sequence_suspend_resume(self):
# We create an instance for use in this test
instance_id = self.create_server()['id']
diff --git a/tempest/scenario/test_server_basic_ops.py b/tempest/scenario/test_server_basic_ops.py
index 0c441ab..d5c378e 100644
--- a/tempest/scenario/test_server_basic_ops.py
+++ b/tempest/scenario/test_server_basic_ops.py
@@ -16,6 +16,7 @@
import json
import re
+from tempest.common import utils
from tempest.common import waiters
from tempest import config
from tempest.lib.common.utils import data_utils
@@ -23,7 +24,6 @@
from tempest.lib import decorators
from tempest.lib import exceptions
from tempest.scenario import manager
-from tempest import test
CONF = config.CONF
@@ -132,7 +132,7 @@
@decorators.idempotent_id('7fff3fb3-91d8-4fd0-bd7d-0204f1f180ba')
@decorators.attr(type='smoke')
- @test.services('compute', 'network')
+ @utils.services('compute', 'network')
def test_server_basic_ops(self):
keypair = self.create_keypair()
security_group = self._create_security_group()
diff --git a/tempest/scenario/test_server_multinode.py b/tempest/scenario/test_server_multinode.py
index 552ab27..fdf875c 100644
--- a/tempest/scenario/test_server_multinode.py
+++ b/tempest/scenario/test_server_multinode.py
@@ -13,11 +13,11 @@
# License for the specific language governing permissions and limitations
# under the License.
+from tempest.common import utils
from tempest import config
from tempest.lib import decorators
from tempest.lib import exceptions
from tempest.scenario import manager
-from tempest import test
CONF = config.CONF
@@ -36,7 +36,7 @@
@decorators.idempotent_id('9cecbe35-b9d4-48da-a37e-7ce70aa43d30')
@decorators.attr(type='smoke')
- @test.services('compute', 'network')
+ @utils.services('compute', 'network')
def test_schedule_to_all_nodes(self):
available_zone = \
self.os_admin.availability_zone_client.list_availability_zones(
diff --git a/tempest/scenario/test_shelve_instance.py b/tempest/scenario/test_shelve_instance.py
index fc04b44..68f18d1 100644
--- a/tempest/scenario/test_shelve_instance.py
+++ b/tempest/scenario/test_shelve_instance.py
@@ -16,11 +16,11 @@
import testtools
from tempest.common import compute
+from tempest.common import utils
from tempest.common import waiters
from tempest import config
from tempest.lib import decorators
from tempest.scenario import manager
-from tempest import test
CONF = config.CONF
@@ -78,7 +78,7 @@
@decorators.idempotent_id('1164e700-0af0-4a4c-8792-35909a88743c')
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
- @test.services('compute', 'network', 'image')
+ @utils.services('compute', 'network', 'image')
def test_shelve_instance(self):
self._create_server_then_shelve_and_unshelve()
@@ -86,6 +86,6 @@
@decorators.idempotent_id('c1b6318c-b9da-490b-9c67-9339b627271f')
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
- @test.services('compute', 'volume', 'network', 'image')
+ @utils.services('compute', 'volume', 'network', 'image')
def test_shelve_volume_backed_instance(self):
self._create_server_then_shelve_and_unshelve(boot_from_volume=True)
diff --git a/tempest/scenario/test_snapshot_pattern.py b/tempest/scenario/test_snapshot_pattern.py
index 52767dc..b51a781 100644
--- a/tempest/scenario/test_snapshot_pattern.py
+++ b/tempest/scenario/test_snapshot_pattern.py
@@ -15,10 +15,10 @@
import testtools
+from tempest.common import utils
from tempest import config
from tempest.lib import decorators
from tempest.scenario import manager
-from tempest import test
CONF = config.CONF
@@ -44,7 +44,7 @@
@decorators.attr(type='slow')
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
- @test.services('compute', 'network', 'image')
+ @utils.services('compute', 'network', 'image')
def test_snapshot_pattern(self):
# prepare for booting an instance
keypair = self.create_keypair()
diff --git a/tempest/scenario/test_stamp_pattern.py b/tempest/scenario/test_stamp_pattern.py
index 3632648..ef369d6 100644
--- a/tempest/scenario/test_stamp_pattern.py
+++ b/tempest/scenario/test_stamp_pattern.py
@@ -16,12 +16,12 @@
from oslo_log import log as logging
import testtools
+from tempest.common import utils
from tempest import config
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
-from tempest import test
CONF = config.CONF
LOG = logging.getLogger(__name__)
@@ -76,7 +76,7 @@
'Snapshotting is not available.')
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
- @test.services('compute', 'network', 'volume', 'image')
+ @utils.services('compute', 'network', 'volume', 'image')
def test_stamp_pattern(self):
# prepare for booting an instance
keypair = self.create_keypair()
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
index b6f3b38..64ea8f6 100644
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -13,12 +13,12 @@
from oslo_log import log as logging
import testtools
+from tempest.common import utils
from tempest.common import waiters
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.scenario import manager
-from tempest import test
CONF = config.CONF
LOG = logging.getLogger(__name__)
@@ -76,7 +76,7 @@
@decorators.idempotent_id('557cd2c2-4eb8-4dce-98be-f86765ff311b')
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
- @test.services('compute', 'volume', 'image')
+ @utils.services('compute', 'volume', 'image')
def test_volume_boot_pattern(self):
"""This test case attempts to reproduce the following steps:
@@ -156,7 +156,7 @@
@decorators.idempotent_id('05795fb2-b2a7-4c9f-8fac-ff25aedb1489')
@decorators.attr(type='slow')
- @test.services('compute', 'image', 'volume')
+ @utils.services('compute', 'image', 'volume')
def test_create_server_from_volume_snapshot(self):
# Create a volume from an image
boot_volume = self._create_volume_from_image()
@@ -192,7 +192,7 @@
created_volume_info['attachments'][0]['volume_id'])
@decorators.idempotent_id('36c34c67-7b54-4b59-b188-02a2f458a63b')
- @test.services('compute', 'volume', 'image')
+ @utils.services('compute', 'volume', 'image')
def test_create_ebs_image_and_check_boot(self):
# create an instance from volume
volume_origin = self._create_volume_from_image()
@@ -216,7 +216,7 @@
@decorators.idempotent_id('cb78919a-e553-4bab-b73b-10cf4d2eb125')
@testtools.skipUnless(CONF.compute_feature_enabled.attach_encrypted_volume,
'Encrypted volume attach is not supported')
- @test.services('compute', 'volume')
+ @utils.services('compute', 'volume')
def test_boot_server_from_encrypted_volume_luks(self):
# Create an encrypted volume
volume = self.create_encrypted_volume('nova.volume.encryptors.'
diff --git a/tempest/scenario/test_volume_migrate_attached.py b/tempest/scenario/test_volume_migrate_attached.py
index 5667fbb..cd10bbd 100644
--- a/tempest/scenario/test_volume_migrate_attached.py
+++ b/tempest/scenario/test_volume_migrate_attached.py
@@ -12,11 +12,11 @@
from oslo_log import log as logging
+from tempest.common import utils
from tempest.common import waiters
from tempest import config
from tempest.lib import decorators
from tempest.scenario import manager
-from tempest import test
CONF = config.CONF
LOG = logging.getLogger(__name__)
@@ -38,11 +38,6 @@
credentials = ['primary', 'admin']
@classmethod
- def setup_clients(cls):
- super(TestVolumeMigrateRetypeAttached, cls).setup_clients()
- cls.admin_volumes_client = cls.os_admin.volumes_v2_client
-
- @classmethod
def skip_checks(cls):
super(TestVolumeMigrateRetypeAttached, cls).skip_checks()
if not CONF.volume_feature_enabled.multi_backend:
@@ -82,7 +77,7 @@
def _volume_retype_with_migration(self, volume_id, new_volume_type):
migration_policy = 'on-demand'
- self.admin_volumes_client.retype_volume(
+ self.volumes_client.retype_volume(
volume_id, new_type=new_volume_type,
migration_policy=migration_policy)
waiters.wait_for_volume_retype(self.volumes_client,
@@ -90,7 +85,7 @@
@decorators.attr(type='slow')
@decorators.idempotent_id('deadd2c2-beef-4dce-98be-f86765ff311b')
- @test.services('compute', 'volume')
+ @utils.services('compute', 'volume')
def test_volume_migrate_attached(self):
LOG.info("Creating keypair and security group")
keypair = self.create_keypair()
diff --git a/tempest/test.py b/tempest/test.py
index 00f99d7..a4cc2cc 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -14,7 +14,6 @@
# under the License.
import atexit
-import functools
import os
import sys
@@ -26,6 +25,7 @@
from tempest import clients
from tempest.common import credentials_factory as credentials
+from tempest.common import utils
import tempest.common.validation_resources as vresources
from tempest import config
from tempest.lib.common import cred_client
@@ -49,95 +49,19 @@
version='Pike', removal_version='?')
-class InvalidServiceTag(lib_exc.TempestException):
- message = "Invalid service tag"
+services = debtcollector.moves.moved_function(
+ utils.services, 'services', __name__,
+ version='Pike', removal_version='?')
-def get_service_list():
- service_list = {
- 'compute': CONF.service_available.nova,
- 'image': CONF.service_available.glance,
- 'volume': CONF.service_available.cinder,
- # NOTE(masayukig): We have two network services which are neutron and
- # nova-network. And we have no way to know whether nova-network is
- # available or not. After the pending removal of nova-network from
- # nova, we can treat the network/neutron case in the same manner as
- # the other services.
- 'network': True,
- # NOTE(masayukig): Tempest tests always require the identity service.
- # So we should set this True here.
- 'identity': True,
- 'object_storage': CONF.service_available.swift,
- }
- return service_list
+requires_ext = debtcollector.moves.moved_function(
+ utils.requires_ext, 'requires_ext', __name__,
+ version='Pike', removal_version='?')
-def services(*args):
- """A decorator used to set an attr for each service used in a test case
-
- This decorator applies a testtools attr for each service that gets
- exercised by a test case.
- """
- def decorator(f):
- known_services = get_service_list()
-
- for service in args:
- if service not in known_services:
- raise InvalidServiceTag('%s is not a valid service' % service)
- decorators.attr(type=list(args))(f)
-
- @functools.wraps(f)
- def wrapper(self, *func_args, **func_kwargs):
- service_list = get_service_list()
-
- for service in args:
- if not service_list[service]:
- msg = 'Skipped because the %s service is not available' % (
- service)
- raise testtools.TestCase.skipException(msg)
- return f(self, *func_args, **func_kwargs)
- return wrapper
- return decorator
-
-
-def requires_ext(**kwargs):
- """A decorator to skip tests if an extension is not enabled
-
- @param extension
- @param service
- """
- def decorator(func):
- @functools.wraps(func)
- def wrapper(*func_args, **func_kwargs):
- if not is_extension_enabled(kwargs['extension'],
- kwargs['service']):
- msg = "Skipped because %s extension: %s is not enabled" % (
- kwargs['service'], kwargs['extension'])
- raise testtools.TestCase.skipException(msg)
- return func(*func_args, **func_kwargs)
- return wrapper
- return decorator
-
-
-def is_extension_enabled(extension_name, service):
- """A function that will check the list of enabled extensions from config
-
- """
- config_dict = {
- 'compute': CONF.compute_feature_enabled.api_extensions,
- 'volume': CONF.volume_feature_enabled.api_extensions,
- 'network': CONF.network_feature_enabled.api_extensions,
- 'object': CONF.object_storage_feature_enabled.discoverable_apis,
- 'identity': CONF.identity_feature_enabled.api_extensions
- }
- if not config_dict[service]:
- return False
- if config_dict[service][0] == 'all':
- return True
- if extension_name in config_dict[service]:
- return True
- return False
-
+is_extension_enabled = debtcollector.moves.moved_function(
+ utils.is_extension_enabled, 'is_extension_enabled', __name__,
+ version='Pike', removal_version='?')
at_exit_set = set()
@@ -296,10 +220,13 @@
resource_setup or at test level.
"""
identity_version = cls.get_identity_version()
- if 'admin' in cls.credentials and not credentials.is_admin_available(
- identity_version=identity_version):
- msg = "Missing Identity Admin API credentials in configuration."
- raise cls.skipException(msg)
+ # setting force_tenant_isolation to True also needs admin credentials.
+ if ('admin' in cls.credentials or
+ getattr(cls, 'force_tenant_isolation', False)):
+ if not credentials.is_admin_available(
+ identity_version=identity_version):
+ raise cls.skipException(
+ "Missing Identity Admin API credentials in configuration.")
if 'alt' in cls.credentials and not credentials.is_alt_available(
identity_version=identity_version):
msg = "Missing a 2nd set of API credentials in configuration."
@@ -373,9 +300,20 @@
@classmethod
def resource_setup(cls):
"""Class level resource setup for test cases."""
+ if (CONF.validation.ip_version_for_ssh not in (4, 6) and
+ CONF.service_available.neutron):
+ msg = "Invalid IP version %s in ip_version_for_ssh. Use 4 or 6"
+ raise lib_exc.InvalidConfiguration(
+ msg % CONF.validation.ip_version_for_ssh)
if hasattr(cls, "os_primary"):
+ vr = cls.validation_resources
cls.validation_resources = vresources.create_validation_resources(
- cls.os_primary, cls.validation_resources)
+ cls.os_primary,
+ use_neutron=CONF.service_available.neutron,
+ ethertype='IPv' + str(CONF.validation.ip_version_for_ssh),
+ floating_network_id=CONF.network.public_network_id,
+ floating_network_name=CONF.network.floating_network_name,
+ **vr)
else:
LOG.warning("Client manager not found, validation resources not"
" created")
@@ -389,8 +327,10 @@
"""
if cls.validation_resources:
if hasattr(cls, "os_primary"):
- vresources.clear_validation_resources(cls.os_primary,
- cls.validation_resources)
+ vr = cls.validation_resources
+ vresources.clear_validation_resources(
+ cls.os_primary,
+ use_neutron=CONF.service_available.neutron, **vr)
cls.validation_resources = {}
else:
LOG.warning("Client manager not found, validation resources "
diff --git a/tempest/tests/cmd/test_run.py b/tempest/tests/cmd/test_run.py
index 7ac347d..6e1250f 100644
--- a/tempest/tests/cmd/test_run.py
+++ b/tempest/tests/cmd/test_run.py
@@ -13,6 +13,7 @@
# under the License.
import argparse
+import atexit
import os
import shutil
import subprocess
@@ -25,6 +26,7 @@
from tempest.tests import base
DEVNULL = open(os.devnull, 'wb')
+atexit.register(DEVNULL.close)
class TestTempestRun(base.TestCase):
@@ -68,6 +70,34 @@
self.assertEqual('i_am_a_fun_little_regex',
self.run_cmd._build_regex(args))
+ def test__build_whitelist_file(self):
+ args = mock.Mock(spec=argparse.Namespace)
+ setattr(args, 'smoke', False)
+ setattr(args, 'regex', None)
+ self.tests = tempfile.NamedTemporaryFile(
+ prefix='whitelist', delete=False)
+ self.tests.write(b"volume \n compute")
+ self.tests.close()
+ setattr(args, 'whitelist_file', self.tests.name)
+ setattr(args, 'blacklist_file', None)
+ self.assertEqual("volume|compute",
+ self.run_cmd._build_regex(args))
+ os.unlink(self.tests.name)
+
+ def test__build_blacklist_file(self):
+ args = mock.Mock(spec=argparse.Namespace)
+ setattr(args, 'smoke', False)
+ setattr(args, 'regex', None)
+ self.tests = tempfile.NamedTemporaryFile(
+ prefix='blacklist', delete=False)
+ self.tests.write(b"volume \n compute")
+ self.tests.close()
+ setattr(args, 'whitelist_file', None)
+ setattr(args, 'blacklist_file', self.tests.name)
+ self.assertEqual("^((?!compute|volume).)*$",
+ self.run_cmd._build_regex(args))
+ os.unlink(self.tests.name)
+
class TestRunReturnCode(base.TestCase):
def setUp(self):
diff --git a/tempest/tests/lib/common/test_api_version_utils.py b/tempest/tests/lib/common/test_api_version_utils.py
index c063556..b99e8d4 100644
--- a/tempest/tests/lib/common/test_api_version_utils.py
+++ b/tempest/tests/lib/common/test_api_version_utils.py
@@ -92,24 +92,106 @@
def test_header_matches(self):
microversion_header_name = 'x-openstack-xyz-api-version'
request_microversion = '2.1'
- test_respose = {microversion_header_name: request_microversion}
+ test_response = {microversion_header_name: request_microversion}
api_version_utils.assert_version_header_matches_request(
- microversion_header_name, request_microversion, test_respose)
+ microversion_header_name, request_microversion, test_response)
def test_header_does_not_match(self):
microversion_header_name = 'x-openstack-xyz-api-version'
request_microversion = '2.1'
- test_respose = {microversion_header_name: '2.2'}
+ test_response = {microversion_header_name: '2.2'}
self.assertRaises(
exceptions.InvalidHTTPResponseHeader,
api_version_utils.assert_version_header_matches_request,
- microversion_header_name, request_microversion, test_respose)
+ microversion_header_name, request_microversion, test_response)
def test_header_not_present(self):
microversion_header_name = 'x-openstack-xyz-api-version'
request_microversion = '2.1'
- test_respose = {}
+ test_response = {}
self.assertRaises(
exceptions.InvalidHTTPResponseHeader,
api_version_utils.assert_version_header_matches_request,
- microversion_header_name, request_microversion, test_respose)
+ microversion_header_name, request_microversion, test_response)
+
+ def test_compare_versions_less_than(self):
+ microversion_header_name = 'x-openstack-xyz-api-version'
+ request_microversion = '2.2'
+ test_response = {microversion_header_name: '2.1'}
+ self.assertFalse(
+ api_version_utils.compare_version_header_to_response(
+ microversion_header_name, request_microversion, test_response,
+ "lt"))
+
+ def test_compare_versions_less_than_equal(self):
+ microversion_header_name = 'x-openstack-xyz-api-version'
+ request_microversion = '2.2'
+ test_response = {microversion_header_name: '2.1'}
+ self.assertFalse(
+ api_version_utils.compare_version_header_to_response(
+ microversion_header_name, request_microversion, test_response,
+ "le"))
+
+ def test_compare_versions_greater_than_equal(self):
+ microversion_header_name = 'x-openstack-xyz-api-version'
+ request_microversion = '2.1'
+ test_response = {microversion_header_name: '2.2'}
+ self.assertFalse(
+ api_version_utils.compare_version_header_to_response(
+ microversion_header_name, request_microversion, test_response,
+ "ge"))
+
+ def test_compare_versions_greater_than(self):
+ microversion_header_name = 'x-openstack-xyz-api-version'
+ request_microversion = '2.1'
+ test_response = {microversion_header_name: '2.2'}
+ self.assertFalse(
+ api_version_utils.compare_version_header_to_response(
+ microversion_header_name, request_microversion, test_response,
+ "gt"))
+
+ def test_compare_versions_equal(self):
+ microversion_header_name = 'x-openstack-xyz-api-version'
+ request_microversion = '2.11'
+ test_response = {microversion_header_name: '2.1'}
+ self.assertFalse(
+ api_version_utils.compare_version_header_to_response(
+ microversion_header_name, request_microversion, test_response,
+ "eq"))
+
+ def test_compare_versions_not_equal(self):
+ microversion_header_name = 'x-openstack-xyz-api-version'
+ request_microversion = '2.1'
+ test_response = {microversion_header_name: '2.1'}
+ self.assertFalse(
+ api_version_utils.compare_version_header_to_response(
+ microversion_header_name, request_microversion, test_response,
+ "ne"))
+
+ def test_compare_versions_with_name_in_microversion(self):
+ microversion_header_name = 'x-openstack-xyz-api-version'
+ request_microversion = 'volume 3.1'
+ test_response = {microversion_header_name: 'volume 3.1'}
+ self.assertTrue(
+ api_version_utils.compare_version_header_to_response(
+ microversion_header_name, request_microversion, test_response,
+ "eq"))
+
+ def test_compare_versions_invalid_operation(self):
+ microversion_header_name = 'x-openstack-xyz-api-version'
+ request_microversion = '2.1'
+ test_response = {microversion_header_name: '2.1'}
+ self.assertRaises(
+ exceptions.InvalidParam,
+ api_version_utils.compare_version_header_to_response,
+ microversion_header_name, request_microversion, test_response,
+ "foo")
+
+ def test_compare_versions_header_not_present(self):
+ microversion_header_name = 'x-openstack-xyz-api-version'
+ request_microversion = '2.1'
+ test_response = {}
+ self.assertFalse(
+ api_version_utils.compare_version_header_to_response(
+ microversion_header_name, request_microversion, test_response,
+ "eq"))
diff --git a/tempest/tests/lib/common/test_http.py b/tempest/tests/lib/common/test_http.py
new file mode 100644
index 0000000..a292209
--- /dev/null
+++ b/tempest/tests/lib/common/test_http.py
@@ -0,0 +1,68 @@
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.lib.common import http
+from tempest.tests import base
+
+
+class TestClosingHttp(base.TestCase):
+ def setUp(self):
+ super(TestClosingHttp, self).setUp()
+ self.cert_none = "CERT_NONE"
+ self.cert_location = "/etc/ssl/certs/ca-certificates.crt"
+
+ def test_constructor_invalid_ca_certs_and_timeout(self):
+ connection = http.ClosingHttp(
+ disable_ssl_certificate_validation=False,
+ ca_certs=None,
+ timeout=None)
+ for attr in ('cert_reqs', 'ca_certs', 'timeout'):
+ self.assertNotIn(attr, connection.connection_pool_kw)
+
+ def test_constructor_valid_ca_certs(self):
+ cert_required = 'CERT_REQUIRED'
+ connection = http.ClosingHttp(
+ disable_ssl_certificate_validation=False,
+ ca_certs=self.cert_location,
+ timeout=None)
+ self.assertEqual(cert_required,
+ connection.connection_pool_kw['cert_reqs'])
+ self.assertEqual(self.cert_location,
+ connection.connection_pool_kw['ca_certs'])
+ self.assertNotIn('timeout',
+ connection.connection_pool_kw)
+
+ def test_constructor_ssl_cert_validation_disabled(self):
+ connection = http.ClosingHttp(
+ disable_ssl_certificate_validation=True,
+ ca_certs=None,
+ timeout=30)
+ self.assertEqual(self.cert_none,
+ connection.connection_pool_kw['cert_reqs'])
+ self.assertEqual(30,
+ connection.connection_pool_kw['timeout'])
+ self.assertNotIn('ca_certs',
+ connection.connection_pool_kw)
+
+ def test_constructor_ssl_cert_validation_disabled_and_ca_certs(self):
+ connection = http.ClosingHttp(
+ disable_ssl_certificate_validation=True,
+ ca_certs=self.cert_location,
+ timeout=None)
+ self.assertNotIn('timeout',
+ connection.connection_pool_kw)
+ self.assertEqual(self.cert_none,
+ connection.connection_pool_kw['cert_reqs'])
+ self.assertNotIn('ca_certs',
+ connection.connection_pool_kw)
diff --git a/tempest/tests/lib/common/utils/linux/test_remote_client.py b/tempest/tests/lib/common/utils/linux/test_remote_client.py
index cf312f4..7a21a5f 100644
--- a/tempest/tests/lib/common/utils/linux/test_remote_client.py
+++ b/tempest/tests/lib/common/utils/linux/test_remote_client.py
@@ -34,7 +34,7 @@
client = remote_client.RemoteClient('192.168.1.10', 'username')
client.exec_command('ls')
mock_ssh_exec_command.assert_called_once_with(
- 'set -eu -o pipefail; PATH=$$PATH:/sbin; ls')
+ 'set -eu -o pipefail; PATH=$PATH:/sbin; ls')
@mock.patch.object(ssh.Client, 'test_connection_auth')
def test_validate_authentication(self, mock_test_connection_auth):
diff --git a/tempest/tests/lib/test_ssh.py b/tempest/tests/lib/test_ssh.py
index a16da1c..37fe646 100644
--- a/tempest/tests/lib/test_ssh.py
+++ b/tempest/tests/lib/test_ssh.py
@@ -12,11 +12,11 @@
# License for the specific language governing permissions and limitations
# under the License.
-from io import StringIO
import socket
import mock
import six
+from six import StringIO
import testtools
from tempest.lib.common import ssh
diff --git a/tempest/tests/test_base_test.py b/tempest/tests/test_base_test.py
index 6c6f612..3ece11d 100644
--- a/tempest/tests/test_base_test.py
+++ b/tempest/tests/test_base_test.py
@@ -13,10 +13,10 @@
# under the License.
import mock
+from oslo_config import cfg
from tempest import clients
from tempest.common import credentials_factory as credentials
-from tempest import config
from tempest.lib.common import fixed_network
from tempest import test
from tempest.tests import base
@@ -28,8 +28,9 @@
super(TestBaseTestCase, self).setUp()
self.useFixture(fake_config.ConfigFixture())
self.fixed_network_name = 'fixed-net'
- config.CONF.compute.fixed_network_name = self.fixed_network_name
- config.CONF.service_available.neutron = True
+ cfg.CONF.set_default('fixed_network_name', self.fixed_network_name,
+ 'compute')
+ cfg.CONF.set_default('neutron', True, 'service_available')
@mock.patch.object(test.BaseTestCase, 'get_client_manager')
@mock.patch.object(test.BaseTestCase, '_get_credentials_provider')
@@ -56,7 +57,7 @@
def test_get_tenant_network_with_nova_net(self, mock_man, mock_iaa,
mock_giv, mock_gtn, mock_gcp,
mock_gcm):
- config.CONF.service_available.neutron = False
+ cfg.CONF.set_default('neutron', False, 'service_available')
mock_prov = mock.Mock()
mock_admin_man = mock.Mock()
mock_iaa.return_value = True
diff --git a/tempest/tests/test_decorators.py b/tempest/tests/test_decorators.py
index 2fc84dc..bf04280 100644
--- a/tempest/tests/test_decorators.py
+++ b/tempest/tests/test_decorators.py
@@ -16,7 +16,9 @@
from oslo_config import cfg
import testtools
+from tempest.common import utils
from tempest import config
+from tempest import exceptions
from tempest.lib.common.utils import data_utils
from tempest import test
from tempest.tests import base
@@ -31,6 +33,10 @@
fake_config.FakePrivate)
+# NOTE: The test module is for tempest.test.idempotent_id.
+# After all projects switch to use decorators.idempotent_id,
+# we can remove tempest.test.idempotent_id as well as this
+# test module
class TestIdempotentIdDecorator(BaseDecoratorsTest):
def _test_helper(self, _id, **decorator_args):
@@ -71,7 +77,7 @@
class TestServicesDecorator(BaseDecoratorsTest):
def _test_services_helper(self, *decorator_args):
class TestFoo(test.BaseTestCase):
- @test.services(*decorator_args)
+ @utils.services(*decorator_args)
def test_bar(self):
return 0
@@ -90,7 +96,7 @@
self._test_services_helper('compute', 'compute')
def test_services_decorator_with_invalid_service(self):
- self.assertRaises(test.InvalidServiceTag,
+ self.assertRaises(exceptions.InvalidServiceTag,
self._test_services_helper, 'compute',
'bad_service')
@@ -102,11 +108,11 @@
'volume')
def test_services_list(self):
- service_list = test.get_service_list()
+ service_list = utils.get_service_list()
for service in service_list:
try:
self._test_services_helper(service)
- except test.InvalidServiceTag:
+ except exceptions.InvalidServiceTag:
self.fail('%s is not listed in the valid service tag list'
% service)
except KeyError:
@@ -133,7 +139,7 @@
def _test_requires_ext_helper(self, expected_to_skip=True,
**decorator_args):
class TestFoo(test.BaseTestCase):
- @test.requires_ext(**decorator_args)
+ @utils.requires_ext(**decorator_args)
def test_bar(self):
return 0
diff --git a/tempest/tests/test_hacking.py b/tempest/tests/test_hacking.py
index c04d933..bc3a753 100644
--- a/tempest/tests/test_hacking.py
+++ b/tempest/tests/test_hacking.py
@@ -86,13 +86,13 @@
def test_scenario_tests_need_service_tags(self):
self.assertFalse(checks.scenario_tests_need_service_tags(
'def test_fake:', './tempest/scenario/test_fake.py',
- "@test.services('compute')"))
+ "@utils.services('compute')"))
self.assertFalse(checks.scenario_tests_need_service_tags(
'def test_fake_test:', './tempest/api/compute/test_fake.py',
- "@test.services('image')"))
+ "@utils.services('image')"))
self.assertFalse(checks.scenario_tests_need_service_tags(
'def test_fake:', './tempest/scenario/orchestration/test_fake.py',
- "@test.services('compute')"))
+ "@utils.services('compute')"))
self.assertTrue(checks.scenario_tests_need_service_tags(
'def test_fake_test:', './tempest/scenario/test_fake.py',
'\n'))
@@ -113,12 +113,13 @@
def test_service_tags_not_in_module_path(self):
self.assertTrue(checks.service_tags_not_in_module_path(
- "@test.services('compute')", './tempest/api/compute/fake_test.py'))
+ "@utils.services('compute')",
+ './tempest/api/compute/fake_test.py'))
self.assertFalse(checks.service_tags_not_in_module_path(
- "@test.services('compute')",
+ "@utils.services('compute')",
'./tempest/scenario/compute/fake_test.py'))
self.assertFalse(checks.service_tags_not_in_module_path(
- "@test.services('compute')", './tempest/api/image/fake_test.py'))
+ "@utils.services('compute')", './tempest/api/image/fake_test.py'))
def test_no_hyphen_at_end_of_rand_name(self):
self.assertIsNone(checks.no_hyphen_at_end_of_rand_name(
diff --git a/test-requirements.txt b/test-requirements.txt
index 09c7685..29f0865 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -5,8 +5,8 @@
# needed for doc build
sphinx>=1.6.2 # BSD
openstackdocstheme>=1.16.0 # Apache-2.0
-reno!=2.3.1,>=1.8.0 # Apache-2.0
-mock>=2.0 # BSD
+reno>=2.5.0 # Apache-2.0
+mock>=2.0.0 # BSD
coverage!=4.4,>=4.0 # Apache-2.0
oslotest>=1.10.0 # Apache-2.0
flake8-import-order==0.11 # LGPLv3
diff --git a/tox.ini b/tox.ini
index c4f51c8..7bdc580 100644
--- a/tox.ini
+++ b/tox.ini
@@ -139,6 +139,7 @@
[testenv:docs]
commands =
+ rm -rf doc/build
python setup.py build_sphinx {posargs}
[testenv:pep8]
@@ -160,12 +161,14 @@
# E129 skipped because it is too limiting when combined with other rules
ignore = E125,E123,E129
show-source = True
-exclude = .git,.venv,.tox,dist,doc,*egg
+exclude = .git,.venv,.tox,dist,doc,*egg,build
enable-extensions = H106,H203,H904
import-order-style = pep8
[testenv:releasenotes]
-commands = sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html
+commands =
+ rm -rf releasenotes/build
+ sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html
[testenv:pip-check-reqs]
# Do not install test-requirements as that will pollute the virtualenv for