Merge "Add black-list based tests for tempest run command"
diff --git a/.zuul.yaml b/.zuul.yaml
index ef9b0eb..8576455 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -222,6 +222,13 @@
LIVE_MIGRATION_AVAILABLE: true
USE_BLOCK_MIGRATION_FOR_LIVE_MIGRATION: true
+- job:
+ name: tempest-multinode-full-py3
+ parent: tempest-multinode-full
+ vars:
+ devstack_localrc:
+ USE_PYTHON3: true
+
- nodeset:
name: openstack-bionic-node
nodes:
@@ -272,6 +279,20 @@
tempest_concurrency: 2
- job:
+ name: tempest-slow-py3
+ parent: tempest-slow
+ vars:
+ devstack_localrc:
+ USE_PYTHON3: true
+ devstack_services:
+ s-account: false
+ s-container: false
+ s-object: false
+ s-proxy: false
+ # without Swift, c-bak cannot run (in the Gate at least)
+ c-bak: false
+
+- job:
name: tempest-full-rocky
parent: tempest-full
nodeset: openstack-single-node-xenial
@@ -500,6 +521,8 @@
irrelevant-files: *tempest-irrelevant-files
- tempest-multinode-full:
irrelevant-files: *tempest-irrelevant-files
+ - tempest-multinode-full-py3:
+ irrelevant-files: *tempest-irrelevant-files
- tempest-tox-plugin-sanity-check:
irrelevant-files:
- ^(test-|)requirements.txt$
@@ -513,6 +536,8 @@
# tools/ is not here since this relies on a script in tools/.
- tempest-slow:
irrelevant-files: *tempest-irrelevant-files
+ - tempest-slow-py3:
+ irrelevant-files: *tempest-irrelevant-files
- nova-live-migration:
voting: false
irrelevant-files: *tempest-irrelevant-files
@@ -556,7 +581,7 @@
jobs:
- nova-multiattach:
irrelevant-files: *tempest-irrelevant-files
- - tempest-slow:
+ - tempest-slow-py3:
irrelevant-files: *tempest-irrelevant-files
- neutron-grenade-multinode:
irrelevant-files: *tempest-irrelevant-files
diff --git a/tempest/api/compute/admin/test_keypairs_v210.py b/tempest/api/compute/admin/test_keypairs_v210.py
index 24ea8a1..40ed532 100644
--- a/tempest/api/compute/admin/test_keypairs_v210.py
+++ b/tempest/api/compute/admin/test_keypairs_v210.py
@@ -56,7 +56,7 @@
self.assertEqual(first_keyname, keypair_detail['name'])
self.assertEqual(user_id, keypair_detail['user_id'],
"The fetched keypair is not for requested user!")
- # Create a admin keypair
+ # Create an admin keypair
admin_keypair = self.create_keypair(keypair_type='ssh',
client=self.client)
admin_keypair.pop('private_key', None)
diff --git a/tempest/api/compute/admin/test_servers_on_multinodes.py b/tempest/api/compute/admin/test_servers_on_multinodes.py
index 5cd98f4..bebc8c5 100644
--- a/tempest/api/compute/admin/test_servers_on_multinodes.py
+++ b/tempest/api/compute/admin/test_servers_on_multinodes.py
@@ -105,7 +105,7 @@
asserts the servers are in the group and on different hosts.
"""
hosts = self._create_servers_with_group('anti-affinity')
- hostnames = hosts.values()
+ hostnames = list(hosts.values())
self.assertNotEqual(hostnames[0], hostnames[1],
'Servers are on the same host: %s' % hosts)
@@ -120,6 +120,6 @@
asserts the servers are in the group and on same host.
"""
hosts = self._create_servers_with_group('affinity')
- hostnames = hosts.values()
+ hostnames = list(hosts.values())
self.assertEqual(hostnames[0], hostnames[1],
'Servers are on the different hosts: %s' % hosts)
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 09dd409..624a99e 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -457,7 +457,7 @@
else:
msg = ('When validation.connect_method equals floating, '
'validation_resources cannot be None')
- raise exceptions.InvalidParam(invalid_param=msg)
+ raise lib_exc.InvalidParam(invalid_param=msg)
elif CONF.validation.connect_method == 'fixed':
addresses = server['addresses'][CONF.validation.network_for_ssh]
for address in addresses:
diff --git a/tempest/api/compute/servers/test_attach_interfaces.py b/tempest/api/compute/servers/test_attach_interfaces.py
index 05c2a28..bea23d9 100644
--- a/tempest/api/compute/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/servers/test_attach_interfaces.py
@@ -256,8 +256,8 @@
if not (CONF.auth.use_dynamic_credentials and
CONF.auth.create_isolated_networks and
not CONF.network.shared_physical_network):
- raise self.skipException("Only owner network supports "
- "creating interface by fixed ip.")
+ raise self.skipException("Only owner network supports "
+ "creating interface by fixed ip.")
server, ifs = self._create_server_get_interfaces()
interface_count = len(ifs)
diff --git a/tempest/api/identity/admin/v3/test_domain_configuration.py b/tempest/api/identity/admin/v3/test_domain_configuration.py
index c4e0622..c0b18ca 100644
--- a/tempest/api/identity/admin/v3/test_domain_configuration.py
+++ b/tempest/api/identity/admin/v3/test_domain_configuration.py
@@ -21,6 +21,10 @@
class DomainConfigurationTestJSON(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
custom_config = {
"identity": {
diff --git a/tempest/api/identity/admin/v3/test_project_tags.py b/tempest/api/identity/admin/v3/test_project_tags.py
index d05173b..b7878a8 100644
--- a/tempest/api/identity/admin/v3/test_project_tags.py
+++ b/tempest/api/identity/admin/v3/test_project_tags.py
@@ -25,6 +25,10 @@
class IdentityV3ProjectTagsTest(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
@decorators.idempotent_id('7c123aac-999d-416a-a0fb-84b915ab10de')
@testtools.skipUnless(CONF.identity_feature_enabled.project_tags,
diff --git a/tempest/api/identity/admin/v3/test_tokens.py b/tempest/api/identity/admin/v3/test_tokens.py
index 8ae43d6..5f1b58d 100644
--- a/tempest/api/identity/admin/v3/test_tokens.py
+++ b/tempest/api/identity/admin/v3/test_tokens.py
@@ -42,10 +42,10 @@
user = self.create_test_user(password=user_password)
# Create a couple projects
- project1_name = data_utils.rand_name(name='project')
+ project1_name = data_utils.rand_name(name=self.__class__.__name__)
project1 = self.setup_test_project(name=project1_name)
- project2_name = data_utils.rand_name(name='project')
+ project2_name = data_utils.rand_name(name=self.__class__.__name__)
project2 = self.setup_test_project(name=project2_name)
self.addCleanup(self.projects_client.delete_project, project2['id'])
diff --git a/tempest/api/identity/admin/v3/test_trusts.py b/tempest/api/identity/admin/v3/test_trusts.py
index 83b3c30..54a5ab7 100644
--- a/tempest/api/identity/admin/v3/test_trusts.py
+++ b/tempest/api/identity/admin/v3/test_trusts.py
@@ -49,7 +49,8 @@
def create_trustor_and_roles(self):
# create a project that trusts will be granted on
- trustor_project_name = data_utils.rand_name(name='project')
+ trustor_project_name = data_utils.rand_name(
+ name=self.__class__.__name__)
project = self.projects_client.create_project(
trustor_project_name,
domain_id=CONF.identity.default_domain_id)['project']
diff --git a/tempest/cmd/account_generator.py b/tempest/cmd/account_generator.py
index 25e91aa..7ea0099 100755
--- a/tempest/cmd/account_generator.py
+++ b/tempest/cmd/account_generator.py
@@ -291,13 +291,16 @@
def main(opts=None):
- setup_logging()
+ log_warning = False
if not opts:
- LOG.warning("Use of: 'tempest-account-generator' is deprecated, "
- "please use: 'tempest account-generator'")
+ log_warning = True
opts = get_options()
if opts.config_file:
config.CONF.set_config_path(opts.config_file)
+ setup_logging()
+ if log_warning:
+ LOG.warning("Use of: 'tempest-account-generator' is deprecated, "
+ "please use: 'tempest account-generator'")
if opts.os_tenant_name:
LOG.warning("'os-tenant-name' and 'OS_TENANT_NAME' are both "
"deprecated, please use 'os-project-name' or "
diff --git a/tempest/common/compute.py b/tempest/common/compute.py
index 375113d..1489e60 100644
--- a/tempest/common/compute.py
+++ b/tempest/common/compute.py
@@ -168,10 +168,19 @@
'imageRef': image_id,
'size': CONF.volume.volume_size}
volume = volumes_client.create_volume(**params)
- waiters.wait_for_volume_resource_status(volumes_client,
- volume['volume']['id'],
- 'available')
-
+ try:
+ waiters.wait_for_volume_resource_status(volumes_client,
+ volume['volume']['id'],
+ 'available')
+ except Exception:
+ with excutils.save_and_reraise_exception():
+ try:
+ volumes_client.delete_volume(volume['volume']['id'])
+ volumes_client.wait_for_resource_deletion(
+ volume['volume']['id'])
+ except Exception as exc:
+ LOG.exception("Deleting volume %s failed, exception %s",
+ volume['volume']['id'], exc)
bd_map_v2 = [{
'uuid': volume['volume']['id'],
'source_type': 'volume',
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index 52ccfa9..49d9742 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -98,6 +98,7 @@
def get_nic_name_by_ip(self, address):
cmd = "ip -o addr | awk '/%s/ {print $2}'" % address
nic = self.exec_command(cmd)
+ LOG.debug('(get_nic_name_by_ip) Command result: %s', nic)
return nic.strip().strip(":").split('@')[0].lower()
def get_dns_servers(self):
diff --git a/tempest/lib/cmd/check_uuid.py b/tempest/lib/cmd/check_uuid.py
index 82fcd0b..ac40eef 100755
--- a/tempest/lib/cmd/check_uuid.py
+++ b/tempest/lib/cmd/check_uuid.py
@@ -233,8 +233,8 @@
if self._is_test_case(module, node))
for node in test_cases:
for subnode in filter(self._is_test_method, node.body):
- test_name = '%s.%s' % (node.name, subnode.name)
- tests[module_name]['tests'][test_name] = subnode
+ test_name = '%s.%s' % (node.name, subnode.name)
+ tests[module_name]['tests'][test_name] = subnode
return tests
@staticmethod
diff --git a/tempest/lib/common/rest_client.py b/tempest/lib/common/rest_client.py
index ec46caf..e612bd1 100644
--- a/tempest/lib/common/rest_client.py
+++ b/tempest/lib/common/rest_client.py
@@ -374,7 +374,7 @@
return self.request('COPY', url, extra_headers, headers)
def get_versions(self):
- """Get the versions on a endpoint from the keystone catalog
+ """Get the versions on an endpoint from the keystone catalog
This method will make a GET request on the baseurl from the keystone
catalog to return a list of API versions. It is expected that a GET
@@ -526,7 +526,7 @@
if (resp.status == 205 and
0 != len(set(resp.keys()) - set(('status',)) -
self.response_header_lc - self.general_header_lc)):
- raise exceptions.ResponseWithEntity()
+ raise exceptions.ResponseWithEntity()
# NOTE(afazekas)
# Now the swift sometimes (delete not empty container)
# returns with non json error response, we can create new rest class
diff --git a/tempest/lib/services/clients.py b/tempest/lib/services/clients.py
index e7ac423..90debd9 100644
--- a/tempest/lib/services/clients.py
+++ b/tempest/lib/services/clients.py
@@ -18,7 +18,6 @@
import importlib
import inspect
import sys
-import warnings
from debtcollector import removals
from oslo_log import log as logging
@@ -35,7 +34,6 @@
from tempest.lib.services import placement
from tempest.lib.services import volume
-warnings.simplefilter("once")
LOG = logging.getLogger(__name__)
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index c11070c..7992585 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -579,10 +579,17 @@
initial_dns_server = '1.2.3.4'
alt_dns_server = '9.8.7.6'
- # renewal should be immediate.
- # Timeouts are suggested by salvatore-orlando in
+ # Original timeouts are suggested by salvatore-orlando in
# https://bugs.launchpad.net/neutron/+bug/1412325/comments/3
- renew_delay = CONF.network.build_interval
+ #
+ # Compared to that renew_delay was increased, because
+ # busybox's udhcpc accepts SIGUSR1 as a renew request. Internally
+ # it goes into RENEW_REQUESTED state. If it receives a 2nd SIGUSR1
+ # signal while in that state then it calls the deconfig script
+ # ("/sbin/cirros-dhcpc deconfig" in sufficiently new cirros versions)
+ # which leads to the address being transiently deconfigured which
+ # for our case is unwanted.
+ renew_delay = 3 * CONF.network.build_interval
renew_timeout = CONF.network.build_timeout
self._setup_network_and_servers(dns_nameservers=[initial_dns_server])
diff --git a/tempest/tests/cmd/test_run.py b/tempest/tests/cmd/test_run.py
index 36f5fb0..4f84ae0 100644
--- a/tempest/tests/cmd/test_run.py
+++ b/tempest/tests/cmd/test_run.py
@@ -108,6 +108,27 @@
subprocess.call(['stestr', 'init'])
self.assertRunExit(['tempest', 'run', '--regex', 'passing'], 0)
+ def test_tempest_run_failing(self):
+ self.assertRunExit(['tempest', 'run', '--regex', 'failing'], 1)
+
+ def test_tempest_run_failing_with_stestr_repository(self):
+ subprocess.call(['stestr', 'init'])
+ self.assertRunExit(['tempest', 'run', '--regex', 'failing'], 1)
+
+ def test_tempest_run_blackregex_failing(self):
+ self.assertRunExit(['tempest', 'run', '--black-regex', 'failing'], 0)
+
+ def test_tempest_run_blackregex_failing_with_stestr_repository(self):
+ subprocess.call(['stestr', 'init'])
+ self.assertRunExit(['tempest', 'run', '--black-regex', 'failing'], 0)
+
+ def test_tempest_run_blackregex_passing(self):
+ self.assertRunExit(['tempest', 'run', '--black-regex', 'passing'], 1)
+
+ def test_tempest_run_blackregex_passing_with_stestr_repository(self):
+ subprocess.call(['stestr', 'init'])
+ self.assertRunExit(['tempest', 'run', '--black-regex', 'passing'], 1)
+
def test_tempest_run_fails(self):
self.assertRunExit(['tempest', 'run'], 1)
diff --git a/tempest/tests/cmd/test_workspace.py b/tempest/tests/cmd/test_workspace.py
index 65481de..b4f6c5f 100644
--- a/tempest/tests/cmd/test_workspace.py
+++ b/tempest/tests/cmd/test_workspace.py
@@ -133,12 +133,89 @@
"None or empty name is specified."
" Please specify correct name for workspace.\n")
+ def test_workspace_manager_rename_with_existing_name(self):
+ new_name = self.name
+ with patch('sys.stdout', new_callable=StringIO) as mock_stdout:
+ ex = self.assertRaises(SystemExit,
+ self.workspace_manager.rename_workspace,
+ self.name, new_name)
+ self.assertEqual(1, ex.code)
+ self.assertEqual(mock_stdout.getvalue(),
+ "A workspace already exists with name: %s.\n"
+ % new_name)
+
+ def test_workspace_manager_rename_no_exist_old_name(self):
+ old_name = ""
+ new_name = data_utils.rand_uuid()
+ with patch('sys.stdout', new_callable=StringIO) as mock_stdout:
+ ex = self.assertRaises(SystemExit,
+ self.workspace_manager.rename_workspace,
+ old_name, new_name)
+ self.assertEqual(1, ex.code)
+ self.assertEqual(mock_stdout.getvalue(),
+ "A workspace was not found with name: %s\n"
+ % old_name)
+
+ def test_workspace_manager_rename_integer_data(self):
+ old_name = self.name
+ new_name = 12345
+ self.workspace_manager.rename_workspace(old_name, new_name)
+ self.assertIsNone(self.workspace_manager.get_workspace(old_name))
+ self.assertIsNotNone(self.workspace_manager.get_workspace(new_name))
+
+ def test_workspace_manager_rename_alphanumeric_data(self):
+ old_name = self.name
+ new_name = 'abc123'
+ self.workspace_manager.rename_workspace(old_name, new_name)
+ self.assertIsNone(self.workspace_manager.get_workspace(old_name))
+ self.assertIsNotNone(self.workspace_manager.get_workspace(new_name))
+
def test_workspace_manager_move(self):
new_path = tempfile.mkdtemp()
self.addCleanup(shutil.rmtree, new_path, ignore_errors=True)
self.workspace_manager.move_workspace(self.name, new_path)
self.assertEqual(
self.workspace_manager.get_workspace(self.name), new_path)
+ # NOTE(mbindlish): Also checking for the workspace that it
+ # shouldn't exist in old path
+ self.assertNotEqual(
+ self.workspace_manager.get_workspace(self.name), self.path)
+
+ def test_workspace_manager_move_wrong_path(self):
+ new_path = 'wrong/path'
+ with patch('sys.stdout', new_callable=StringIO) as mock_stdout:
+ ex = self.assertRaises(SystemExit,
+ self.workspace_manager.move_workspace,
+ self.name, new_path)
+ self.assertEqual(1, ex.code)
+ self.assertEqual(mock_stdout.getvalue(),
+ "Path does not exist.\n")
+
+ def test_workspace_manager_move_wrong_workspace(self):
+ workspace_name = "wrong_workspace_name"
+ new_path = tempfile.mkdtemp()
+ self.addCleanup(shutil.rmtree, new_path, ignore_errors=True)
+ with patch('sys.stdout', new_callable=StringIO) as mock_stdout:
+ ex = self.assertRaises(SystemExit,
+ self.workspace_manager.move_workspace,
+ workspace_name, new_path)
+ self.assertEqual(1, ex.code)
+ self.assertEqual(mock_stdout.getvalue(),
+ "A workspace was not found with name: %s\n"
+ % workspace_name)
+
+ def test_workspace_manager_move_no_workspace_name(self):
+ workspace_name = ""
+ new_path = tempfile.mkdtemp()
+ self.addCleanup(shutil.rmtree, new_path, ignore_errors=True)
+ with patch('sys.stdout', new_callable=StringIO) as mock_stdout:
+ ex = self.assertRaises(SystemExit,
+ self.workspace_manager.move_workspace,
+ workspace_name, new_path)
+ self.assertEqual(1, ex.code)
+ self.assertEqual(mock_stdout.getvalue(),
+ "A workspace was not found with name: %s\n"
+ % workspace_name)
def test_workspace_manager_move_no_workspace_path(self):
new_path = ""
@@ -155,6 +232,30 @@
self.workspace_manager.remove_workspace_entry(self.name)
self.assertIsNone(self.workspace_manager.get_workspace(self.name))
+ def test_workspace_manager_remove_entry_no_name(self):
+ no_name = ""
+ with patch('sys.stdout', new_callable=StringIO) as mock_stdout:
+ ex = self.assertRaises(SystemExit,
+ self.workspace_manager.
+ remove_workspace_entry,
+ no_name)
+ self.assertEqual(1, ex.code)
+ self.assertEqual(mock_stdout.getvalue(),
+ "A workspace was not found with name: %s\n"
+ % no_name)
+
+ def test_workspace_manager_remove_entry_wrong_name(self):
+ wrong_name = "wrong_name"
+ with patch('sys.stdout', new_callable=StringIO) as mock_stdout:
+ ex = self.assertRaises(SystemExit,
+ self.workspace_manager.
+ remove_workspace_entry,
+ wrong_name)
+ self.assertEqual(1, ex.code)
+ self.assertEqual(mock_stdout.getvalue(),
+ "A workspace was not found with name: %s\n"
+ % wrong_name)
+
def test_workspace_manager_remove_directory(self):
path = self.workspace_manager.remove_workspace_entry(self.name)
self.workspace_manager.remove_workspace_directory(path)
@@ -188,8 +289,11 @@
nonexistent_name)
self.assertEqual(1, ex.code)
self.assertEqual(mock_stdout.getvalue(),
- "A workspace was not found with name: %s\n" %
- nonexistent_name)
+ "A workspace was not found with name: %s\n"
+ % nonexistent_name)
+
+ def test_workspace_name_exists(self):
+ self.assertIsNone(self.workspace_manager._name_exists(self.name))
def test_workspace_name_already_exists(self):
duplicate_name = self.name
@@ -203,6 +307,11 @@
"A workspace already exists with name: %s.\n"
% duplicate_name)
+ def test_workspace_name_exists_check_new_name(self):
+ new_name = "fake_name"
+ self.assertIsNone(self.workspace_manager.
+ _workspace_name_exists(new_name))
+
def test_workspace_manager_path_not_exist(self):
fake_path = "fake_path"
with patch('sys.stdout', new_callable=StringIO) as mock_stdout:
@@ -213,6 +322,11 @@
self.assertEqual(mock_stdout.getvalue(),
"Path does not exist.\n")
+ def test_validate_path_exists(self):
+ new_path = self.path
+ self.assertIsNone(self.workspace_manager.
+ _validate_path(new_path))
+
def test_workspace_manager_list_workspaces(self):
listed = self.workspace_manager.list_workspaces()
self.assertEqual(1, len(listed))
@@ -242,3 +356,21 @@
self.assertEqual(mock_stdout.getvalue(),
"None or empty path is specified for workspace."
" Please specify correct workspace path.\n")
+
+ def test_register_new_workspace_integer_data(self):
+ workspace_name = 12345
+ self.workspace_manager.register_new_workspace(
+ workspace_name, self.path)
+ self.assertIsNotNone(
+ self.workspace_manager.get_workspace(workspace_name))
+ self.assertEqual(
+ self.workspace_manager.get_workspace(workspace_name), self.path)
+
+ def test_register_new_workspace_alphanumeric_data(self):
+ workspace_name = 'abc123'
+ self.workspace_manager.register_new_workspace(
+ workspace_name, self.path)
+ self.assertIsNotNone(
+ self.workspace_manager.get_workspace(workspace_name))
+ self.assertEqual(
+ self.workspace_manager.get_workspace(workspace_name), self.path)