Merge "Fix to use proper random values"
diff --git a/run_tests.sh b/run_tests.sh
index 970da51..5c8ce7d 100755
--- a/run_tests.sh
+++ b/run_tests.sh
@@ -63,7 +63,7 @@
-l|--logging) logging=1;;
-L|--logging-config) logging_config=$2; shift;;
--) [ "yes" == "$first_uu" ] || testrargs="$testrargs $1"; first_uu=no ;;
- *) testrargs="$testrargs $1"
+ *) testrargs="$testrargs $1"; noseargs+=" $1" ;;
esac
shift
done
diff --git a/tempest/api/compute/admin/test_quotas.py b/tempest/api/compute/admin/test_quotas.py
index f55f152..e744200 100644
--- a/tempest/api/compute/admin/test_quotas.py
+++ b/tempest/api/compute/admin/test_quotas.py
@@ -52,15 +52,6 @@
'instances', 'security_group_rules',
'cores', 'security_groups'))
- @classmethod
- def tearDownClass(cls):
- for server in cls.servers:
- try:
- cls.servers_client.delete_server(server['id'])
- except exceptions.NotFound:
- continue
- super(QuotasAdminTestJSON, cls).tearDownClass()
-
@attr(type='smoke')
def test_get_default_quotas(self):
# Admin can get the default resource quota set for a tenant
diff --git a/tempest/api/compute/admin/test_servers.py b/tempest/api/compute/admin/test_servers.py
index 1b346f1..97e0e69 100644
--- a/tempest/api/compute/admin/test_servers.py
+++ b/tempest/api/compute/admin/test_servers.py
@@ -19,6 +19,7 @@
from tempest.common.utils.data_utils import rand_name
from tempest import exceptions
from tempest.test import attr
+from tempest.test import skip_because
class ServersAdminTestJSON(base.BaseComputeAdminTest):
@@ -159,6 +160,7 @@
self.client.reset_state, '999')
@attr(type='gate')
+ @skip_because(bug="1240043")
def test_get_server_diagnostics_by_admin(self):
# Retrieve server diagnostics by admin user
resp, diagnostic = self.client.get_server_diagnostics(self.s1_id)
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 0b527d9..885adcf 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -100,6 +100,19 @@
pass
@classmethod
+ def rebuild_server(cls, **kwargs):
+ # Destroy an existing server and creates a new one
+ try:
+ cls.servers_client.delete_server(cls.server_id)
+ cls.servers_client.wait_for_server_termination(cls.server_id)
+ except Exception as exc:
+ LOG.exception(exc)
+ pass
+ resp, server = cls.create_server(wait_until='ACTIVE', **kwargs)
+ cls.server_id = server['id']
+ cls.password = server['adminPass']
+
+ @classmethod
def clear_images(cls):
for image_id in cls.images:
try:
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index 6f646b2..255beb7 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -44,13 +44,13 @@
self.client.wait_for_server_status(self.server_id, 'ACTIVE')
except Exception:
# Rebuild server if something happened to it during a test
- self.rebuild_servers()
+ self.rebuild_server()
@classmethod
def setUpClass(cls):
super(ServerActionsTestJSON, cls).setUpClass()
cls.client = cls.servers_client
- cls.rebuild_servers()
+ cls.rebuild_server()
@testtools.skipUnless(compute.CHANGE_PASSWORD_AVAILABLE,
'Change password not available.')
@@ -286,14 +286,6 @@
self.assertEqual(202, resp.status)
self.client.wait_for_server_status(self.server_id, 'ACTIVE')
- @classmethod
- def rebuild_servers(cls):
- # Destroy any existing server and creates a new one
- cls.clear_servers()
- resp, server = cls.create_server(wait_until='ACTIVE')
- cls.server_id = server['id']
- cls.password = server['adminPass']
-
@attr(type='gate')
def test_stop_start_server(self):
resp, server = self.servers_client.stop(self.server_id)
@@ -303,6 +295,7 @@
self.assertEqual(202, resp.status)
self.servers_client.wait_for_server_status(self.server_id, 'ACTIVE')
+ @skip_because(bug="1233026")
@attr(type='gate')
def test_lock_unlock_server(self):
# Lock the server,try server stop(exceptions throw),unlock it and retry
diff --git a/tempest/api/compute/servers/test_server_metadata.py b/tempest/api/compute/servers/test_server_metadata.py
index 5ea3cbf..15c3e6b 100644
--- a/tempest/api/compute/servers/test_server_metadata.py
+++ b/tempest/api/compute/servers/test_server_metadata.py
@@ -81,14 +81,6 @@
# no teardown - all creates should fail
- @attr(type=['negative', 'gate'])
- def test_create_metadata_key_error(self):
- # Blank key should trigger an error.
- meta = {'': 'data1'}
- self.assertRaises(exceptions.BadRequest,
- self.create_server,
- meta=meta)
-
@attr(type='gate')
def test_update_server_metadata(self):
# The server's metadata values should be updated to the
@@ -147,62 +139,48 @@
self.assertEqual(expected, resp_metadata)
@attr(type=['negative', 'gate'])
- def test_get_nonexistant_server_metadata_item(self):
- # Negative test: GET on a non-existent server should not succeed
+ def test_server_metadata_negative(self):
+ # Blank key should trigger an error.
+ meta = {'': 'data1'}
+ self.assertRaises(exceptions.BadRequest,
+ self.create_server,
+ meta=meta)
+
+ # GET on a non-existent server should not succeed
self.assertRaises(exceptions.NotFound,
self.client.get_server_metadata_item, 999, 'test2')
- @attr(type=['negative', 'gate'])
- def test_list_nonexistant_server_metadata(self):
- # Negative test:List metadata on a non-existent server should
- # not succeed
+ # List metadata on a non-existent server should not succeed
self.assertRaises(exceptions.NotFound,
self.client.list_server_metadata, 999)
- @attr(type=['negative', 'gate'])
- def test_set_server_metadata_item_incorrect_uri_key(self):
# Raise BadRequest if key in uri does not match
# the key passed in body.
-
meta = {'testkey': 'testvalue'}
self.assertRaises(exceptions.BadRequest,
self.client.set_server_metadata_item,
self.server_id, 'key', meta)
- @attr(type=['negative', 'gate'])
- def test_set_nonexistant_server_metadata(self):
- # Negative test: Set metadata on a non-existent server should not
- # succeed
+ # Set metadata on a non-existent server should not succeed
meta = {'meta1': 'data1'}
self.assertRaises(exceptions.NotFound,
self.client.set_server_metadata, 999, meta)
- @attr(type=['negative', 'gate'])
- def test_update_nonexistant_server_metadata(self):
- # Negative test: An update should not happen for a non-existent image
+ # An update should not happen for a non-existent image
meta = {'key1': 'value1', 'key2': 'value2'}
self.assertRaises(exceptions.NotFound,
self.client.update_server_metadata, 999, meta)
- @attr(type=['negative', 'gate'])
- def test_update_metadata_key_error(self):
- # Blank key should trigger an error.
+ # Blank key should trigger an error
meta = {'': 'data1'}
self.assertRaises(exceptions.BadRequest,
self.client.update_server_metadata,
self.server_id, meta=meta)
- @attr(type=['negative', 'gate'])
- def test_delete_nonexistant_server_metadata_item(self):
- # Negative test: Should not be able to delete metadata item from a
- # non-existent server
-
- # Delete the metadata item
+ # Should not be able to delete metadata item from a non-existent server
self.assertRaises(exceptions.NotFound,
self.client.delete_server_metadata_item, 999, 'd')
- @attr(type=['negative', 'gate'])
- def test_set_server_metadata_too_long(self):
# Raise a 413 OverLimit exception while exceeding metadata items limit
# for tenant.
_, quota_set = self.quotas.get_quota_set(self.tenant_id)
@@ -214,21 +192,12 @@
self.client.set_server_metadata,
self.server_id, req_metadata)
- @attr(type=['negative', 'gate'])
- def test_update_server_metadata_too_long(self):
# Raise a 413 OverLimit exception while exceeding metadata items limit
- # for tenant.
- _, quota_set = self.quotas.get_quota_set(self.tenant_id)
- quota_metadata = quota_set['metadata_items']
- req_metadata = {}
- for num in range(1, quota_metadata + 2):
- req_metadata['key' + str(num)] = 'val' + str(num)
+ # for tenant (update).
self.assertRaises(exceptions.OverLimit,
self.client.update_server_metadata,
self.server_id, req_metadata)
- @attr(type=['negative', 'gate'])
- def test_update_all_metadata_field_error(self):
# Raise a bad request error for blank key.
# set_server_metadata will replace all metadata with new value
meta = {'': 'data1'}
@@ -236,6 +205,13 @@
self.client.set_server_metadata,
self.server_id, meta=meta)
+ # Raise a bad request error for a missing metadata field
+ # set_server_metadata will replace all metadata with new value
+ meta = {'meta1': 'data1'}
+ self.assertRaises(exceptions.BadRequest,
+ self.client.set_server_metadata,
+ self.server_id, meta=meta, no_metadata_field=True)
+
class ServerMetadataTestXML(ServerMetadataTestJSON):
_interface = 'xml'
diff --git a/tempest/api/compute/servers/test_servers_negative.py b/tempest/api/compute/servers/test_servers_negative.py
index 5d9a5ce..c896224 100644
--- a/tempest/api/compute/servers/test_servers_negative.py
+++ b/tempest/api/compute/servers/test_servers_negative.py
@@ -28,6 +28,13 @@
class ServersNegativeTestJSON(base.BaseComputeTest):
_interface = 'json'
+ def setUp(self):
+ super(ServersNegativeTestJSON, self).setUp()
+ try:
+ self.client.wait_for_server_status(self.server_id, 'ACTIVE')
+ except Exception:
+ self.rebuild_server()
+
@classmethod
def setUpClass(cls):
super(ServersNegativeTestJSON, cls).setUpClass()
@@ -35,6 +42,8 @@
cls.img_client = cls.images_client
cls.alt_os = clients.AltManager()
cls.alt_client = cls.alt_os.servers_client
+ resp, server = cls.create_server(wait_until='ACTIVE')
+ cls.server_id = server['id']
@attr(type=['negative', 'gate'])
def test_server_name_blank(self):
@@ -92,8 +101,6 @@
@attr(type=['negative', 'gate'])
def test_reboot_deleted_server(self):
# Reboot a deleted server
- resp, server = self.create_server()
- self.server_id = server['id']
self.client.delete_server(self.server_id)
self.client.wait_for_server_termination(self.server_id)
self.assertRaises(exceptions.NotFound, self.client.reboot,
@@ -102,8 +109,6 @@
@attr(type=['negative', 'gate'])
def test_pause_paused_server(self):
# Pause a paused server.
- resp, server = self.create_server(wait_until='ACTIVE')
- self.server_id = server['id']
self.client.pause_server(self.server_id)
self.client.wait_for_server_status(self.server_id, 'PAUSED')
self.assertRaises(exceptions.Duplicate,
@@ -113,9 +118,6 @@
@attr(type=['negative', 'gate'])
def test_rebuild_deleted_server(self):
# Rebuild a deleted server
-
- resp, server = self.create_server()
- self.server_id = server['id']
self.client.delete_server(self.server_id)
self.client.wait_for_server_termination(self.server_id)
@@ -195,21 +197,19 @@
def test_update_server_of_another_tenant(self):
# Update name of a server that belongs to another tenant
- resp, server = self.create_server(wait_until='ACTIVE')
- new_name = server['id'] + '_new'
+ new_name = self.server_id + '_new'
self.assertRaises(exceptions.NotFound,
- self.alt_client.update_server, server['id'],
+ self.alt_client.update_server, self.server_id,
name=new_name)
@attr(type=['negative', 'gate'])
def test_update_server_name_length_exceeds_256(self):
# Update name of server exceed the name length limit
- resp, server = self.create_server(wait_until='ACTIVE')
new_name = 'a' * 256
self.assertRaises(exceptions.BadRequest,
self.client.update_server,
- server['id'],
+ self.server_id,
name=new_name)
@attr(type=['negative', 'gate'])
@@ -222,10 +222,9 @@
@attr(type=['negative', 'gate'])
def test_delete_a_server_of_another_tenant(self):
# Delete a server that belongs to another tenant
- resp, server = self.create_server(wait_until='ACTIVE')
self.assertRaises(exceptions.NotFound,
self.alt_client.delete_server,
- server['id'])
+ self.server_id)
@attr(type=['negative', 'gate'])
def test_delete_server_pass_negative_id(self):
@@ -277,11 +276,9 @@
@attr(type=['negative', 'gate'])
def test_unpause_server_invalid_state(self):
# unpause an active server.
- resp, server = self.create_server(wait_until='ACTIVE')
- server_id = server['id']
self.assertRaises(exceptions.Duplicate,
self.client.unpause_server,
- server_id)
+ self.server_id)
@attr(type=['negative', 'gate'])
def test_suspend_non_existent_server(self):
@@ -291,17 +288,13 @@
@attr(type=['negative', 'gate'])
def test_suspend_server_invalid_state(self):
- # create server.
- resp, server = self.create_server(wait_until='ACTIVE')
- server_id = server['id']
-
# suspend a suspended server.
- resp, _ = self.client.suspend_server(server_id)
+ resp, _ = self.client.suspend_server(self.server_id)
self.assertEqual(202, resp.status)
- self.client.wait_for_server_status(server_id, 'SUSPENDED')
+ self.client.wait_for_server_status(self.server_id, 'SUSPENDED')
self.assertRaises(exceptions.Duplicate,
self.client.suspend_server,
- server_id)
+ self.server_id)
@attr(type=['negative', 'gate'])
def test_resume_non_existent_server(self):
@@ -311,14 +304,10 @@
@attr(type=['negative', 'gate'])
def test_resume_server_invalid_state(self):
- # create server.
- resp, server = self.create_server(wait_until='ACTIVE')
- server_id = server['id']
-
# resume an active server.
self.assertRaises(exceptions.Duplicate,
self.client.resume_server,
- server_id)
+ self.server_id)
class ServersNegativeTestXML(ServersNegativeTestJSON):
diff --git a/tempest/api/identity/admin/test_tenant_negative.py b/tempest/api/identity/admin/test_tenant_negative.py
new file mode 100644
index 0000000..6875bf5
--- /dev/null
+++ b/tempest/api/identity/admin/test_tenant_negative.py
@@ -0,0 +1,148 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 Huawei Technologies Co.,LTD.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import uuid
+
+from tempest.api.identity import base
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest.test import attr
+
+
+class TenantsNegativeTestJSON(base.BaseIdentityAdminTest):
+ _interface = 'json'
+
+ @attr(type=['negative', 'gate'])
+ def test_list_tenants_by_unauthorized_user(self):
+ # Non-administrator user should not be able to list tenants
+ self.assertRaises(exceptions.Unauthorized,
+ self.non_admin_client.list_tenants)
+
+ @attr(type=['negative', 'gate'])
+ def test_list_tenant_request_without_token(self):
+ # Request to list tenants without a valid token should fail
+ token = self.client.get_auth()
+ self.client.delete_token(token)
+ self.assertRaises(exceptions.Unauthorized, self.client.list_tenants)
+ self.client.clear_auth()
+
+ @attr(type=['negative', 'gate'])
+ def test_tenant_delete_by_unauthorized_user(self):
+ # Non-administrator user should not be able to delete a tenant
+ tenant_name = data_utils.rand_name(name='tenant-')
+ resp, tenant = self.client.create_tenant(tenant_name)
+ self.assertEqual(200, resp.status)
+ self.data.tenants.append(tenant)
+ self.assertRaises(exceptions.Unauthorized,
+ self.non_admin_client.delete_tenant, tenant['id'])
+
+ @attr(type=['negative', 'gate'])
+ def test_tenant_delete_request_without_token(self):
+ # Request to delete a tenant without a valid token should fail
+ tenant_name = data_utils.rand_name(name='tenant-')
+ resp, tenant = self.client.create_tenant(tenant_name)
+ self.assertEqual(200, resp.status)
+ self.data.tenants.append(tenant)
+ token = self.client.get_auth()
+ self.client.delete_token(token)
+ self.assertRaises(exceptions.Unauthorized, self.client.delete_tenant,
+ tenant['id'])
+ self.client.clear_auth()
+
+ @attr(type=['negative', 'gate'])
+ def test_delete_non_existent_tenant(self):
+ # Attempt to delete a non existent tenant should fail
+ self.assertRaises(exceptions.NotFound, self.client.delete_tenant,
+ str(uuid.uuid4().hex))
+
+ @attr(type=['negative', 'gate'])
+ def test_tenant_create_duplicate(self):
+ # Tenant names should be unique
+ tenant_name = data_utils.rand_name(name='tenant-')
+ resp, body = self.client.create_tenant(tenant_name)
+ self.assertEqual(200, resp.status)
+ tenant = body
+ self.data.tenants.append(tenant)
+ tenant1_id = body.get('id')
+
+ self.addCleanup(self.client.delete_tenant, tenant1_id)
+ self.addCleanup(self.data.tenants.remove, tenant)
+ self.assertRaises(exceptions.Duplicate, self.client.create_tenant,
+ tenant_name)
+
+ @attr(type=['negative', 'gate'])
+ def test_create_tenant_by_unauthorized_user(self):
+ # Non-administrator user should not be authorized to create a tenant
+ tenant_name = data_utils.rand_name(name='tenant-')
+ self.assertRaises(exceptions.Unauthorized,
+ self.non_admin_client.create_tenant, tenant_name)
+
+ @attr(type=['negative', 'gate'])
+ def test_create_tenant_request_without_token(self):
+ # Create tenant request without a token should not be authorized
+ tenant_name = data_utils.rand_name(name='tenant-')
+ token = self.client.get_auth()
+ self.client.delete_token(token)
+ self.assertRaises(exceptions.Unauthorized, self.client.create_tenant,
+ tenant_name)
+ self.client.clear_auth()
+
+ @attr(type=['negative', 'gate'])
+ def test_create_tenant_with_empty_name(self):
+ # Tenant name should not be empty
+ self.assertRaises(exceptions.BadRequest, self.client.create_tenant,
+ name='')
+
+ @attr(type=['negative', 'gate'])
+ def test_create_tenants_name_length_over_64(self):
+ # Tenant name length should not be greater than 64 characters
+ tenant_name = 'a' * 65
+ self.assertRaises(exceptions.BadRequest, self.client.create_tenant,
+ tenant_name)
+
+ @attr(type=['negative', 'gate'])
+ def test_update_non_existent_tenant(self):
+ # Attempt to update a non existent tenant should fail
+ self.assertRaises(exceptions.NotFound, self.client.update_tenant,
+ str(uuid.uuid4().hex))
+
+ @attr(type=['negative', 'gate'])
+ def test_tenant_update_by_unauthorized_user(self):
+ # Non-administrator user should not be able to update a tenant
+ tenant_name = data_utils.rand_name(name='tenant-')
+ resp, tenant = self.client.create_tenant(tenant_name)
+ self.assertEqual(200, resp.status)
+ self.data.tenants.append(tenant)
+ self.assertRaises(exceptions.Unauthorized,
+ self.non_admin_client.update_tenant, tenant['id'])
+
+ @attr(type=['negative', 'gate'])
+ def test_tenant_update_request_without_token(self):
+ # Request to update a tenant without a valid token should fail
+ tenant_name = data_utils.rand_name(name='tenant-')
+ resp, tenant = self.client.create_tenant(tenant_name)
+ self.assertEqual(200, resp.status)
+ self.data.tenants.append(tenant)
+ token = self.client.get_auth()
+ self.client.delete_token(token)
+ self.assertRaises(exceptions.Unauthorized, self.client.update_tenant,
+ tenant['id'])
+ self.client.clear_auth()
+
+
+class TenantsNegativeTestXML(TenantsNegativeTestJSON):
+ _interface = 'xml'
diff --git a/tempest/api/identity/admin/test_tenants.py b/tempest/api/identity/admin/test_tenants.py
index 486b739..e36b543 100644
--- a/tempest/api/identity/admin/test_tenants.py
+++ b/tempest/api/identity/admin/test_tenants.py
@@ -16,8 +16,7 @@
# under the License.
from tempest.api.identity import base
-from tempest.common.utils.data_utils import rand_name
-from tempest import exceptions
+from tempest.common.utils import data_utils
from tempest.test import attr
@@ -25,25 +24,13 @@
_interface = 'json'
@attr(type='gate')
- def test_list_tenants_by_unauthorized_user(self):
- # Non-administrator user should not be able to list tenants
- self.assertRaises(exceptions.Unauthorized,
- self.non_admin_client.list_tenants)
-
- @attr(type='gate')
- def test_list_tenant_request_without_token(self):
- # Request to list tenants without a valid token should fail
- token = self.client.get_auth()
- self.client.delete_token(token)
- self.assertRaises(exceptions.Unauthorized, self.client.list_tenants)
- self.client.clear_auth()
-
- @attr(type='gate')
def test_tenant_list_delete(self):
# Create several tenants and delete them
tenants = []
for _ in xrange(3):
- resp, tenant = self.client.create_tenant(rand_name('tenant-new'))
+ tenant_name = data_utils.rand_name(name='tenant-new')
+ resp, tenant = self.client.create_tenant(tenant_name)
+ self.assertEqual(200, resp.status)
self.data.tenants.append(tenant)
tenants.append(tenant)
tenant_ids = map(lambda x: x['id'], tenants)
@@ -62,37 +49,10 @@
self.assertFalse(any(found), 'Tenants failed to delete')
@attr(type='gate')
- def test_tenant_delete_by_unauthorized_user(self):
- # Non-administrator user should not be able to delete a tenant
- tenant_name = rand_name('tenant-')
- resp, tenant = self.client.create_tenant(tenant_name)
- self.data.tenants.append(tenant)
- self.assertRaises(exceptions.Unauthorized,
- self.non_admin_client.delete_tenant, tenant['id'])
-
- @attr(type='gate')
- def test_tenant_delete_request_without_token(self):
- # Request to delete a tenant without a valid token should fail
- tenant_name = rand_name('tenant-')
- resp, tenant = self.client.create_tenant(tenant_name)
- self.data.tenants.append(tenant)
- token = self.client.get_auth()
- self.client.delete_token(token)
- self.assertRaises(exceptions.Unauthorized, self.client.delete_tenant,
- tenant['id'])
- self.client.clear_auth()
-
- @attr(type='gate')
- def test_delete_non_existent_tenant(self):
- # Attempt to delete a non existent tenant should fail
- self.assertRaises(exceptions.NotFound, self.client.delete_tenant,
- 'junk_tenant_123456abc')
-
- @attr(type='gate')
def test_tenant_create_with_description(self):
# Create tenant with a description
- tenant_name = rand_name('tenant-')
- tenant_desc = rand_name('desc-')
+ tenant_name = data_utils.rand_name(name='tenant-')
+ tenant_desc = data_utils.rand_name(name='desc-')
resp, body = self.client.create_tenant(tenant_name,
description=tenant_desc)
tenant = body
@@ -113,7 +73,7 @@
@attr(type='gate')
def test_tenant_create_enabled(self):
# Create a tenant that is enabled
- tenant_name = rand_name('tenant-')
+ tenant_name = data_utils.rand_name(name='tenant-')
resp, body = self.client.create_tenant(tenant_name, enabled=True)
tenant = body
self.data.tenants.append(tenant)
@@ -131,7 +91,7 @@
@attr(type='gate')
def test_tenant_create_not_enabled(self):
# Create a tenant that is not enabled
- tenant_name = rand_name('tenant-')
+ tenant_name = data_utils.rand_name(name='tenant-')
resp, body = self.client.create_tenant(tenant_name, enabled=False)
tenant = body
self.data.tenants.append(tenant)
@@ -149,61 +109,18 @@
self.data.tenants.remove(tenant)
@attr(type='gate')
- def test_tenant_create_duplicate(self):
- # Tenant names should be unique
- tenant_name = rand_name('tenant-dup-')
- resp, body = self.client.create_tenant(tenant_name)
- tenant = body
- self.data.tenants.append(tenant)
- tenant1_id = body.get('id')
-
- self.addCleanup(self.client.delete_tenant, tenant1_id)
- self.addCleanup(self.data.tenants.remove, tenant)
- self.assertRaises(exceptions.Duplicate, self.client.create_tenant,
- tenant_name)
-
- @attr(type='gate')
- def test_create_tenant_by_unauthorized_user(self):
- # Non-administrator user should not be authorized to create a tenant
- tenant_name = rand_name('tenant-')
- self.assertRaises(exceptions.Unauthorized,
- self.non_admin_client.create_tenant, tenant_name)
-
- @attr(type='gate')
- def test_create_tenant_request_without_token(self):
- # Create tenant request without a token should not be authorized
- tenant_name = rand_name('tenant-')
- token = self.client.get_auth()
- self.client.delete_token(token)
- self.assertRaises(exceptions.Unauthorized, self.client.create_tenant,
- tenant_name)
- self.client.clear_auth()
-
- @attr(type='gate')
- def test_create_tenant_with_empty_name(self):
- # Tenant name should not be empty
- self.assertRaises(exceptions.BadRequest, self.client.create_tenant,
- name='')
-
- @attr(type='gate')
- def test_create_tenants_name_length_over_64(self):
- # Tenant name length should not be greater than 64 characters
- tenant_name = 'a' * 65
- self.assertRaises(exceptions.BadRequest, self.client.create_tenant,
- tenant_name)
-
- @attr(type='gate')
def test_tenant_update_name(self):
# Update name attribute of a tenant
- t_name1 = rand_name('tenant-')
+ t_name1 = data_utils.rand_name(name='tenant-')
resp, body = self.client.create_tenant(t_name1)
+ self.assertEqual(200, resp.status)
tenant = body
self.data.tenants.append(tenant)
t_id = body['id']
resp1_name = body['name']
- t_name2 = rand_name('tenant2-')
+ t_name2 = data_utils.rand_name(name='tenant2-')
resp, body = self.client.update_tenant(t_id, name=t_name2)
st2 = resp['status']
resp2_name = body['name']
@@ -223,16 +140,17 @@
@attr(type='gate')
def test_tenant_update_desc(self):
# Update description attribute of a tenant
- t_name = rand_name('tenant-')
- t_desc = rand_name('desc-')
+ t_name = data_utils.rand_name(name='tenant-')
+ t_desc = data_utils.rand_name(name='desc-')
resp, body = self.client.create_tenant(t_name, description=t_desc)
+ self.assertEqual(200, resp.status)
tenant = body
self.data.tenants.append(tenant)
t_id = body['id']
resp1_desc = body['description']
- t_desc2 = rand_name('desc2-')
+ t_desc2 = data_utils.rand_name(name='desc2-')
resp, body = self.client.update_tenant(t_id, description=t_desc2)
st2 = resp['status']
resp2_desc = body['description']
@@ -252,9 +170,10 @@
@attr(type='gate')
def test_tenant_update_enable(self):
# Update the enabled attribute of a tenant
- t_name = rand_name('tenant-')
+ t_name = data_utils.rand_name(name='tenant-')
t_en = False
resp, body = self.client.create_tenant(t_name, enabled=t_en)
+ self.assertEqual(200, resp.status)
tenant = body
self.data.tenants.append(tenant)
diff --git a/tempest/api/image/v1/test_image_members.py b/tempest/api/image/v1/test_image_members.py
index e9c395e..9ea9a3d 100644
--- a/tempest/api/image/v1/test_image_members.py
+++ b/tempest/api/image/v1/test_image_members.py
@@ -28,21 +28,26 @@
@classmethod
def setUpClass(cls):
super(ImageMembersTests, cls).setUpClass()
- admin = clients.AdminManager(interface='json')
- cls.admin_client = admin.identity_client
- cls.tenants = cls._get_tenants()
+ if cls.config.compute.allow_tenant_isolation:
+ creds = cls.isolated_creds.get_alt_creds()
+ username, tenant_name, password = creds
+ cls.os_alt = clients.Manager(username=username,
+ password=password,
+ tenant_name=tenant_name)
+ else:
+ cls.os_alt = clients.AltManager()
- @classmethod
- def _get_tenants(cls):
- resp, tenants = cls.admin_client.list_tenants()
- tenants = map(lambda x: x['id'], tenants)
- return tenants
+ alt_tenant_name = cls.os_alt.tenant_name
+ identity_client = cls._get_identity_admin_client()
+ _, tenants = identity_client.list_tenants()
+ cls.alt_tenant_id = [tnt['id'] for tnt in tenants if tnt['name'] ==
+ alt_tenant_name][0]
def _create_image(self):
image_file = StringIO.StringIO('*' * 1024)
resp, image = self.create_image(container_format='bare',
disk_format='raw',
- is_public=True,
+ is_public=False,
data=image_file)
self.assertEqual(201, resp.status)
image_id = image['id']
@@ -51,23 +56,23 @@
@attr(type='gate')
def test_add_image_member(self):
image = self._create_image()
- resp = self.client.add_member(self.tenants[0], image)
+ resp = self.client.add_member(self.alt_tenant_id, image)
self.assertEqual(204, resp.status)
resp, body = self.client.get_image_membership(image)
self.assertEqual(200, resp.status)
members = body['members']
members = map(lambda x: x['member_id'], members)
- self.assertIn(self.tenants[0], members)
+ self.assertIn(self.alt_tenant_id, members)
@attr(type='gate')
def test_get_shared_images(self):
image = self._create_image()
- resp = self.client.add_member(self.tenants[0], image)
+ resp = self.client.add_member(self.alt_tenant_id, image)
self.assertEqual(204, resp.status)
share_image = self._create_image()
- resp = self.client.add_member(self.tenants[0], share_image)
+ resp = self.client.add_member(self.alt_tenant_id, share_image)
self.assertEqual(204, resp.status)
- resp, body = self.client.get_shared_images(self.tenants[0])
+ resp, body = self.client.get_shared_images(self.alt_tenant_id)
self.assertEqual(200, resp.status)
images = body['shared_images']
images = map(lambda x: x['image_id'], images)
@@ -77,28 +82,28 @@
@attr(type='gate')
def test_remove_member(self):
image_id = self._create_image()
- resp = self.client.add_member(self.tenants[0], image_id)
+ resp = self.client.add_member(self.alt_tenant_id, image_id)
self.assertEqual(204, resp.status)
- resp = self.client.delete_member(self.tenants[0], image_id)
+ resp = self.client.delete_member(self.alt_tenant_id, image_id)
self.assertEqual(204, resp.status)
resp, body = self.client.get_image_membership(image_id)
self.assertEqual(200, resp.status)
members = body['members']
- self.assertEqual(0, len(members))
+ self.assertEqual(0, len(members), str(members))
@attr(type=['negative', 'gate'])
def test_add_member_with_non_existing_image(self):
# Add member with non existing image.
non_exist_image = rand_name('image_')
self.assertRaises(exceptions.NotFound, self.client.add_member,
- self.tenants[0], non_exist_image)
+ self.alt_tenant_id, non_exist_image)
@attr(type=['negative', 'gate'])
def test_delete_member_with_non_existing_image(self):
# Delete member with non existing image.
non_exist_image = rand_name('image_')
self.assertRaises(exceptions.NotFound, self.client.delete_member,
- self.tenants[0], non_exist_image)
+ self.alt_tenant_id, non_exist_image)
@attr(type=['negative', 'gate'])
def test_delete_member_with_non_existing_tenant(self):
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index cfac257..c3a66c5 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -56,6 +56,7 @@
cls.networks = []
cls.subnets = []
cls.ports = []
+ cls.routers = []
cls.pools = []
cls.vips = []
cls.members = []
@@ -73,6 +74,8 @@
cls.client.delete_pool(pool['id'])
for port in cls.ports:
cls.client.delete_port(port['id'])
+ for router in cls.routers:
+ cls.client.delete_router(router['id'])
for subnet in cls.subnets:
cls.client.delete_subnet(subnet['id'])
for network in cls.networks:
@@ -125,6 +128,21 @@
return port
@classmethod
+ def create_router(cls, router_name=None, admin_state_up=False,
+ external_network_id=None, enable_snat=None):
+ ext_gw_info = {}
+ if external_network_id:
+ ext_gw_info['network_id'] = external_network_id
+ if enable_snat:
+ ext_gw_info['enable_snat'] = enable_snat
+ resp, body = cls.client.create_router(
+ router_name, external_gateway_info=ext_gw_info,
+ admin_state_up=admin_state_up)
+ router = body['router']
+ cls.routers.append(router)
+ return router
+
+ @classmethod
def create_pool(cls, name, lb_method, protocol, subnet):
"""Wrapper utility that returns a test pool."""
resp, body = cls.client.create_pool(name, lb_method, protocol,
diff --git a/tempest/api/network/test_floating_ips.py b/tempest/api/network/test_floating_ips.py
index ca2c879..9acb6c5 100644
--- a/tempest/api/network/test_floating_ips.py
+++ b/tempest/api/network/test_floating_ips.py
@@ -47,11 +47,9 @@
# Create network, subnet, router and add interface
cls.network = cls.create_network()
cls.subnet = cls.create_subnet(cls.network)
- resp, router = cls.client.create_router(
+ cls.router = cls.create_router(
rand_name('router-'),
- external_gateway_info={"network_id":
- cls.network_cfg.public_network_id})
- cls.router = router['router']
+ external_network_id=cls.network_cfg.public_network_id)
resp, _ = cls.client.add_router_interface_with_subnet_id(
cls.router['id'], cls.subnet['id'])
cls.port = list()
@@ -66,7 +64,6 @@
cls.subnet['id'])
for i in range(2):
cls.client.delete_port(cls.port[i]['id'])
- cls.client.delete_router(cls.router['id'])
super(FloatingIPTestJSON, cls).tearDownClass()
def _delete_floating_ip(self, floating_ip_id):
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index 8b939fe..2cfbf61 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -52,6 +52,8 @@
@attr(type='smoke')
def test_create_show_list_update_delete_router(self):
# Create a router
+ # NOTE(salv-orlando): Do not invoke self.create_router
+ # as we need to check the response code
name = rand_name('router-')
resp, create_body = self.client.create_router(
name, external_gateway_info={
@@ -94,41 +96,37 @@
def test_add_remove_router_interface_with_subnet_id(self):
network = self.create_network()
subnet = self.create_subnet(network)
- name = rand_name('router-')
- resp, create_body = self.client.create_router(name)
- self.addCleanup(self.client.delete_router, create_body['router']['id'])
+ router = self.create_router(rand_name('router-'))
# Add router interface with subnet id
resp, interface = self.client.add_router_interface_with_subnet_id(
- create_body['router']['id'], subnet['id'])
+ router['id'], subnet['id'])
self.assertEqual('200', resp['status'])
self.addCleanup(self._remove_router_interface_with_subnet_id,
- create_body['router']['id'], subnet['id'])
+ router['id'], subnet['id'])
self.assertTrue('subnet_id' in interface.keys())
self.assertTrue('port_id' in interface.keys())
# Verify router id is equal to device id in port details
resp, show_port_body = self.client.show_port(
interface['port_id'])
self.assertEqual(show_port_body['port']['device_id'],
- create_body['router']['id'])
+ router['id'])
@attr(type='smoke')
def test_add_remove_router_interface_with_port_id(self):
network = self.create_network()
self.create_subnet(network)
- name = rand_name('router-')
- resp, create_body = self.client.create_router(name)
- self.addCleanup(self.client.delete_router, create_body['router']['id'])
+ router = self.create_router(rand_name('router-'))
resp, port_body = self.client.create_port(network['id'])
# add router interface to port created above
resp, interface = self.client.add_router_interface_with_port_id(
- create_body['router']['id'], port_body['port']['id'])
+ router['id'], port_body['port']['id'])
self.assertEqual('200', resp['status'])
self.addCleanup(self._remove_router_interface_with_port_id,
- create_body['router']['id'], port_body['port']['id'])
+ router['id'], port_body['port']['id'])
self.assertTrue('subnet_id' in interface.keys())
self.assertTrue('port_id' in interface.keys())
# Verify router id is equal to device id in port details
resp, show_port_body = self.client.show_port(
interface['port_id'])
self.assertEqual(show_port_body['port']['device_id'],
- create_body['router']['id'])
+ router['id'])
diff --git a/tempest/api/network/test_security_groups.py b/tempest/api/network/test_security_groups.py
index 60ca88a..914dcff 100644
--- a/tempest/api/network/test_security_groups.py
+++ b/tempest/api/network/test_security_groups.py
@@ -16,7 +16,7 @@
# under the License.
from tempest.api.network import base
-from tempest.common.utils.data_utils import rand_name
+from tempest.common.utils import data_utils
from tempest import exceptions
from tempest.test import attr
@@ -66,9 +66,9 @@
self.assertIsNotNone(found, msg)
@attr(type='smoke')
- def test_create_show_delete_security_group_and_rule(self):
+ def test_create_show_delete_security_group(self):
# Create a security group
- name = rand_name('secgroup-')
+ name = data_utils.rand_name('secgroup-')
resp, group_create_body = self.client.create_security_group(name)
self.assertEqual('201', resp['status'])
self.addCleanup(self._delete_security_group,
@@ -88,14 +88,29 @@
for secgroup in list_body['security_groups']:
secgroup_list.append(secgroup['id'])
self.assertIn(group_create_body['security_group']['id'], secgroup_list)
- # No Update in security group
- # Create rule
- resp, rule_create_body = self.client.create_security_group_rule(
- group_create_body['security_group']['id']
- )
+
+ @attr(type='smoke')
+ def test_create_show_delete_security_group_rule(self):
+ # Create a security group
+ name = data_utils.rand_name('secgroup-')
+ resp, group_create_body = self.client.create_security_group(name)
self.assertEqual('201', resp['status'])
- self.addCleanup(self._delete_security_group_rule,
- rule_create_body['security_group_rule']['id'])
+ self.addCleanup(self._delete_security_group,
+ group_create_body['security_group']['id'])
+ self.assertEqual(group_create_body['security_group']['name'], name)
+
+ # Create rules for each protocol
+ protocols = ['tcp', 'udp', 'icmp']
+ for protocol in protocols:
+ resp, rule_create_body = self.client.create_security_group_rule(
+ group_create_body['security_group']['id'],
+ protocol=protocol
+ )
+ self.assertEqual('201', resp['status'])
+ self.addCleanup(self._delete_security_group_rule,
+ rule_create_body['security_group_rule']['id']
+ )
+
# Show details of the created security rule
resp, show_rule_body = self.client.show_security_group_rule(
rule_create_body['security_group_rule']['id']
@@ -111,13 +126,13 @@
@attr(type=['negative', 'smoke'])
def test_show_non_existent_security_group(self):
- non_exist_id = rand_name('secgroup-')
+ non_exist_id = data_utils.rand_name('secgroup-')
self.assertRaises(exceptions.NotFound, self.client.show_security_group,
non_exist_id)
@attr(type=['negative', 'smoke'])
def test_show_non_existent_security_group_rule(self):
- non_exist_id = rand_name('rule-')
+ non_exist_id = data_utils.rand_name('rule-')
self.assertRaises(exceptions.NotFound,
self.client.show_security_group_rule,
non_exist_id)
diff --git a/tempest/scenario/orchestration/test_autoscaling.py b/tempest/scenario/orchestration/test_autoscaling.py
index 658e9bb..e843793 100644
--- a/tempest/scenario/orchestration/test_autoscaling.py
+++ b/tempest/scenario/orchestration/test_autoscaling.py
@@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import heatclient.exc as heat_exceptions
import time
from tempest.scenario import manager
@@ -74,7 +75,8 @@
self.assertEqual('CREATE', self.stack.action)
# wait for create to complete.
- self.status_timeout(self.client.stacks, sid, 'COMPLETE')
+ self.status_timeout(self.client.stacks, sid, 'COMPLETE',
+ error_status='FAILED')
self.stack.get()
self.assertEqual('CREATE_COMPLETE', self.stack.stack_status)
@@ -96,8 +98,10 @@
call_until_true(lambda: server_count() == to_servers,
timeout, interval)
self.assertEqual(to_servers, self.server_count,
- 'Failed scaling from %d to %d servers' % (
- from_servers, to_servers))
+ 'Failed scaling from %d to %d servers. '
+ 'Current server count: %s' % (
+ from_servers, to_servers,
+ self.server_count))
# he marched them up to the top of the hill
assertScale(1, 2)
@@ -106,3 +110,15 @@
# and he marched them down again
assertScale(3, 2)
assertScale(2, 1)
+
+ # delete stack on completion
+ self.stack.delete()
+ self.status_timeout(self.client.stacks, sid, 'COMPLETE',
+ error_status='FAILED',
+ not_found_exception=heat_exceptions.NotFound)
+
+ try:
+ self.stack.get()
+ self.assertEqual('DELETE_COMPLETE', self.stack.stack_status)
+ except heat_exceptions.NotFound:
+ pass
diff --git a/tempest/services/compute/json/servers_client.py b/tempest/services/compute/json/servers_client.py
index eda0ede..dfbc01c 100644
--- a/tempest/services/compute/json/servers_client.py
+++ b/tempest/services/compute/json/servers_client.py
@@ -236,8 +236,11 @@
body = json.loads(body)
return resp, body['metadata']
- def set_server_metadata(self, server_id, meta):
- post_body = json.dumps({'metadata': meta})
+ def set_server_metadata(self, server_id, meta, no_metadata_field=False):
+ if no_metadata_field:
+ post_body = ""
+ else:
+ post_body = json.dumps({'metadata': meta})
resp, body = self.put('servers/%s/metadata' % str(server_id),
post_body, self.headers)
body = json.loads(body)
diff --git a/tempest/services/compute/xml/servers_client.py b/tempest/services/compute/xml/servers_client.py
index cb21c61..ada0398 100644
--- a/tempest/services/compute/xml/servers_client.py
+++ b/tempest/services/compute/xml/servers_client.py
@@ -494,14 +494,15 @@
body = self._parse_key_value(etree.fromstring(body))
return resp, body
- def set_server_metadata(self, server_id, meta):
+ def set_server_metadata(self, server_id, meta, no_metadata_field=False):
doc = Document()
- metadata = Element("metadata")
- doc.append(metadata)
- for k, v in meta.items():
- meta_element = Element("meta", key=k)
- meta_element.append(Text(v))
- metadata.append(meta_element)
+ if not no_metadata_field:
+ metadata = Element("metadata")
+ doc.append(metadata)
+ for k, v in meta.items():
+ meta_element = Element("meta", key=k)
+ meta_element.append(Text(v))
+ metadata.append(meta_element)
resp, body = self.put('servers/%s/metadata' % str(server_id),
str(doc), self.headers)
return resp, xml_to_json(etree.fromstring(body))
diff --git a/tempest/tests/test_wrappers.py b/tempest/tests/test_wrappers.py
index 1a5af00..dbe3420 100644
--- a/tempest/tests/test_wrappers.py
+++ b/tempest/tests/test_wrappers.py
@@ -20,8 +20,6 @@
import tempfile
import testtools
-from tempest.test import attr
-
DEVNULL = open(os.devnull, 'wb')
@@ -46,7 +44,6 @@
shutil.copy('tempest/tests/files/setup.cfg', self.setup_cfg_file)
shutil.copy('tempest/tests/files/__init__.py', self.init_file)
- @attr(type='smoke')
def test_pretty_tox(self):
# Copy wrapper script and requirements:
pretty_tox = os.path.join(self.directory, 'pretty_tox.sh')
@@ -62,7 +59,6 @@
shell=True, stdout=DEVNULL, stderr=DEVNULL)
self.assertEqual(exit_code, 0)
- @attr(type='smoke')
def test_pretty_tox_fails(self):
# Copy wrapper script and requirements:
pretty_tox = os.path.join(self.directory, 'pretty_tox.sh')
@@ -78,7 +74,6 @@
stdout=DEVNULL, stderr=DEVNULL)
self.assertEqual(exit_code, 1)
- @attr(type='smoke')
def test_pretty_tox_serial(self):
# Copy wrapper script and requirements:
pretty_tox = os.path.join(self.directory, 'pretty_tox_serial.sh')
@@ -90,7 +85,6 @@
shell=True, stdout=DEVNULL, stderr=DEVNULL)
self.assertEqual(exit_code, 0)
- @attr(type='smoke')
def test_pretty_tox_serial_fails(self):
# Copy wrapper script and requirements:
pretty_tox = os.path.join(self.directory, 'pretty_tox_serial.sh')
diff --git a/tox.ini b/tox.ini
index ff09b3f..d93112c 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,11 +1,23 @@
[tox]
envlist = pep8
+minversion = 1.6
+skipsdist = True
[testenv]
setenv = VIRTUAL_ENV={envdir}
LANG=en_US.UTF-8
LANGUAGE=en_US:en
LC_ALL=C
+usedevelop = True
+
+[testenv:py26]
+commands = python setup.py test --slowest --testr-arg='tempest\.tests {posargs}'
+
+[testenv:py33]
+commands = python setup.py test --slowest --testr-arg='tempest\.tests {posargs}'
+
+[testenv:py27]
+commands = python setup.py test --slowest --testr-arg='tempest\.tests {posargs}'
[testenv:all]
sitepackages = True
@@ -15,29 +27,25 @@
[testenv:full]
sitepackages = True
-setenv = VIRTUAL_ENV={envdir}
# The regex below is used to select which tests to run and exclude the slow tag:
# See the testrepostiory bug: https://bugs.launchpad.net/testrepository/+bug/1208610
commands =
- sh tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli|tests)) {posargs}'
+ sh tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli)) {posargs}'
[testenv:testr-full]
sitepackages = True
-setenv = VIRTUAL_ENV={envdir}
commands =
- sh tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli|tests)) {posargs}'
+ sh tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli)) {posargs}'
[testenv:heat-slow]
sitepackages = True
-setenv = VIRTUAL_ENV={envdir}
- OS_TEST_TIMEOUT=1200
+setenv = OS_TEST_TIMEOUT=1200
# The regex below is used to select heat api/scenario tests tagged as slow.
commands =
sh tools/pretty_tox_serial.sh '(?=.*\[.*\bslow\b.*\])(^tempest\.(api|scenario)\.orchestration) {posargs}'
[testenv:large-ops]
sitepackages = True
-setenv = VIRTUAL_ENV={envdir}
commands =
python setup.py testr --slowest --testr-args='tempest.scenario.test_large_ops {posargs}'
@@ -53,7 +61,7 @@
NOSE_OPENSTACK_STDOUT=1
TEMPEST_PY26_NOSE_COMPAT=1
commands =
- nosetests --logging-format '%(asctime)-15s %(message)s' --with-xunit -sv --xunit-file=nosetests-full.xml tempest/api tempest/scenario tempest/thirdparty tempest/cli tempest/tests {posargs}
+ nosetests --logging-format '%(asctime)-15s %(message)s' --with-xunit -sv --xunit-file=nosetests-full.xml tempest/api tempest/scenario tempest/thirdparty tempest/cli {posargs}
[testenv:py26-smoke]
setenv = VIRTUAL_ENV={envdir}
@@ -69,7 +77,6 @@
[testenv:smoke]
sitepackages = True
-setenv = VIRTUAL_ENV={envdir}
# This is still serial because neutron doesn't work with parallel. See:
# https://bugs.launchpad.net/tempest/+bug/1216076 so the neutron smoke
# job would fail if we moved it to parallel.
@@ -78,15 +85,13 @@
[testenv:coverage]
sitepackages = True
-setenv = VIRTUAL_ENV={envdir}
commands =
python -m tools/tempest_coverage -c start --combine
- sh tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli|tests))'
+ sh tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli))'
python -m tools/tempest_coverage -c report --html {posargs}
[testenv:stress]
sitepackages = True
-setenv = VIRTUAL_ENV={envdir}
commands =
python -m tempest/stress/run_stress -a -d 3600 -S