Merge "Move test_extension and use base for non-admin"
diff --git a/HACKING.rst b/HACKING.rst
index a209b3f..910a977 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -313,7 +313,7 @@
qualified test name and track test functionality through refactoring. The
format of the metadata looks like::
- @test.idempotent_id('585e934c-448e-43c4-acbf-d06a9b899997')
+ @decorators.idempotent_id('585e934c-448e-43c4-acbf-d06a9b899997')
def test_list_servers_with_detail(self):
# The created server should be in the detailed list of all servers
...
diff --git a/doc/source/test-removal.rst b/doc/source/test-removal.rst
index 4757dc4..d06e4ba 100644
--- a/doc/source/test-removal.rst
+++ b/doc/source/test-removal.rst
@@ -64,7 +64,7 @@
SELECT * from tests where test_id like "%test_id%";
(where $test_id is the full test_id, but truncated to the class because of
-setupClass or tearDownClass failures)
+setUpClass or tearDownClass failures)
You can access the infra mysql subunit2sql db w/ read-only permissions with:
@@ -82,7 +82,7 @@
#. run the query: MySQL [subunit2sql]> select * from tests where test_id like
"tempest.api.compute.admin.test_flavors_negative.FlavorsAdminNegativeTestJSON%";
which will return a table of all the tests in the class (but it will also
- catch failures in setupClass and tearDownClass)
+ catch failures in setUpClass and tearDownClass)
#. paste the output table with numbers and the mysql command you ran to
generate it into the etherpad.
@@ -185,4 +185,4 @@
If a test exists in Tempest that would meet this criteria as consequence of a
change, the test must be removed according to the procedure discussed into
this document. The API change should not be merged until all conditions
-required for test removal can be met.
\ No newline at end of file
+required for test removal can be met.
diff --git a/releasenotes/notes/add-tempest-run-combine-option-e94c1049ba8985d5.yaml b/releasenotes/notes/add-tempest-run-combine-option-e94c1049ba8985d5.yaml
new file mode 100644
index 0000000..73900ca
--- /dev/null
+++ b/releasenotes/notes/add-tempest-run-combine-option-e94c1049ba8985d5.yaml
@@ -0,0 +1,6 @@
+---
+features:
+ - |
+ Adds a new cli option to tempest run, --combine, which is used to indicate
+ you want the subunit stream output combined with the previous run's in
+ the testr repository
diff --git a/releasenotes/notes/deprecate-resources-prefix-option-ad490c0a30a0266b.yaml b/releasenotes/notes/deprecate-resources-prefix-option-ad490c0a30a0266b.yaml
new file mode 100644
index 0000000..f679208
--- /dev/null
+++ b/releasenotes/notes/deprecate-resources-prefix-option-ad490c0a30a0266b.yaml
@@ -0,0 +1,10 @@
+---
+upgrade:
+ - The default value of rand_name()'s prefix argument is changed
+ to 'tempest' from None to identify resources are created by
+ Tempest.
+deprecations:
+ - The resources_prefix is marked as deprecated because it is
+ enough to set 'tempest' as the prefix on rand_name() to
+ ideintify resources which are created by Tempest and no
+ projects set this option on OpenStack dev community.
diff --git a/releasenotes/notes/deprecate-skip_unless_attr-decorator-450a1ed727494724.yaml b/releasenotes/notes/deprecate-skip_unless_attr-decorator-450a1ed727494724.yaml
new file mode 100644
index 0000000..4d8b941
--- /dev/null
+++ b/releasenotes/notes/deprecate-skip_unless_attr-decorator-450a1ed727494724.yaml
@@ -0,0 +1,5 @@
+---
+deprecations:
+ - The ``skip_unless_attr`` decorator in lib/decorators.py has been deprecated,
+ please use the standard ``testtools.skipUnless`` and ``testtools.skipIf``
+ decorators.
diff --git a/releasenotes/notes/use-keystone-v3-api-935860d30ddbb8e9.yaml b/releasenotes/notes/use-keystone-v3-api-935860d30ddbb8e9.yaml
new file mode 100644
index 0000000..dd6e924
--- /dev/null
+++ b/releasenotes/notes/use-keystone-v3-api-935860d30ddbb8e9.yaml
@@ -0,0 +1,5 @@
+---
+upgrade:
+ - Tempest now defaults to using Keystone v3 API for the
+ authentication, because Keystone v3 API is CURRENT and
+ the v2 API is deprecated.
diff --git a/tempest/api/compute/servers/test_create_server.py b/tempest/api/compute/servers/test_create_server.py
index fd5e50e..38dbb50 100644
--- a/tempest/api/compute/servers/test_create_server.py
+++ b/tempest/api/compute/servers/test_create_server.py
@@ -122,7 +122,8 @@
self.validation_resources['keypair']['private_key'],
server=self.server,
servers_client=self.client)
- self.assertEqual(flavor['vcpus'], linux_client.get_number_of_vcpus())
+ output = linux_client.exec_command('grep -c ^processor /proc/cpuinfo')
+ self.assertEqual(flavor['vcpus'], int(output))
@decorators.idempotent_id('ac1ad47f-984b-4441-9274-c9079b7a0666')
@testtools.skipUnless(CONF.validation.run_validation,
@@ -136,7 +137,7 @@
self.validation_resources['keypair']['private_key'],
server=self.server,
servers_client=self.client)
- hostname = linux_client.get_hostname()
+ hostname = linux_client.exec_command("hostname").rstrip()
msg = ('Failed while verifying servername equals hostname. Expected '
'hostname "%s" but got "%s".' % (self.name, hostname))
self.assertEqual(self.name.lower(), hostname, msg)
diff --git a/tempest/api/compute/servers/test_list_server_filters.py b/tempest/api/compute/servers/test_list_server_filters.py
index c0a8eae..7b782de 100644
--- a/tempest/api/compute/servers/test_list_server_filters.py
+++ b/tempest/api/compute/servers/test_list_server_filters.py
@@ -12,13 +12,17 @@
# 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 testtools
from tempest.api.compute import base
from tempest.common import fixed_network
from tempest.common.utils import data_utils
from tempest.common import waiters
+from tempest import config
from tempest.lib import decorators
-from tempest.lib import exceptions as lib_exc
+
+
+CONF = config.CONF
class ListServerFiltersTestJSON(base.BaseV2ComputeTest):
@@ -37,31 +41,6 @@
def resource_setup(cls):
super(ListServerFiltersTestJSON, cls).resource_setup()
- # Check to see if the alternate image ref actually exists...
- images_client = cls.compute_images_client
- images = images_client.list_images()['images']
-
- if cls.image_ref != cls.image_ref_alt and \
- any([image for image in images
- if image['id'] == cls.image_ref_alt]):
- cls.multiple_images = True
- else:
- cls.image_ref_alt = cls.image_ref
-
- # Do some sanity checks here. If one of the images does
- # not exist, fail early since the tests won't work...
- try:
- cls.compute_images_client.show_image(cls.image_ref)
- except lib_exc.NotFound:
- raise RuntimeError("Image %s (image_ref) was not found!" %
- cls.image_ref)
-
- try:
- cls.compute_images_client.show_image(cls.image_ref_alt)
- except lib_exc.NotFound:
- raise RuntimeError("Image %s (image_ref_alt) was not found!" %
- cls.image_ref_alt)
-
network = cls.get_tenant_network()
if network:
cls.fixed_network_name = network.get('name')
@@ -74,9 +53,12 @@
**network_kwargs)
cls.s2_name = data_utils.rand_name(cls.__name__ + '-instance')
- cls.s2 = cls.create_test_server(name=cls.s2_name,
- image_id=cls.image_ref_alt,
- wait_until='ACTIVE')
+ # If image_ref_alt is "" or None then we still want to boot a server
+ # but we rely on `testtools.skipUnless` decorator to actually skip
+ # the irrelevant tests.
+ cls.s2 = cls.create_test_server(
+ name=cls.s2_name, image_id=cls.image_ref_alt or cls.image_ref,
+ wait_until='ACTIVE')
cls.s3_name = data_utils.rand_name(cls.__name__ + '-instance')
cls.s3 = cls.create_test_server(name=cls.s3_name,
@@ -84,7 +66,8 @@
wait_until='ACTIVE')
@decorators.idempotent_id('05e8a8e7-9659-459a-989d-92c2f501f4ba')
- @decorators.skip_unless_attr('multiple_images', 'Only one image found')
+ @testtools.skipUnless(CONF.compute.image_ref != CONF.compute.image_ref_alt,
+ "Need distinct images to run this test")
def test_list_servers_filter_by_image(self):
# Filter the list of servers by image
params = {'image': self.image_ref}
@@ -169,7 +152,8 @@
len([x for x in servers['servers'] if 'id' in x]))
@decorators.idempotent_id('b3304c3b-97df-46d2-8cd3-e2b6659724e7')
- @decorators.skip_unless_attr('multiple_images', 'Only one image found')
+ @testtools.skipUnless(CONF.compute.image_ref != CONF.compute.image_ref_alt,
+ "Need distinct images to run this test")
def test_list_servers_detailed_filter_by_image(self):
# Filter the detailed list of servers by image
params = {'image': self.image_ref}
@@ -269,16 +253,34 @@
if not self.fixed_network_name:
msg = 'fixed_network_name needs to be configured to run this test'
raise self.skipException(msg)
+
+ # list servers filter by ip is something "regexp match", i.e,
+ # filter by "10.1.1.1" will return both "10.1.1.1" and "10.1.1.10".
+ # so here look for the longest server ip, and filter by that ip,
+ # 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
- addr_spec = self.s1['addresses'][self.fixed_network_name][0]
- params = {'ip': addr_spec['addr']}
+ ip_addr = self.s1['addresses'][self.fixed_network_name][0]['addr']
+ ip_list[ip_addr] = self.s1['id']
+
+ self.s2 = self.client.show_server(self.s2['id'])['server']
+ ip_addr = self.s2['addresses'][self.fixed_network_name][0]['addr']
+ ip_list[ip_addr] = self.s2['id']
+
+ self.s3 = self.client.show_server(self.s3['id'])['server']
+ ip_addr = self.s3['addresses'][self.fixed_network_name][0]['addr']
+ ip_list[ip_addr] = self.s3['id']
+
+ longest_ip = max([[len(ip), ip] for ip in ip_list])[1]
+ params = {'ip': longest_ip}
body = self.client.list_servers(**params)
servers = body['servers']
- self.assertIn(self.s1_name, map(lambda x: x['name'], servers))
- self.assertNotIn(self.s2_name, map(lambda x: x['name'], servers))
- self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers))
+ self.assertIn(ip_list[longest_ip], map(lambda x: x['id'], servers))
+ del ip_list[longest_ip]
+ for ip in ip_list:
+ self.assertNotIn(ip_list[ip], map(lambda x: x['id'], servers))
@decorators.skip_because(bug="1540645")
@decorators.idempotent_id('a905e287-c35e-42f2-b132-d02b09f3654a')
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index 6160024..b915739 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -471,7 +471,7 @@
# NOTE: SHUTOFF is irregular status. To avoid test instability,
# one server is created only for this test without using
- # the server that was created in setupClass.
+ # the server that was created in setUpClass.
server = self.create_test_server(wait_until='ACTIVE')
temp_server_id = server['id']
diff --git a/tempest/api/compute/test_versions.py b/tempest/api/compute/test_versions.py
index c9f0724..dcab067 100644
--- a/tempest/api/compute/test_versions.py
+++ b/tempest/api/compute/test_versions.py
@@ -14,11 +14,13 @@
from tempest.api.compute import base
from tempest.lib import decorators
+from tempest import test
class TestVersions(base.BaseV2ComputeTest):
@decorators.idempotent_id('6c0a0990-43b6-4529-9b61-5fd8daf7c55c')
+ @test.attr(type='smoke')
def test_list_api_versions(self):
"""Test that a get of the unversioned url returns the choices doc.
@@ -37,6 +39,7 @@
"The first listed version should be v2.0")
@decorators.idempotent_id('b953a29e-929c-4a8e-81be-ec3a7e03cb76')
+ @test.attr(type='smoke')
def test_get_version_details(self):
"""Test individual version endpoints info works.
diff --git a/tempest/api/identity/base.py b/tempest/api/identity/base.py
index 80e7936..344779c 100644
--- a/tempest/api/identity/base.py
+++ b/tempest/api/identity/base.py
@@ -15,6 +15,7 @@
from tempest.common.utils import data_utils
from tempest import config
+from tempest.lib.common.utils import test_utils
import tempest.test
CONF = config.CONF
@@ -72,7 +73,9 @@
kwargs['password'] = user_password
user = self.users_client.create_user(**kwargs)['user']
# Delete the user at the end of the test
- self.addCleanup(self.users_client.delete_user, user['id'])
+ self.addCleanup(
+ test_utils.call_and_ignore_notfound_exc,
+ self.users_client.delete_user, user['id'])
return user
def setup_test_role(self, domain_id=None):
@@ -83,7 +86,9 @@
role = self.roles_client.create_role(**params)['role']
# Delete the role at the end of the test
- self.addCleanup(self.roles_client.delete_role, role['id'])
+ self.addCleanup(
+ test_utils.call_and_ignore_notfound_exc,
+ self.roles_client.delete_role, role['id'])
return role
@@ -152,7 +157,9 @@
name=data_utils.rand_name('test_tenant'),
description=data_utils.rand_name('desc'))['tenant']
# Delete the tenant at the end of the test
- self.addCleanup(self.tenants_client.delete_tenant, tenant['id'])
+ self.addCleanup(
+ test_utils.call_and_ignore_notfound_exc,
+ self.tenants_client.delete_tenant, tenant['id'])
return tenant
@@ -246,12 +253,16 @@
name=data_utils.rand_name('test_project'),
description=data_utils.rand_name('desc'))['project']
# Delete the project at the end of the test
- self.addCleanup(self.projects_client.delete_project, project['id'])
+ self.addCleanup(
+ test_utils.call_and_ignore_notfound_exc,
+ self.projects_client.delete_project, project['id'])
return project
def setup_test_domain(self):
"""Set up a test domain."""
domain = self.create_domain()
# Delete the domain at the end of the test
- self.addCleanup(self.delete_domain, domain['id'])
+ self.addCleanup(
+ test_utils.call_and_ignore_notfound_exc,
+ self.delete_domain, domain['id'])
return domain
diff --git a/tempest/api/orchestration/stacks/test_neutron_resources.py b/tempest/api/orchestration/stacks/test_neutron_resources.py
index 3a52108..0154658 100644
--- a/tempest/api/orchestration/stacks/test_neutron_resources.py
+++ b/tempest/api/orchestration/stacks/test_neutron_resources.py
@@ -84,12 +84,15 @@
# to heat.
body = cls.client.show_resource(cls.stack_identifier,
'Server')
- server_id = body['physical_resource_id']
- LOG.debug('Console output for %s', server_id)
- output = cls.servers_client.get_console_output(
- server_id)['output']
- LOG.debug(output)
- raise
+ server_id = body.get('physical_resource_id')
+ if server_id:
+ LOG.debug('Console output for %s', server_id)
+ output = cls.servers_client.get_console_output(
+ server_id)['output']
+ LOG.debug(output)
+ else:
+ LOG.debug('Server resource is %s', body)
+ raise # original exception
cls.test_resources = {}
for resource in resources:
diff --git a/tempest/cmd/run.py b/tempest/cmd/run.py
index 54b844a..b36bf5c 100644
--- a/tempest/cmd/run.py
+++ b/tempest/cmd/run.py
@@ -78,11 +78,20 @@
subunit-trace output filter. But, if you would prefer a subunit v2 stream be
output to STDOUT use the **--subunit** flag
+Combining Runs
+==============
+
+There are certain situations in which you want to split a single run of tempest
+across 2 executions of tempest run. (for example to run part of the tests
+serially and others in parallel) To accomplish this but still treat the results
+as a single run you can leverage the **--combine** option which will append
+the current run's results with the previous runs.
"""
import io
import os
import sys
+import tempfile
import threading
from cliff import command
@@ -165,6 +174,12 @@
else:
print("No .testr.conf file was found for local execution")
sys.exit(2)
+ if parsed_args.combine:
+ temp_stream = tempfile.NamedTemporaryFile()
+ return_code = run_argv(['tempest', 'last', '--subunit'], sys.stdin,
+ temp_stream, sys.stderr)
+ if return_code > 0:
+ sys.exit(return_code)
regex = self._build_regex(parsed_args)
if parsed_args.list_tests:
@@ -173,6 +188,16 @@
else:
options = self._build_options(parsed_args)
returncode = self._run(regex, options)
+ if returncode > 0:
+ sys.exit(returncode)
+
+ if parsed_args.combine:
+ return_code = run_argv(['tempest', 'last', '--subunit'], sys.stdin,
+ temp_stream, sys.stderr)
+ if return_code > 0:
+ sys.exit(return_code)
+ returncode = run_argv(['tempest', 'load', temp_stream.name],
+ sys.stdin, sys.stdout, sys.stderr)
sys.exit(returncode)
def get_description(self):
@@ -231,6 +256,10 @@
# output args
parser.add_argument("--subunit", action='store_true',
help='Enable subunit v2 output')
+ parser.add_argument("--combine", action='store_true',
+ help='Combine the output of this run with the '
+ "previous run's as a combined stream in the "
+ "testr repository after it finish")
parser.set_defaults(parallel=True)
return parser
diff --git a/tempest/common/utils/__init__.py b/tempest/common/utils/__init__.py
index b6565d1..84e31d0 100644
--- a/tempest/common/utils/__init__.py
+++ b/tempest/common/utils/__init__.py
@@ -19,10 +19,6 @@
CONF = config.CONF
-PING_IPV4_COMMAND = 'ping -c 3 '
-PING_IPV6_COMMAND = 'ping6 -c 3 '
-PING_PACKET_LOSS_REGEX = '(\d{1,3})\.?\d*\% packet loss'
-
class DataUtils(object):
def __getattr__(self, attr):
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index 1487c1d..1aa09e6 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -75,9 +75,13 @@
"""
self.server = server
self.servers_client = servers_client
+
ssh_timeout = CONF.validation.ssh_timeout
connect_timeout = CONF.validation.connect_timeout
self.log_console = CONF.compute_feature_enabled.console_output
+ self.ssh_shell_prologue = CONF.validation.ssh_shell_prologue
+ self.ping_count = CONF.validation.ping_count
+ self.ping_size = CONF.validation.ping_size
self.ssh_client = ssh.Client(ip_address, username, password,
ssh_timeout, pkey=pkey,
@@ -87,7 +91,7 @@
def exec_command(self, cmd):
# Shell options below add more clearness on failures,
# path is extended for some non-cirros guest oses (centos7)
- cmd = CONF.validation.ssh_shell_prologue + " " + cmd
+ cmd = self.ssh_shell_prologue + " " + cmd
LOG.debug("Remote command: %s", cmd)
return self.ssh_client.exec_command(cmd)
@@ -99,20 +103,6 @@
"""
self.ssh_client.test_connection_auth()
- def get_hostname(self):
- # Get host name using command "hostname"
- actual_hostname = self.exec_command("hostname").rstrip()
- return actual_hostname
-
- def get_ram_size_in_mb(self):
- output = self.exec_command('free -m | grep Mem')
- if output:
- return output.split()[1]
-
- def get_number_of_vcpus(self):
- output = self.exec_command('grep -c ^processor /proc/cpuinfo')
- return int(output)
-
def get_disks(self):
# Select root disk devices as shown by lsblk
command = 'lsblk -lb --nodeps'
@@ -142,8 +132,12 @@
cmd = 'sudo sh -c "echo \\"%s\\" >/dev/console"' % message
return self.exec_command(cmd)
- def ping_host(self, host, count=CONF.validation.ping_count,
- size=CONF.validation.ping_size, nic=None):
+ def ping_host(self, host, count=None, size=None, nic=None):
+ if count is None:
+ count = self.ping_count
+ if size is None:
+ size = self.ping_size
+
addr = netaddr.IPAddress(host)
cmd = 'ping6' if addr.version == 6 else 'ping'
if nic:
@@ -176,11 +170,9 @@
cmd = "ip address"
return self.exec_command(cmd)
- def assign_static_ip(self, nic, addr):
+ def assign_static_ip(self, nic, addr, network_mask_bits=28):
cmd = "sudo ip addr add {ip}/{mask} dev {nic}".format(
- ip=addr, mask=CONF.network.project_network_mask_bits,
- nic=nic
- )
+ ip=addr, mask=network_mask_bits, nic=nic)
return self.exec_command(cmd)
def set_nic_state(self, nic, state="up"):
@@ -218,7 +210,7 @@
cmd = "sudo /sbin/dhclient -r && sudo /sbin/dhclient"
self.exec_command(cmd)
- def renew_lease(self, fixed_ip=None):
+ def renew_lease(self, fixed_ip=None, dhcp_client='udhcpc'):
"""Wrapper method for renewing DHCP lease via given client
Supporting:
@@ -227,7 +219,6 @@
"""
# TODO(yfried): add support for dhcpcd
supported_clients = ['udhcpc', 'dhclient']
- dhcp_client = CONF.scenario.dhcp_client
if dhcp_client not in supported_clients:
raise tempest.lib.exceptions.InvalidConfiguration(
'%s DHCP client unsupported' % dhcp_client)
diff --git a/tempest/config.py b/tempest/config.py
index 651c32e..274cd21 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -133,7 +133,7 @@
cfg.StrOpt('uri_v3',
help='Full URI of the OpenStack Identity API (Keystone), v3'),
cfg.StrOpt('auth_version',
- default='v2',
+ default='v3',
help="Identity API version to be used for authentication "
"for API tests."),
cfg.StrOpt('region',
@@ -1028,7 +1028,12 @@
help="Prefix to be added when generating the name for "
"test resources. It can be used to discover all "
"resources associated with a specific test run when "
- "running tempest on a real-life cloud"),
+ "running tempest on a real-life cloud",
+ deprecated_for_removal=True,
+ deprecated_reason="It is enough to add 'tempest' as this "
+ "prefix to ideintify resources which are "
+ "created by Tempest and no projects set "
+ "this option on OpenStack dev community."),
]
_opts = [
diff --git a/tempest/lib/api_schema/response/compute/v2_1/keypairs.py b/tempest/lib/api_schema/response/compute/v2_1/keypairs.py
index 2828097..e7dcf79 100644
--- a/tempest/lib/api_schema/response/compute/v2_1/keypairs.py
+++ b/tempest/lib/api_schema/response/compute/v2_1/keypairs.py
@@ -34,12 +34,9 @@
},
'additionalProperties': False,
- # When we run the get keypair API, response body includes
- # all the above mentioned attributes.
- # But in Nova API sample file, response body includes only
- # 'public_key', 'name' & 'fingerprint'. So only 'public_key',
- # 'name' & 'fingerprint' are defined as 'required'.
- 'required': ['public_key', 'name', 'fingerprint']
+ 'required': ['public_key', 'name', 'fingerprint', 'user_id',
+ 'deleted', 'created_at', 'updated_at',
+ 'deleted_at', 'id']
}
},
'additionalProperties': False,
diff --git a/tempest/lib/cmd/check_uuid.py b/tempest/lib/cmd/check_uuid.py
index 283b10f..eafde44 100755
--- a/tempest/lib/cmd/check_uuid.py
+++ b/tempest/lib/cmd/check_uuid.py
@@ -26,10 +26,6 @@
from oslo_utils import uuidutils
import six.moves.urllib.parse as urlparse
-# TODO(oomichi): Need to remove this after switching all modules to decorators
-# on all OpenStack projects because they runs check-uuid on their own gates.
-OLD_DECORATOR_MODULE = 'test'
-
DECORATOR_MODULE = 'decorators'
DECORATOR_NAME = 'idempotent_id'
DECORATOR_IMPORT = 'tempest.%s' % DECORATOR_MODULE
@@ -128,8 +124,7 @@
hasattr(decorator.func, 'attr') and
decorator.func.attr == DECORATOR_NAME and
hasattr(decorator.func, 'value') and
- (decorator.func.value.id == DECORATOR_MODULE or
- decorator.func.value.id == OLD_DECORATOR_MODULE)):
+ decorator.func.value.id == DECORATOR_MODULE):
for arg in decorator.args:
idempotent_id = ast.literal_eval(arg)
return idempotent_id
@@ -361,7 +356,7 @@
sys.exit("@decorators.idempotent_id existence and uniqueness checks "
"failed\n"
"Run 'tox -v -euuidgen' to automatically fix tests with\n"
- "missing @test.idempotent_id decorators.")
+ "missing @decorators.idempotent_id decorators.")
if __name__ == '__main__':
run()
diff --git a/tempest/lib/common/utils/data_utils.py b/tempest/lib/common/utils/data_utils.py
index 642514b..a0941ef 100644
--- a/tempest/lib/common/utils/data_utils.py
+++ b/tempest/lib/common/utils/data_utils.py
@@ -43,7 +43,7 @@
return uuid.uuid4().hex
-def rand_name(name='', prefix=None):
+def rand_name(name='', prefix='tempest'):
"""Generate a random name that includes a random number
:param str name: The name that you want to include
diff --git a/tempest/lib/decorators.py b/tempest/lib/decorators.py
index 6ed99b4..92f9698 100644
--- a/tempest/lib/decorators.py
+++ b/tempest/lib/decorators.py
@@ -15,6 +15,7 @@
import functools
import uuid
+import debtcollector.removals
import six
import testtools
@@ -61,6 +62,7 @@
return decorator
+@debtcollector.removals.remove(removal_version='Queen')
class skip_unless_attr(object):
"""Decorator to skip tests if a specified attr does not exists or False"""
def __init__(self, attr, msg=None):
diff --git a/tempest/scenario/test_aggregates_basic_ops.py b/tempest/scenario/test_aggregates_basic_ops.py
index 5152472..b0b516a 100644
--- a/tempest/scenario/test_aggregates_basic_ops.py
+++ b/tempest/scenario/test_aggregates_basic_ops.py
@@ -96,6 +96,7 @@
return aggregate
@decorators.idempotent_id('cb2b4c4f-0c7c-4164-bdde-6285b302a081')
+ @test.attr(type='slow')
@test.services('compute')
def test_aggregate_basic_ops(self):
self.useFixture(fixtures.LockFixture('availability_zone'))
diff --git a/tempest/scenario/test_encrypted_cinder_volumes.py b/tempest/scenario/test_encrypted_cinder_volumes.py
index da29485..a05b1b1 100644
--- a/tempest/scenario/test_encrypted_cinder_volumes.py
+++ b/tempest/scenario/test_encrypted_cinder_volumes.py
@@ -62,6 +62,7 @@
self.nova_volume_detach(server, attached_volume)
@decorators.idempotent_id('79165fb4-5534-4b9d-8429-97ccffb8f86e')
+ @test.attr(type='slow')
@test.services('compute', 'volume', 'image')
def test_encrypted_cinder_volumes_luks(self):
server = self.launch_instance()
@@ -71,6 +72,7 @@
self.attach_detach_volume(server, volume)
@decorators.idempotent_id('cbc752ed-b716-4717-910f-956cce965722')
+ @test.attr(type='slow')
@test.services('compute', 'volume', 'image')
def test_encrypted_cinder_volumes_cryptsetup(self):
server = self.launch_instance()
diff --git a/tempest/scenario/test_network_advanced_server_ops.py b/tempest/scenario/test_network_advanced_server_ops.py
index 1196659..6665fa7 100644
--- a/tempest/scenario/test_network_advanced_server_ops.py
+++ b/tempest/scenario/test_network_advanced_server_ops.py
@@ -104,6 +104,7 @@
return body['OS-EXT-SRV-ATTR:host']
@decorators.idempotent_id('61f1aa9a-1573-410e-9054-afa557cab021')
+ @test.attr(type='slow')
@test.services('compute', 'network')
def test_server_connectivity_stop_start(self):
keypair = self.create_keypair()
@@ -129,6 +130,7 @@
server, keypair, floating_ip)
@decorators.idempotent_id('88a529c2-1daa-4c85-9aec-d541ba3eb699')
+ @test.attr(type='slow')
@test.services('compute', 'network')
def test_server_connectivity_rebuild(self):
keypair = self.create_keypair()
@@ -143,6 +145,7 @@
@decorators.idempotent_id('2b2642db-6568-4b35-b812-eceed3fa20ce')
@testtools.skipUnless(CONF.compute_feature_enabled.pause,
'Pause is not available.')
+ @test.attr(type='slow')
@test.services('compute', 'network')
def test_server_connectivity_pause_unpause(self):
keypair = self.create_keypair()
@@ -160,6 +163,7 @@
@decorators.idempotent_id('5cdf9499-541d-4923-804e-b9a60620a7f0')
@testtools.skipUnless(CONF.compute_feature_enabled.suspend,
'Suspend is not available.')
+ @test.attr(type='slow')
@test.services('compute', 'network')
def test_server_connectivity_suspend_resume(self):
keypair = self.create_keypair()
@@ -177,6 +181,7 @@
@decorators.idempotent_id('719eb59d-2f42-4b66-b8b1-bb1254473967')
@testtools.skipUnless(CONF.compute_feature_enabled.resize,
'Resize is not available.')
+ @test.attr(type='slow')
@test.services('compute', 'network')
def test_server_connectivity_resize(self):
resize_flavor = CONF.compute.flavor_ref_alt
@@ -200,6 +205,7 @@
@testtools.skipUnless(CONF.compute.min_compute_nodes > 1,
'Less than 2 compute nodes, skipping multinode '
'tests.')
+ @test.attr(type='slow')
@test.services('compute', 'network')
def test_server_connectivity_cold_migration(self):
keypair = self.create_keypair()
@@ -225,6 +231,7 @@
@testtools.skipUnless(CONF.compute.min_compute_nodes > 1,
'Less than 2 compute nodes, skipping multinode '
'tests.')
+ @test.attr(type='slow')
@test.services('compute', 'network')
def test_server_connectivity_cold_migration_revert(self):
keypair = self.create_keypair()
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index 51b59c9..85d7e37 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -285,9 +285,9 @@
% CONF.network.build_timeout)
num, new_nic = self.diff_list[0]
- ssh_client.assign_static_ip(nic=new_nic,
- addr=new_port['fixed_ips'][0][
- 'ip_address'])
+ ssh_client.assign_static_ip(
+ nic=new_nic, addr=new_port['fixed_ips'][0]['ip_address'],
+ network_mask_bits=CONF.network.project_network_mask_bits)
ssh_client.set_nic_state(nic=new_nic)
def _get_server_nics(self, ssh_client):
@@ -406,6 +406,7 @@
@decorators.idempotent_id('b158ea55-472e-4086-8fa9-c64ac0c6c1d0')
@testtools.skipUnless(test.is_extension_enabled('net-mtu', 'network'),
'No way to calculate MTU for networks')
+ @test.attr(type='slow')
@test.services('compute', 'network')
def test_mtu_sized_frames(self):
"""Validate that network MTU sized frames fit through."""
@@ -418,6 +419,7 @@
'Connectivity can only be tested when in a '
'multitenant network environment')
@decorators.skip_because(bug="1610994")
+ @test.attr(type='slow')
@test.services('compute', 'network')
def test_connectivity_between_vms_on_different_networks(self):
"""Test connectivity between VMs on different networks
@@ -493,6 +495,7 @@
@testtools.skipIf(CONF.network.shared_physical_network,
'Router state can be altered only with multitenant '
'networks capabilities')
+ @test.attr(type='slow')
@test.services('compute', 'network')
def test_update_router_admin_state(self):
"""Test to update admin state up of router
@@ -526,6 +529,7 @@
'network isolation not available')
@testtools.skipUnless(CONF.scenario.dhcp_client,
"DHCP client is not available.")
+ @test.attr(type='slow')
@test.services('compute', 'network')
def test_subnet_details(self):
"""Tests that subnet's extra configuration details are affecting VMs.
@@ -592,7 +596,8 @@
# NOTE(amuller): we are renewing the lease as part of the retry
# because Neutron updates dnsmasq asynchronously after the
# subnet-update API call returns.
- ssh_client.renew_lease(fixed_ip=floating_ip['fixed_ip_address'])
+ ssh_client.renew_lease(fixed_ip=floating_ip['fixed_ip_address'],
+ dhcp_client=CONF.scenario.dhcp_client)
if ssh_client.get_dns_servers() != [alt_dns_server]:
LOG.debug("Failed to update DNS nameservers")
return False
@@ -608,6 +613,7 @@
@testtools.skipUnless(CONF.network_feature_enabled.port_admin_state_change,
"Changing a port's admin state is not supported "
"by the test environment")
+ @test.attr(type='slow')
@test.services('compute', 'network')
def test_update_instance_port_admin_state(self):
"""Test to update admin_state_up attribute of instance port
@@ -653,6 +659,7 @@
should_succeed=True)
@decorators.idempotent_id('759462e1-8535-46b0-ab3a-33aa45c55aaa')
+ @test.attr(type='slow')
@test.services('compute', 'network')
def test_preserve_preexisting_port(self):
"""Test preserve pre-existing port
@@ -704,6 +711,7 @@
@test.requires_ext(service='network', extension='l3_agent_scheduler')
@decorators.idempotent_id('2e788c46-fb3f-4ac9-8f82-0561555bea73')
+ @test.attr(type='slow')
@test.services('compute', 'network')
def test_router_rescheduling(self):
"""Tests that router can be removed from agent and add to a new agent.
@@ -783,6 +791,7 @@
@testtools.skipUnless(CONF.compute_feature_enabled.interface_attach,
'NIC hotplug not available')
@decorators.idempotent_id('7c0bb1a2-d053-49a4-98f9-ca1a1d849f63')
+ @test.attr(type='slow')
@test.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 fcf395d..d8a1363 100644
--- a/tempest/scenario/test_network_v6.py
+++ b/tempest/scenario/test_network_v6.py
@@ -240,6 +240,7 @@
def test_dualnet_dhcp6_stateless_from_os(self):
self._prepare_and_test(address6_mode='dhcpv6-stateless', dualnet=True)
+ @test.attr(type='slow')
@decorators.idempotent_id('cf1c4425-766b-45b8-be35-e2959728eb00')
@test.services('compute', 'network')
def test_dualnet_multi_prefix_dhcpv6_stateless(self):
diff --git a/tempest/scenario/test_object_storage_basic_ops.py b/tempest/scenario/test_object_storage_basic_ops.py
index c989e01..7fd8c91 100644
--- a/tempest/scenario/test_object_storage_basic_ops.py
+++ b/tempest/scenario/test_object_storage_basic_ops.py
@@ -46,6 +46,7 @@
self.delete_container(container_name)
@decorators.idempotent_id('916c7111-cb1f-44b2-816d-8f760e4ea910')
+ @test.attr(type='slow')
@test.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 3d383f7..fa12f33 100644
--- a/tempest/scenario/test_security_groups_basic_ops.py
+++ b/tempest/scenario/test_security_groups_basic_ops.py
@@ -494,6 +494,7 @@
raise
@decorators.idempotent_id('f4d556d7-1526-42ad-bafb-6bebf48568f6')
+ @test.attr(type='slow')
@test.services('compute', 'network')
def test_port_update_new_security_group(self):
"""Verifies the traffic after updating the vm port
@@ -548,6 +549,7 @@
raise
@decorators.idempotent_id('d2f77418-fcc4-439d-b935-72eca704e293')
+ @test.attr(type='slow')
@test.services('compute', 'network')
def test_multiple_security_groups(self):
"""Verify multiple security groups and checks that rules
@@ -579,6 +581,7 @@
private_key=private_key,
should_connect=True)
+ @test.attr(type='slow')
@test.requires_ext(service='network', extension='port-security')
@decorators.idempotent_id('7c811dcc-263b-49a3-92d2-1b4d8405f50c')
@test.services('compute', 'network')
@@ -619,6 +622,7 @@
self._log_console_output(servers=tenant.servers)
raise
+ @test.attr(type='slow')
@test.requires_ext(service='network', extension='port-security')
@decorators.idempotent_id('13ccf253-e5ad-424b-9c4a-97b88a026699')
@testtools.skipUnless(
diff --git a/tempest/scenario/test_server_advanced_ops.py b/tempest/scenario/test_server_advanced_ops.py
index ec839cd..1960e9a 100644
--- a/tempest/scenario/test_server_advanced_ops.py
+++ b/tempest/scenario/test_server_advanced_ops.py
@@ -48,6 +48,7 @@
cls.set_network_resources()
super(TestServerAdvancedOps, cls).setup_credentials()
+ @test.attr(type='slow')
@decorators.idempotent_id('e6c28180-7454-4b59-b188-0257af08a63b')
@testtools.skipUnless(CONF.compute_feature_enabled.resize,
'Resize is not available.')
@@ -69,6 +70,7 @@
waiters.wait_for_server_status(self.servers_client, instance_id,
'ACTIVE')
+ @test.attr(type='slow')
@decorators.idempotent_id('949da7d5-72c8-4808-8802-e3d70df98e2c')
@testtools.skipUnless(CONF.compute_feature_enabled.suspend,
'Suspend is not available.')
diff --git a/tempest/scenario/test_shelve_instance.py b/tempest/scenario/test_shelve_instance.py
index 75cef88..9e763f8 100644
--- a/tempest/scenario/test_shelve_instance.py
+++ b/tempest/scenario/test_shelve_instance.py
@@ -74,6 +74,7 @@
private_key=keypair['private_key'])
self.assertEqual(timestamp, timestamp2)
+ @test.attr(type='slow')
@decorators.idempotent_id('1164e700-0af0-4a4c-8792-35909a88743c')
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
@@ -81,6 +82,7 @@
def test_shelve_instance(self):
self._create_server_then_shelve_and_unshelve()
+ @test.attr(type='slow')
@decorators.idempotent_id('c1b6318c-b9da-490b-9c67-9339b627271f')
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
diff --git a/tempest/scenario/test_snapshot_pattern.py b/tempest/scenario/test_snapshot_pattern.py
index 6dedd1d..a699de2 100644
--- a/tempest/scenario/test_snapshot_pattern.py
+++ b/tempest/scenario/test_snapshot_pattern.py
@@ -41,6 +41,7 @@
raise cls.skipException("Snapshotting is not available.")
@decorators.idempotent_id('608e604b-1d63-4a82-8e3e-91bc665c90b4')
+ @test.attr(type='slow')
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
@test.services('compute', 'network', 'image')
diff --git a/tempest/scenario/test_stamp_pattern.py b/tempest/scenario/test_stamp_pattern.py
index 716c0bf..aabb767 100644
--- a/tempest/scenario/test_stamp_pattern.py
+++ b/tempest/scenario/test_stamp_pattern.py
@@ -88,6 +88,7 @@
CONF.compute.build_interval):
raise lib_exc.TimeoutException
+ @test.attr(type='slow')
@decorators.skip_because(bug="1664793")
@decorators.idempotent_id('10fd234a-515c-41e5-b092-8323060598c5')
@testtools.skipUnless(CONF.compute_feature_enabled.snapshot,
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
index b72dae9..8cab19c 100644
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -95,7 +95,6 @@
waiters.wait_for_server_termination(self.servers_client, server['id'])
@decorators.idempotent_id('557cd2c2-4eb8-4dce-98be-f86765ff311b')
- @test.attr(type='smoke')
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
@test.services('compute', 'volume', 'image')
@@ -177,6 +176,7 @@
self.assertEqual(timestamp, timestamp3)
@decorators.idempotent_id('05795fb2-b2a7-4c9f-8fac-ff25aedb1489')
+ @test.attr(type='slow')
@test.services('compute', 'image', 'volume')
def test_create_server_from_volume_snapshot(self):
# Create a volume from an image
diff --git a/tempest/scenario/test_volume_migrate_attached.py b/tempest/scenario/test_volume_migrate_attached.py
index 891e22d..f580ea6 100644
--- a/tempest/scenario/test_volume_migrate_attached.py
+++ b/tempest/scenario/test_volume_migrate_attached.py
@@ -91,6 +91,7 @@
waiters.wait_for_volume_retype(self.volumes_client,
volume_id, new_volume_type)
+ @test.attr(type='slow')
@decorators.idempotent_id('deadd2c2-beef-4dce-98be-f86765ff311b')
@test.services('compute', 'volume')
def test_volume_migrate_attached(self):
diff --git a/tempest/test.py b/tempest/test.py
index 970e97c..52994ac 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -643,7 +643,11 @@
cred_provider, networks_client, CONF.compute.fixed_network_name)
def assertEmpty(self, list, msg=None):
+ if msg is None:
+ msg = "list is not empty: %s" % list
self.assertEqual(0, len(list), msg)
def assertNotEmpty(self, list, msg=None):
+ if msg is None:
+ msg = "list is empty."
self.assertGreater(len(list), 0, msg)
diff --git a/tempest/tests/common/utils/linux/test_remote_client.py b/tempest/tests/common/utils/linux/test_remote_client.py
index 5be6229..1c5e89f 100644
--- a/tempest/tests/common/utils/linux/test_remote_client.py
+++ b/tempest/tests/common/utils/linux/test_remote_client.py
@@ -67,16 +67,6 @@
self.ssh_mock = self.useFixture(mockpatch.PatchObject(self.conn,
'ssh_client'))
- def test_get_hostname(self):
- self.ssh_mock.mock.exec_command.return_value = 'fake_hostname'
- self.assertEqual(self.conn.get_hostname(), 'fake_hostname')
-
- def test_get_ram_size(self):
- free_output = "Mem: 48294 45738 2555 0" \
- "402 40346"
- self.ssh_mock.mock.exec_command.return_value = free_output
- self.assertEqual(self.conn.get_ram_size_in_mb(), '48294')
-
def test_write_to_console_regular_str(self):
self.conn.write_to_console('test')
self._assert_exec_called_with(
@@ -102,11 +92,6 @@
cmd = "set -eu -o pipefail; PATH=$PATH:/sbin; " + cmd
self.ssh_mock.mock.exec_command.assert_called_with(cmd)
- def test_get_number_of_vcpus(self):
- self.ssh_mock.mock.exec_command.return_value = '16'
- self.assertEqual(self.conn.get_number_of_vcpus(), 16)
- self._assert_exec_called_with('grep -c ^processor /proc/cpuinfo')
-
def test_get_disks(self):
output_lsblk = """\
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
diff --git a/tempest/tests/lib/common/utils/test_data_utils.py b/tempest/tests/lib/common/utils/test_data_utils.py
index 4446e5c..8bdf70e 100644
--- a/tempest/tests/lib/common/utils/test_data_utils.py
+++ b/tempest/tests/lib/common/utils/test_data_utils.py
@@ -37,16 +37,20 @@
actual2 = data_utils.rand_uuid_hex()
self.assertNotEqual(actual, actual2)
- def test_rand_name(self):
- actual = data_utils.rand_name()
+ def test_rand_name_with_default_prefix(self):
+ actual = data_utils.rand_name('foo')
self.assertIsInstance(actual, str)
- actual2 = data_utils.rand_name()
+ self.assertTrue(actual.startswith('tempest-foo'))
+ actual2 = data_utils.rand_name('foo')
+ self.assertTrue(actual2.startswith('tempest-foo'))
self.assertNotEqual(actual, actual2)
- actual = data_utils.rand_name('foo')
+ def test_rand_name_with_none_prefix(self):
+ actual = data_utils.rand_name('foo', prefix=None)
+ self.assertIsInstance(actual, str)
self.assertTrue(actual.startswith('foo'))
- actual2 = data_utils.rand_name('foo')
- self.assertTrue(actual.startswith('foo'))
+ actual2 = data_utils.rand_name('foo', prefix=None)
+ self.assertTrue(actual2.startswith('foo'))
self.assertNotEqual(actual, actual2)
def test_rand_name_with_prefix(self):
diff --git a/tools/tox_install.sh b/tools/tox_install.sh
new file mode 100755
index 0000000..43468e4
--- /dev/null
+++ b/tools/tox_install.sh
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+
+# Client constraint file contains this client version pin that is in conflict
+# with installing the client from source. We should remove the version pin in
+# the constraints file before applying it for from-source installation.
+
+CONSTRAINTS_FILE=$1
+shift 1
+
+set -e
+
+# NOTE(tonyb): Place this in the tox enviroment's log dir so it will get
+# published to logs.openstack.org for easy debugging.
+localfile="$VIRTUAL_ENV/log/upper-constraints.txt"
+
+if [[ $CONSTRAINTS_FILE != http* ]]; then
+ CONSTRAINTS_FILE=file://$CONSTRAINTS_FILE
+fi
+# NOTE(tonyb): need to add curl to bindep.txt if the project supports bindep
+curl $CONSTRAINTS_FILE --insecure --progress-bar --output $localfile
+
+pip install -c$localfile openstack-requirements
+
+# This is the main purpose of the script: Allow local installation of
+# the current repo. It is listed in constraints file and thus any
+# install will be constrained and we need to unconstrain it.
+edit-constraints $localfile -- $CLIENT_NAME
+
+pip install -c$localfile -U $*
+exit $?
diff --git a/tox.ini b/tox.ini
index d8d390e..dfa8332 100644
--- a/tox.ini
+++ b/tox.ini
@@ -8,6 +8,8 @@
setenv =
VIRTUAL_ENV={envdir}
OS_TEST_PATH=./tempest/test_discover
+ BRANCH_NAME=master
+ CLIENT_NAME=tempest
deps =
setuptools
-r{toxinidir}/requirements.txt
@@ -17,9 +19,12 @@
VIRTUAL_ENV={envdir}
OS_TEST_PATH=./tempest/tests
PYTHONWARNINGS=default::DeprecationWarning
-passenv = OS_STDOUT_CAPTURE OS_STDERR_CAPTURE OS_TEST_TIMEOUT OS_TEST_LOCK_PATH OS_TEST_PATH TEMPEST_CONFIG TEMPEST_CONFIG_DIR http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY
+ BRANCH_NAME=master
+ CLIENT_NAME=tempest
+passenv = OS_STDOUT_CAPTURE OS_STDERR_CAPTURE OS_TEST_TIMEOUT OS_TEST_LOCK_PATH OS_TEST_PATH TEMPEST_CONFIG TEMPEST_CONFIG_DIR http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY ZUUL_CACHE_DIR REQUIREMENTS_PIP_LOCATION
usedevelop = True
-install_command = pip install -U {opts} {packages}
+install_command =
+ {toxinidir}/tools/tox_install.sh {env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages}
whitelist_externals = *
deps =
-r{toxinidir}/requirements.txt
@@ -78,7 +83,8 @@
# See the testrepository bug: https://bugs.launchpad.net/testrepository/+bug/1208610
commands =
find . -type f -name "*.pyc" -delete
- tempest run --regex '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario))' {posargs}
+ tempest run --regex '(?!.*\[.*\bslow\b.*\])(^tempest\.api)' {posargs}
+ tempest run --combine --serial --regex '(?!.*\[.*\bslow\b.*\])(^tempest\.scenario)' {posargs}
[testenv:full-serial]
envdir = .tox/tempest
@@ -91,6 +97,16 @@
find . -type f -name "*.pyc" -delete
tempest run --serial --regex '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario))' {posargs}
+[testenv:scenario]
+envdir = .tox/tempest
+sitepackages = {[tempestenv]sitepackages}
+setenv = {[tempestenv]setenv}
+deps = {[tempestenv]deps}
+# The regex below is used to select all scenario tests
+commands =
+ find . -type f -name "*.pyc" -delete
+ tempest run --serial --regex '(^tempest\.scenario)' {posargs}
+
[testenv:smoke]
envdir = .tox/tempest
sitepackages = {[tempestenv]sitepackages}