Merge "Add NetworkSubnetPools to tempest cleanup"
diff --git a/.zuul.yaml b/.zuul.yaml
index 8ff151f..a6a4b3e 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -478,6 +478,7 @@
- openstack-python-jobs
- openstack-python35-jobs
- openstack-python36-jobs
+ - openstack-python37-jobs
- publish-openstack-docs-pti
- release-notes-jobs-python3
check:
diff --git a/releasenotes/notes/conditional-attr-a8564ec5a70ec840.yaml b/releasenotes/notes/conditional-attr-a8564ec5a70ec840.yaml
new file mode 100644
index 0000000..c707f14
--- /dev/null
+++ b/releasenotes/notes/conditional-attr-a8564ec5a70ec840.yaml
@@ -0,0 +1,6 @@
+---
+features:
+ - |
+ The ``tempest.lib.decorators.attr`` decorator now supports a ``condition``
+ kwarg which can be used to conditionally apply the attr to the test
+ function if the condition evaluates to True.
diff --git a/tempest/api/compute/volumes/test_attach_volume.py b/tempest/api/compute/volumes/test_attach_volume.py
index f7b5b4b..8bb4eaa 100644
--- a/tempest/api/compute/volumes/test_attach_volume.py
+++ b/tempest/api/compute/volumes/test_attach_volume.py
@@ -65,6 +65,8 @@
class AttachVolumeTestJSON(BaseAttachVolumeTest):
@decorators.idempotent_id('52e9045a-e90d-4c0d-9087-79d657faffff')
+ # This test is conditionally marked slow if SSH validation is enabled.
+ @decorators.attr(type='slow', condition=CONF.validation.run_validation)
def test_attach_detach_volume(self):
# Stop and Start a server with an attached volume, ensuring that
# the volume remains attached.
diff --git a/tempest/api/identity/admin/v3/test_groups.py b/tempest/api/identity/admin/v3/test_groups.py
index 80d7469..df0d79d 100644
--- a/tempest/api/identity/admin/v3/test_groups.py
+++ b/tempest/api/identity/admin/v3/test_groups.py
@@ -23,6 +23,10 @@
class GroupsV3TestJSON(base.BaseIdentityV3AdminTest):
+ # NOTE: force_tenant_isolation is true in the base class by default but
+ # overridden to false here to allow test execution for clouds using the
+ # pre-provisioned credentials provider.
+ force_tenant_isolation = False
@classmethod
def resource_setup(cls):
diff --git a/tempest/lib/common/rest_client.py b/tempest/lib/common/rest_client.py
index e612bd1..3be441e 100644
--- a/tempest/lib/common/rest_client.py
+++ b/tempest/lib/common/rest_client.py
@@ -282,7 +282,7 @@
def get(self, url, headers=None, extra_headers=False):
"""Send a HTTP GET request using keystone service catalog and auth
- :param str url: the relative url to send the post request to
+ :param str url: the relative url to send the get request to
:param dict headers: The headers to use for the request
:param bool extra_headers: Boolean value than indicates if the headers
returned by the get_headers() method are to
@@ -297,7 +297,7 @@
def delete(self, url, headers=None, body=None, extra_headers=False):
"""Send a HTTP DELETE request using keystone service catalog and auth
- :param str url: the relative url to send the post request to
+ :param str url: the relative url to send the delete request to
:param dict headers: The headers to use for the request
:param dict body: the request body
:param bool extra_headers: Boolean value than indicates if the headers
@@ -313,7 +313,7 @@
def patch(self, url, body, headers=None, extra_headers=False):
"""Send a HTTP PATCH request using keystone service catalog and auth
- :param str url: the relative url to send the post request to
+ :param str url: the relative url to send the patch request to
:param dict body: the request body
:param dict headers: The headers to use for the request
:param bool extra_headers: Boolean value than indicates if the headers
@@ -329,7 +329,7 @@
def put(self, url, body, headers=None, extra_headers=False, chunked=False):
"""Send a HTTP PUT request using keystone service catalog and auth
- :param str url: the relative url to send the post request to
+ :param str url: the relative url to send the put request to
:param dict body: the request body
:param dict headers: The headers to use for the request
:param bool extra_headers: Boolean value than indicates if the headers
@@ -346,7 +346,7 @@
def head(self, url, headers=None, extra_headers=False):
"""Send a HTTP HEAD request using keystone service catalog and auth
- :param str url: the relative url to send the post request to
+ :param str url: the relative url to send the head request to
:param dict headers: The headers to use for the request
:param bool extra_headers: Boolean value than indicates if the headers
returned by the get_headers() method are to
@@ -361,7 +361,7 @@
def copy(self, url, headers=None, extra_headers=False):
"""Send a HTTP COPY request using keystone service catalog and auth
- :param str url: the relative url to send the post request to
+ :param str url: the relative url to send the copy request to
:param dict headers: The headers to use for the request
:param bool extra_headers: Boolean value than indicates if the headers
returned by the get_headers() method are to
diff --git a/tempest/lib/decorators.py b/tempest/lib/decorators.py
index b399aa0..62a5d67 100644
--- a/tempest/lib/decorators.py
+++ b/tempest/lib/decorators.py
@@ -136,9 +136,16 @@
This decorator applies the testtools.testcase.attr if it is in the list of
attributes to testtools we want to apply.
+
+ :param condition: Optional condition which if true will apply the attr. If
+ a condition is specified which is false the attr will not be applied to
+ the test function. If not specified, the attr is always applied.
"""
def decorator(f):
+ # Check to see if the attr should be conditional applied.
+ if 'condition' in kwargs and not kwargs.get('condition'):
+ return f
if 'type' in kwargs and isinstance(kwargs['type'], str):
f = testtools.testcase.attr(kwargs['type'])(f)
elif 'type' in kwargs and isinstance(kwargs['type'], list):
diff --git a/tempest/lib/services/identity/v3/oauth_token_client.py b/tempest/lib/services/identity/v3/oauth_token_client.py
index b1d298b..94da043 100644
--- a/tempest/lib/services/identity/v3/oauth_token_client.py
+++ b/tempest/lib/services/identity/v3/oauth_token_client.py
@@ -74,6 +74,7 @@
scheme, netloc, path, params, query, fragment = urlparse.urlparse(uri)
scheme = scheme.lower()
netloc = netloc.lower()
+ path = path.replace('//', '/')
normalized_uri = urlparse.urlunparse((scheme, netloc, path,
params, '', ''))
diff --git a/tempest/scenario/test_network_advanced_server_ops.py b/tempest/scenario/test_network_advanced_server_ops.py
index 4be2b29..37bcd04 100644
--- a/tempest/scenario/test_network_advanced_server_ops.py
+++ b/tempest/scenario/test_network_advanced_server_ops.py
@@ -119,6 +119,7 @@
server, keypair, floating_ip)
@decorators.idempotent_id('7b6860c2-afa3-4846-9522-adeb38dfbe08')
+ @decorators.attr(type='slow')
@utils.services('compute', 'network')
def test_server_connectivity_reboot(self):
keypair = self.create_keypair()
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
index 810480b..3bc5b0b 100644
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -76,6 +76,7 @@
self.snapshots_client.wait_for_resource_deletion(snapshot_id)
@decorators.idempotent_id('557cd2c2-4eb8-4dce-98be-f86765ff311b')
+ @decorators.attr(type='slow')
# Note: This test is being skipped based on 'public_network_id'.
# It is being used in create_floating_ip() method which gets called
# from get_server_ip() method
diff --git a/tempest/tests/lib/test_decorators.py b/tempest/tests/lib/test_decorators.py
index 0b1a599..3e6160e 100644
--- a/tempest/tests/lib/test_decorators.py
+++ b/tempest/tests/lib/test_decorators.py
@@ -32,9 +32,17 @@
# By our decorators.attr decorator the attribute __testtools_attrs
# will be set only for 'type' argument, so we test it first.
if 'type' in decorator_args:
- # this is what testtools sets
- self.assertEqual(getattr(foo, '__testtools_attrs'),
- set(expected_attrs))
+ if 'condition' in decorator_args:
+ if decorator_args['condition']:
+ # The expected attrs should be in the function.
+ self.assertEqual(set(expected_attrs),
+ getattr(foo, '__testtools_attrs'))
+ else:
+ # The expected attrs should not be in the function.
+ self.assertNotIn('__testtools_attrs', foo)
+ else:
+ self.assertEqual(set(expected_attrs),
+ getattr(foo, '__testtools_attrs'))
def test_attr_without_type(self):
self._test_attr_helper(expected_attrs='baz', bar='baz')
@@ -50,6 +58,13 @@
def test_attr_decorator_with_duplicated_type(self):
self._test_attr_helper(expected_attrs=['foo'], type=['foo', 'foo'])
+ def test_attr_decorator_condition_false(self):
+ self._test_attr_helper(None, type='slow', condition=False)
+
+ def test_attr_decorator_condition_true(self):
+ self._test_attr_helper(expected_attrs=['slow'], type='slow',
+ condition=True)
+
class TestSkipBecauseDecorator(base.TestCase):
def _test_skip_because_helper(self, expected_to_skip=True,