Merge "[Negative] Extend volume over quota limit"
diff --git a/.zuul.yaml b/.zuul.yaml
index f061b12..9af79a6 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -326,22 +326,26 @@
- ^tempest/hacking/.*$
- ^tempest/tests/.*$
required-projects:
+ - git.openstack.org/openstack/airship-tempest-plugin
- git.openstack.org/openstack/almanach
- git.openstack.org/openstack/aodh
- git.openstack.org/openstack/barbican-tempest-plugin
+ - git.openstack.org/openstack/blazar-tempest-plugin
- git.openstack.org/openstack/ceilometer
- - git.openstack.org/openstack/cinder
- - git.openstack.org/openstack/congress
+ - git.openstack.org/openstack/cinder-tempest-plugin
+ - git.openstack.org/openstack/cloudkitty-tempest-plugin
+ - git.openstack.org/openstack/congress-tempest-plugin
- git.openstack.org/openstack/designate-tempest-plugin
- - git.openstack.org/openstack/ec2-api
+ - git.openstack.org/openstack/ec2api-tempest-plugin
- git.openstack.org/openstack/freezer
- git.openstack.org/openstack/freezer-api
- git.openstack.org/openstack/freezer-tempest-plugin
+ - git.openstack.org/openstack/gabbi-tempest
- git.openstack.org/openstack/gce-api
- git.openstack.org/openstack/glare
- - git.openstack.org/openstack/heat
+ - git.openstack.org/openstack/heat-tempest-plugin
- git.openstack.org/openstack/intel-nfv-ci-tests
- - git.openstack.org/openstack/ironic
+ - git.openstack.org/openstack/ironic-tempest-plugin
- git.openstack.org/openstack/ironic-inspector
- git.openstack.org/openstack/keystone-tempest-plugin
- git.openstack.org/openstack/kingbird
@@ -350,19 +354,21 @@
- git.openstack.org/openstack/magnum-tempest-plugin
- git.openstack.org/openstack/manila
- git.openstack.org/openstack/manila-tempest-plugin
- - git.openstack.org/openstack/mistral
+ - git.openstack.org/openstack/mistral-tempest-plugin
- git.openstack.org/openstack/mogan
- git.openstack.org/openstack/monasca-api
- git.openstack.org/openstack/monasca-log-api
- - git.openstack.org/openstack/murano
+ - git.openstack.org/openstack/monasca-tempest-plugin
+ - git.openstack.org/openstack/murano-tempest-plugin
+ - git.openstack.org/openstack/networking-ansible
- git.openstack.org/openstack/networking-bgpvpn
- git.openstack.org/openstack/networking-cisco
- git.openstack.org/openstack/networking-fortinet
- git.openstack.org/openstack/networking-generic-switch
- - git.openstack.org/openstack/networking-l2gw
+ - git.openstack.org/openstack/networking-l2gw-tempest-plugin
- git.openstack.org/openstack/networking-midonet
- - git.openstack.org/openstack/networking-plumgrid
- git.openstack.org/openstack/networking-sfc
+ - git.openstack.org/openstack/networking-spp
- git.openstack.org/openstack/neutron
- git.openstack.org/openstack/neutron-dynamic-routing
- git.openstack.org/openstack/neutron-fwaas
@@ -371,21 +377,25 @@
- git.openstack.org/openstack/neutron-vpnaas
- git.openstack.org/openstack/nova-lxd
- git.openstack.org/openstack/novajoin-tempest-plugin
+ - git.openstack.org/openstack/octavia
- git.openstack.org/openstack/octavia-tempest-plugin
- git.openstack.org/openstack/oswin-tempest-plugin
- git.openstack.org/openstack/panko
- git.openstack.org/openstack/patrole
+ - git.openstack.org/openstack/python-watcherclient
- git.openstack.org/openstack/qinling
- git.openstack.org/openstack/requirements
- git.openstack.org/openstack/sahara-tests
- git.openstack.org/openstack/senlin
- git.openstack.org/openstack/senlin-tempest-plugin
- git.openstack.org/openstack/tap-as-a-service
+ - git.openstack.org/openstack/telemetry-tempest-plugin
- git.openstack.org/openstack/tempest-horizon
- - git.openstack.org/openstack/trio2o
- - git.openstack.org/openstack/trove
+ - git.openstack.org/openstack/tobiko
+ - git.openstack.org/openstack/tripleo-common-tempest-plugin
+ - git.openstack.org/openstack/trove-tempest-plugin
- git.openstack.org/openstack/valet
- - git.openstack.org/openstack/vitrage
+ - git.openstack.org/openstack/vitrage-tempest-plugin
- git.openstack.org/openstack/vmware-nsx-tempest-plugin
- git.openstack.org/openstack/watcher-tempest-plugin
- git.openstack.org/openstack/zaqar-tempest-plugin
@@ -499,7 +509,17 @@
irrelevant-files: *tempest-irrelevant-files
- tempest-multinode-full:
irrelevant-files: *tempest-irrelevant-files
- - tempest-tox-plugin-sanity-check
+ - tempest-tox-plugin-sanity-check:
+ irrelevant-files:
+ - ^(test-|)requirements.txt$
+ - ^.*\.rst$
+ - ^doc/.*$
+ - ^etc/.*$
+ - ^releasenotes/.*$
+ - ^setup.cfg$
+ - ^tempest/hacking/.*$
+ - ^tempest/tests/.*$
+ # tools/ is not here since this relies on a script in tools/.
- tempest-slow:
irrelevant-files: *tempest-irrelevant-files
- nova-cells-v1:
diff --git a/HACKING.rst b/HACKING.rst
index f2b800a..eb6551a 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -6,7 +6,7 @@
- Step 2: Read on
Tempest Specific Commandments
-------------------------------
+-----------------------------
- [T102] Cannot import OpenStack python clients in tempest/api &
tempest/scenario tests
@@ -35,6 +35,30 @@
- Clean up test data at the completion of each test
- Use configuration files for values that will vary by environment
+Supported OpenStack Components
+------------------------------
+
+Tempest's :ref:`library` and :ref:`plugin interface <tempest_plugin>` can be
+leveraged to support integration testing for virtually any OpenStack component.
+
+However, Tempest only offers **in-tree** integration testing coverage for the
+following components:
+
+* Cinder
+* Glance
+* Keystone
+* Neutron
+* Nova
+* Swift
+
+Historically, Tempest offered in-tree testing for other components as well, but
+since the introduction of the `External Plugin Interface`_, Tempest's in-tree
+testing scope has been limited to the projects above. Integration tests for
+projects not included above should go into one of the
+`relevant plugin projects`_.
+
+.. _External Plugin Interface: https://specs.openstack.org/openstack/qa-specs/specs/tempest/implemented/tempest-external-plugin-interface.html
+.. _relevant plugin projects: https://docs.openstack.org/tempest/latest/plugin-registry.html#detected-plugins
Exception Handling
------------------
diff --git a/doc/source/data/tempest-plugins-registry.header b/doc/source/data/tempest-plugins-registry.header
index 0de12b7..831d8a6 100644
--- a/doc/source/data/tempest-plugins-registry.header
+++ b/doc/source/data/tempest-plugins-registry.header
@@ -3,9 +3,9 @@
job. You should edit the files data/tempest-plugins-registry.footer
and data/tempest-plugins-registry.header instead of this one.
-==========================
- Tempest Plugin Registry
-==========================
+=======================
+Tempest Plugin Registry
+=======================
Since we've created the external plugin mechanism, it's gotten used by
a lot of projects. The following is a list of plugins that currently
diff --git a/releasenotes/notes/add-immutable-user-source-support-dd17772a997075e0.yaml b/releasenotes/notes/add-immutable-user-source-support-dd17772a997075e0.yaml
new file mode 100644
index 0000000..931d689
--- /dev/null
+++ b/releasenotes/notes/add-immutable-user-source-support-dd17772a997075e0.yaml
@@ -0,0 +1,11 @@
+---
+features:
+ - |
+ Add a new config setting ``immutable_user_source`` in the
+ ``[identity-feature-enabled]`` group that defaults to false.
+ This setting, combined with the usage of the ``@testtools.skipIf()``
+ decorator, will allow tests that require user creation, deletion,
+ or modification to skip instead of failing in environments that
+ are LDAP-backed. In such environments, the user source is read-only,
+ so this feature flag is needed to allow such tests to gracefully skip
+ without having to blacklist them.
diff --git a/releasenotes/notes/bug-1799883-6ea95fc64f70c9ef.yaml b/releasenotes/notes/bug-1799883-6ea95fc64f70c9ef.yaml
new file mode 100644
index 0000000..630908f
--- /dev/null
+++ b/releasenotes/notes/bug-1799883-6ea95fc64f70c9ef.yaml
@@ -0,0 +1,7 @@
+---
+fixes:
+ - |
+ Fixed bug #1799883. ``tempest workspace register`` and ``tempest workspace move`` CLI
+ will now validate the value of the ``--path`` CLI argument and raise an exception if
+ it is None or empty string. Earlier both CLI actions were accepting None or empty path
+ which was confusing.
diff --git a/setup.cfg b/setup.cfg
index 96ee7ea..fcbe956 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -4,7 +4,7 @@
description-file =
README.rst
author = OpenStack
-author-email = openstack-dev@lists.openstack.org
+author-email = openstack-discuss@lists.openstack.org
home-page = https://docs.openstack.org/tempest/latest/
classifier =
Intended Audience :: Information Technology
diff --git a/tempest/api/compute/admin/test_volume_swap.py b/tempest/api/compute/admin/test_volume_swap.py
index a853182..6b58939 100644
--- a/tempest/api/compute/admin/test_volume_swap.py
+++ b/tempest/api/compute/admin/test_volume_swap.py
@@ -70,6 +70,7 @@
"""The test suite for swapping of volume with admin user.
The following is the scenario outline:
+
1. Create a volume "volume1" with non-admin.
2. Create a volume "volume2" with non-admin.
3. Boot an instance "instance1" with non-admin.
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 4e2b59b..09dd409 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -477,7 +477,7 @@
"""Create a volume and wait for it to become 'available'.
:param image_ref: Specify an image id to create a bootable volume.
- :**kwargs: other parameters to create volume.
+ :param kwargs: other parameters to create volume.
:returns: The available volume.
"""
if 'size' not in kwargs:
diff --git a/tempest/api/compute/servers/test_attach_interfaces.py b/tempest/api/compute/servers/test_attach_interfaces.py
index 6434161..05c2a28 100644
--- a/tempest/api/compute/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/servers/test_attach_interfaces.py
@@ -169,7 +169,9 @@
iface = self.interfaces_client.create_interface(
server['id'], net_id=network_id,
fixed_ips=fixed_ips)['interfaceAttachment']
- self.addCleanup(self.ports_client.delete_port, iface['port_id'])
+ self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+ self.ports_client.delete_port,
+ iface['port_id'])
self._check_interface(iface, server_id=server['id'],
fixed_ip=ip_list[0])
return iface
@@ -261,16 +263,6 @@
interface_count = len(ifs)
self.assertGreater(interface_count, 0)
- try:
- iface = self._test_create_interface(server)
- except lib_exc.BadRequest as e:
- msg = ('Multiple possible networks found, use a Network ID to be '
- 'more specific.')
- if not CONF.compute.fixed_network_name and six.text_type(e) == msg:
- raise
- else:
- ifs.append(iface)
-
iface = self._test_create_interface_by_fixed_ips(server, ifs)
ifs.append(iface)
diff --git a/tempest/api/identity/admin/v2/test_services.py b/tempest/api/identity/admin/v2/test_services.py
index e2ed5ef..03543ac 100644
--- a/tempest/api/identity/admin/v2/test_services.py
+++ b/tempest/api/identity/admin/v2/test_services.py
@@ -89,14 +89,10 @@
service = self.services_client.create_service(
name=name, type=s_type,
description=description)['OS-KSADM:service']
+ self.addCleanup(self.services_client.delete_service, service['id'])
services.append(service)
service_ids = [svc['id'] for svc in services]
- def delete_services():
- for service_id in service_ids:
- self.services_client.delete_service(service_id)
-
- self.addCleanup(delete_services)
# List and Verify Services
body = self.services_client.list_services()['OS-KSADM:services']
found = [serv for serv in body if serv['id'] in service_ids]
diff --git a/tempest/api/identity/admin/v2/test_tenants.py b/tempest/api/identity/admin/v2/test_tenants.py
index cda721c..f68754e 100644
--- a/tempest/api/identity/admin/v2/test_tenants.py
+++ b/tempest/api/identity/admin/v2/test_tenants.py
@@ -50,7 +50,7 @@
'been sent in response for create')
body = self.tenants_client.show_tenant(tenant_id)['tenant']
desc2 = body['description']
- self.assertEqual(desc2, tenant_desc, 'Description does not appear'
+ self.assertEqual(desc2, tenant_desc, 'Description does not appear '
'to be set')
self.tenants_client.delete_tenant(tenant_id)
diff --git a/tempest/api/identity/admin/v3/test_projects.py b/tempest/api/identity/admin/v3/test_projects.py
index 6ddf42e..f75edaa 100644
--- a/tempest/api/identity/admin/v3/test_projects.py
+++ b/tempest/api/identity/admin/v3/test_projects.py
@@ -31,7 +31,7 @@
'been sent in response for create')
body = self.projects_client.show_project(project_id)['project']
desc2 = body['description']
- self.assertEqual(desc2, project_desc, 'Description does not appear'
+ self.assertEqual(desc2, project_desc, 'Description does not appear '
'to be set')
@decorators.idempotent_id('5f50fe07-8166-430b-a882-3b2ee0abe26f')
diff --git a/tempest/api/identity/admin/v3/test_users.py b/tempest/api/identity/admin/v3/test_users.py
index 3813568..8955a93 100644
--- a/tempest/api/identity/admin/v3/test_users.py
+++ b/tempest/api/identity/admin/v3/test_users.py
@@ -28,6 +28,14 @@
class UsersV3TestJSON(base.BaseIdentityV3AdminTest):
+ @classmethod
+ def skip_checks(cls):
+ super(UsersV3TestJSON, cls).skip_checks()
+ if CONF.identity_feature_enabled.immutable_user_source:
+ raise cls.skipException('Skipped because environment has an '
+ 'immutable user source and solely '
+ 'provides read-only access to users.')
+
@decorators.idempotent_id('b537d090-afb9-4519-b95d-270b0708e87e')
def test_user_update(self):
# Test case to check if updating of user attributes is successful.
diff --git a/tempest/api/identity/v2/test_ec2_credentials.py b/tempest/api/identity/v2/test_ec2_credentials.py
index 237e728..9981ef8 100644
--- a/tempest/api/identity/v2/test_ec2_credentials.py
+++ b/tempest/api/identity/v2/test_ec2_credentials.py
@@ -57,18 +57,19 @@
self.creds.user_id,
tenant_id=self.creds.tenant_id)["credential"]
created_creds.append(creds1['access'])
+ self.addCleanup(
+ self.non_admin_users_client.delete_user_ec2_credential,
+ self.creds.user_id, creds1['access'])
+
# create second ec2 credentials
creds2 = self.non_admin_users_client.create_user_ec2_credential(
self.creds.user_id,
tenant_id=self.creds.tenant_id)["credential"]
created_creds.append(creds2['access'])
- # add credentials to be cleaned up
- self.addCleanup(
- self.non_admin_users_client.delete_user_ec2_credential,
- self.creds.user_id, creds1['access'])
self.addCleanup(
self.non_admin_users_client.delete_user_ec2_credential,
self.creds.user_id, creds2['access'])
+
# get the list of user ec2 credentials
resp = self.non_admin_users_client.list_user_ec2_credentials(
self.creds.user_id)["credentials"]
diff --git a/tempest/api/network/admin/test_agent_management.py b/tempest/api/network/admin/test_agent_management.py
index 30ed176..eaf477c 100644
--- a/tempest/api/network/admin/test_agent_management.py
+++ b/tempest/api/network/admin/test_agent_management.py
@@ -48,11 +48,6 @@
agent.pop('configurations', None)
self.assertIn(self.agent, agents)
- @decorators.idempotent_id('e335be47-b9a1-46fd-be30-0874c0b751e6')
- def test_list_agents_non_admin(self):
- body = self.agents_client.list_agents()
- self.assertEmpty(body["agents"])
-
@decorators.idempotent_id('869bc8e8-0fda-4a30-9b71-f8a7cf58ca9f')
def test_show_agent(self):
body = self.admin_agents_client.show_agent(self.agent['id'])
@@ -95,4 +90,4 @@
non_existent_id = data_utils.rand_uuid()
self.assertRaises(
lib_exc.NotFound,
- self.agents_client.delete_agent, non_existent_id)
+ self.admin_agents_client.delete_agent, non_existent_id)
diff --git a/tempest/api/network/test_agent_management_negative.py b/tempest/api/network/test_agent_management_negative.py
new file mode 100644
index 0000000..d1c02ce
--- /dev/null
+++ b/tempest/api/network/test_agent_management_negative.py
@@ -0,0 +1,28 @@
+# Copyright 2018 OpenStack Foundation
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.api.network import base
+from tempest.lib import decorators
+
+
+class AgentManagementNegativeTest(base.BaseNetworkTest):
+
+ @decorators.idempotent_id('e335be47-b9a1-46fd-be30-0874c0b751e6')
+ @decorators.attr(type=['negative'])
+ def test_list_agents_non_admin(self):
+ """Validate that non-admin user cannot list agents."""
+ # Listing agents requires admin_only permissions.
+ body = self.agents_client.list_agents()
+ self.assertEmpty(body["agents"])
diff --git a/tempest/api/network/test_dhcp_ipv6.py b/tempest/api/network/test_dhcp_ipv6.py
index 0730d58..399954c 100644
--- a/tempest/api/network/test_dhcp_ipv6.py
+++ b/tempest/api/network/test_dhcp_ipv6.py
@@ -135,7 +135,7 @@
real_ip, eui_ip = self._get_ips_from_subnet(**kwargs)
self._clean_network()
self.assertEqual(eui_ip, real_ip,
- ('Real port IP %s shall be equal to EUI-64 %s'
+ ('Real port IP %s shall be equal to EUI-64 %s '
'when ipv6_ra_mode=%s,ipv6_address_mode=%s') % (
real_ip, eui_ip,
ra_mode if ra_mode else "Off",
diff --git a/tempest/api/object_storage/test_container_quotas.py b/tempest/api/object_storage/test_container_quotas.py
index 982c4a1..fcd9a7c 100644
--- a/tempest/api/object_storage/test_container_quotas.py
+++ b/tempest/api/object_storage/test_container_quotas.py
@@ -31,9 +31,10 @@
Quotas are set by adding meta values to the container,
and are validated when set:
- - X-Container-Meta-Quota-Bytes:
+
+ - X-Container-Meta-Quota-Bytes:
Maximum size of the container, in bytes.
- - X-Container-Meta-Quota-Count:
+ - X-Container-Meta-Quota-Count:
Maximum object count of the container.
"""
super(ContainerQuotasTest, self).setUp()
diff --git a/tempest/cmd/cleanup.py b/tempest/cmd/cleanup.py
index 29abd49..2f54f9a 100644
--- a/tempest/cmd/cleanup.py
+++ b/tempest/cmd/cleanup.py
@@ -279,7 +279,7 @@
self.admin_id,
self.admin_role_id)
except Exception as ex:
- LOG.exception("Failed removing role from project which still"
+ LOG.exception("Failed removing role from project which still "
"exists, exception: %s", ex)
def _project_exists(self, project_id):
diff --git a/tempest/cmd/run.py b/tempest/cmd/run.py
index 84c6d9a..3e84b82 100644
--- a/tempest/cmd/run.py
+++ b/tempest/cmd/run.py
@@ -243,8 +243,8 @@
parser.add_argument('--load-list', '--load_list',
help='Path to a non-regex whitelist file, '
'this file contains a separate test '
- 'on each newline. This command'
- 'supports files created by the tempest'
+ 'on each newline. This command '
+ 'supports files created by the tempest '
'run ``--list-tests`` command')
# list only args
parser.add_argument('--list-tests', '-l', action='store_true',
diff --git a/tempest/cmd/workspace.py b/tempest/cmd/workspace.py
index d276bde..d0c4b28 100644
--- a/tempest/cmd/workspace.py
+++ b/tempest/cmd/workspace.py
@@ -94,7 +94,7 @@
@lockutils.synchronized('workspaces', external=True)
def move_workspace(self, name, path):
self._populate()
- path = os.path.abspath(os.path.expanduser(path))
+ path = os.path.abspath(os.path.expanduser(path)) if path else path
self._name_exists(name)
self._validate_path(path)
self.workspaces[name] = path
@@ -115,6 +115,7 @@
@lockutils.synchronized('workspaces', external=True)
def remove_workspace_directory(self, workspace_path):
+ self._validate_path(workspace_path)
shutil.rmtree(workspace_path)
@lockutils.synchronized('workspaces', external=True)
@@ -136,6 +137,10 @@
sys.exit(1)
def _validate_path(self, path):
+ if not path:
+ print("None or empty path is specified for workspace."
+ " Please specify correct workspace path.")
+ sys.exit(1)
if not os.path.exists(path):
print("Path does not exist.")
sys.exit(1)
@@ -144,7 +149,7 @@
def register_new_workspace(self, name, path, init=False):
"""Adds the new workspace and writes out the new workspace config"""
self._populate()
- path = os.path.abspath(os.path.expanduser(path))
+ path = os.path.abspath(os.path.expanduser(path)) if path else path
# This only happens when register is called from outside of init
if not init:
self._validate_path(path)
diff --git a/tempest/common/compute.py b/tempest/common/compute.py
index e218d5a..375113d 100644
--- a/tempest/common/compute.py
+++ b/tempest/common/compute.py
@@ -78,23 +78,22 @@
:param wait_until: Server status to wait for the server to reach after
its creation.
:param volume_backed: Whether the server is volume backed or not.
- If this is true, a volume will be created and
- create server will be requested with
- 'block_device_mapping_v2' populated with below
- values:
- --------------------------------------------
- bd_map_v2 = [{
- 'uuid': volume['volume']['id'],
- 'source_type': 'volume',
- 'destination_type': 'volume',
- 'boot_index': 0,
- 'delete_on_termination': True}]
- kwargs['block_device_mapping_v2'] = bd_map_v2
- ---------------------------------------------
- If server needs to be booted from volume with other
- combination of bdm inputs than mentioned above, then
- pass the bdm inputs explicitly as kwargs and image_id
- as empty string ('').
+ If this is true, a volume will be created and create server will be
+ requested with 'block_device_mapping_v2' populated with below values:
+
+ .. code-block:: python
+
+ bd_map_v2 = [{
+ 'uuid': volume['volume']['id'],
+ 'source_type': 'volume',
+ 'destination_type': 'volume',
+ 'boot_index': 0,
+ 'delete_on_termination': True}]
+ kwargs['block_device_mapping_v2'] = bd_map_v2
+
+ If server needs to be booted from volume with other combination of bdm
+ inputs than mentioned above, then pass the bdm inputs explicitly as
+ kwargs and image_id as empty string ('').
:param name: Name of the server to be provisioned. If not defined a random
string ending with '-instance' will be generated.
:param flavor: Flavor of the server to be provisioned. If not defined,
diff --git a/tempest/common/identity.py b/tempest/common/identity.py
index eaf651b..525110b 100644
--- a/tempest/common/identity.py
+++ b/tempest/common/identity.py
@@ -64,7 +64,8 @@
should not be used for testing identity features.
:param clients: a client manager.
- :return
+ :return: v2 or v3 of CredsClient
+ :rtype: V2CredsClient or V3CredsClient
"""
if CONF.identity.auth_version == 'v2':
client = clients.identity_client
diff --git a/tempest/config.py b/tempest/config.py
index 6c6ff58..f490e03 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -170,11 +170,22 @@
cfg.IntOpt('user_lockout_failure_attempts',
default=2,
help="The number of unsuccessful login attempts the user is "
- "allowed before having the account locked."),
+ "allowed before having the account locked. This only "
+ "takes effect when identity-feature-enabled."
+ "security_compliance is set to 'True'. For more details, "
+ "refer to keystone config options keystone.conf:"
+ "security_compliance.lockout_failure_attempts. "
+ "This feature is disabled by default in keystone."),
cfg.IntOpt('user_lockout_duration',
default=5,
help="The number of seconds a user account will remain "
- "locked."),
+ "locked. This only takes "
+ "effect when identity-feature-enabled.security_compliance "
+ "is set to 'True'. For more details, refer to "
+ "keystone config options "
+ "keystone.conf:security_compliance.lockout_duration. "
+ "Setting this option will have no effect unless you also "
+ "set identity.user_lockout_failure_attempts."),
cfg.IntOpt('user_unique_last_password_count',
default=2,
help="The number of passwords for a user that must be unique "
@@ -251,7 +262,13 @@
cfg.BoolOpt('application_credentials',
default=False,
help='Does the environment have application credentials '
- 'enabled?')
+ 'enabled?'),
+ cfg.BoolOpt('immutable_user_source',
+ default=False,
+ help='Set to True if the environment has a read-only '
+ 'user source. This will skip all tests that attempt to '
+ 'create, delete, or modify users. This should not be set '
+ 'to True if using dynamic credentials')
]
compute_group = cfg.OptGroup(name='compute',
diff --git a/tempest/lib/auth.py b/tempest/lib/auth.py
index 2dd9d00..8e6d3d5 100644
--- a/tempest/lib/auth.py
+++ b/tempest/lib/auth.py
@@ -324,7 +324,7 @@
pass
if expiry is None:
raise ValueError(
- "time data '{data}' does not match any of the"
+ "time data '{data}' does not match any of the "
"expected formats: {formats}".format(
data=expiry_string, formats=self.EXPIRY_DATE_FORMATS))
return expiry
diff --git a/tempest/lib/common/fixed_network.py b/tempest/lib/common/fixed_network.py
index 875a79d..926c3a4 100644
--- a/tempest/lib/common/fixed_network.py
+++ b/tempest/lib/common/fixed_network.py
@@ -24,7 +24,7 @@
"""Get a full network dict from just a network name
:param str name: the name of the network to use
- :param NetworksClient compute_networks_client: The network client
+ :param network.NetworksClient compute_networks_client: The network client
object to use for making the network lists api request
:return: The full dictionary for the network in question
:rtype: dict
diff --git a/tempest/lib/common/utils/data_utils.py b/tempest/lib/common/utils/data_utils.py
index c5df590..438d73e 100644
--- a/tempest/lib/common/utils/data_utils.py
+++ b/tempest/lib/common/utils/data_utils.py
@@ -65,9 +65,9 @@
:param int length: The length of password that you expect to set
(If it's smaller than 3, it's same as 3.)
:return: a random password. The format is
- '<random upper letter>-<random number>-<random special character>
- -<random ascii letters or digit characters or special symbols>'
- (e.g. 'G2*ac8&lKFFgh%2')
+ ``'<random upper letter>-<random number>-<random special character>
+ -<random ascii letters or digit characters or special symbols>'``
+ (e.g. ``G2*ac8&lKFFgh%2``)
:rtype: string
"""
upper = random.choice(string.ascii_uppercase)
diff --git a/tempest/lib/services/volume/v1/types_client.py b/tempest/lib/services/volume/v1/types_client.py
index 58a80b7..da9eb8b 100644
--- a/tempest/lib/services/volume/v1/types_client.py
+++ b/tempest/lib/services/volume/v1/types_client.py
@@ -149,10 +149,11 @@
extra_specs):
"""Update a volume_type extra spec.
- volume_type_id: Id of volume_type.
- extra_spec_name: Name of the extra spec to be updated.
- extra_spec: A dictionary of with key as extra_spec_name and the
- updated value.
+ :param volume_type_id: Id of volume_type.
+ :param extra_spec_name: Name of the extra spec to be updated.
+ :param extra_specs: A dictionary of with key as extra_spec_name and the
+ updated value.
+
For a full list of available parameters, please refer to the official
API reference:
https://developer.openstack.org/api-ref/block-storage/v2/#update-extra-specs-for-a-volume-type
diff --git a/tempest/lib/services/volume/v3/types_client.py b/tempest/lib/services/volume/v3/types_client.py
index 13ecd15..1405785 100644
--- a/tempest/lib/services/volume/v3/types_client.py
+++ b/tempest/lib/services/volume/v3/types_client.py
@@ -153,6 +153,7 @@
:param extra_spec_name: Name of the extra spec to be updated.
:param extra_specs: A dictionary of with key as extra_spec_name and the
updated value.
+
For a full list of available parameters, please refer to the official
API reference:
https://developer.openstack.org/api-ref/block-storage/v3/index.html#update-extra-specification-for-volume-type
diff --git a/tempest/lib/services/volume/v3/volumes_client.py b/tempest/lib/services/volume/v3/volumes_client.py
index 11c5767..fec2950 100644
--- a/tempest/lib/services/volume/v3/volumes_client.py
+++ b/tempest/lib/services/volume/v3/volumes_client.py
@@ -182,7 +182,7 @@
:param id: A checked resource id
:raises lib_exc.DeleteErrorException: If the specified resource is on
- the status the delete was failed.
+ the status the delete was failed.
"""
try:
volume = self.show_volume(id)
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 00d45cd..dbb9acc 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -378,12 +378,12 @@
server=None):
"""Get a SSH client to a remote server
- @param ip_address the server floating or fixed IP address to use
- for ssh validation
- @param username name of the Linux account on the remote server
- @param private_key the SSH private key to use
- @param server: server dict, used for debugging purposes
- @return a RemoteClient object
+ :param ip_address: the server floating or fixed IP address to use
+ for ssh validation
+ :param username: name of the Linux account on the remote server
+ :param private_key: the SSH private key to use
+ :param server: server dict, used for debugging purposes
+ :return: a RemoteClient object
"""
if username is None:
diff --git a/tempest/scenario/test_encrypted_cinder_volumes.py b/tempest/scenario/test_encrypted_cinder_volumes.py
index 8c210d5..008d1ae 100644
--- a/tempest/scenario/test_encrypted_cinder_volumes.py
+++ b/tempest/scenario/test_encrypted_cinder_volumes.py
@@ -29,11 +29,12 @@
For both LUKS and cryptsetup encryption types, this test performs
the following:
- * Creates an image in Glance
- * Boots an instance from the image
- * Creates an encryption type (as admin)
- * Creates a volume of that encryption type (as a regular user)
- * Attaches and detaches the encrypted volume to the instance
+
+ * Creates an image in Glance
+ * Boots an instance from the image
+ * Creates an encryption type (as admin)
+ * Creates a volume of that encryption type (as a regular user)
+ * Attaches and detaches the encrypted volume to the instance
"""
@classmethod
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index c1132cf..c11070c 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -374,39 +374,37 @@
def test_network_basic_ops(self):
"""Basic network operation test
- For a freshly-booted VM with an IP address ("port") on a given
- network:
+ For a freshly-booted VM with an IP address ("port") on a given network:
- the Tempest host can ping the IP address. This implies, but
- does not guarantee (see the ssh check that follows), that the
- VM has been assigned the correct IP address and has
- connectivity to the Tempest host.
+ does not guarantee (see the ssh check that follows), that the
+ VM has been assigned the correct IP address and has
+ connectivity to the Tempest host.
- the Tempest host can perform key-based authentication to an
- ssh server hosted at the IP address. This check guarantees
- that the IP address is associated with the target VM.
+ ssh server hosted at the IP address. This check guarantees
+ that the IP address is associated with the target VM.
- the Tempest host can ssh into the VM via the IP address and
- successfully execute the following:
+ successfully execute the following:
- - ping an external IP address, implying external connectivity.
+ - ping an external IP address, implying external connectivity.
- - ping an external hostname, implying that dns is correctly
- configured.
+ - ping an external hostname, implying that dns is correctly
+ configured.
- - ping an internal IP address, implying connectivity to another
- VM on the same network.
+ - ping an internal IP address, implying connectivity to another
+ VM on the same network.
- detach the floating-ip from the VM and verify that it becomes
- unreachable
+ unreachable
- associate detached floating ip to a new VM and verify connectivity.
- VMs are created with unique keypair so connectivity also asserts that
- floating IP is associated with the new VM instead of the old one
+ VMs are created with unique keypair so connectivity also asserts
+ that floating IP is associated with the new VM instead of the old
+ one
Verifies that floating IP status is updated correctly after each change
-
-
"""
self._setup_network_and_servers()
self._check_public_network_connectivity(should_connect=True)
@@ -445,30 +443,25 @@
def test_connectivity_between_vms_on_different_networks(self):
"""Test connectivity between VMs on different networks
- For a freshly-booted VM with an IP address ("port") on a given
- network:
+ For a freshly-booted VM with an IP address ("port") on a given network:
- the Tempest host can ping the IP address.
-
- the Tempest host can ssh into the VM via the IP address and
- successfully execute the following:
+ successfully execute the following:
- - ping an external IP address, implying external connectivity.
-
- - ping an external hostname, implying that dns is correctly
- configured.
-
- - ping an internal IP address, implying connectivity to another
- VM on the same network.
+ - ping an external IP address, implying external connectivity.
+ - ping an external hostname, implying that dns is correctly
+ configured.
+ - ping an internal IP address, implying connectivity to another
+ VM on the same network.
- Create another network on the same tenant with subnet, create
- an VM on the new network.
+ an VM on the new network.
- - Ping the new VM from previous VM failed since the new network
- was not attached to router yet.
-
- - Attach the new network to the router, Ping the new VM from
- previous VM succeed.
+ - Ping the new VM from previous VM failed since the new network
+ was not attached to router yet.
+ - Attach the new network to the router, Ping the new VM from
+ previous VM succeed.
"""
self._setup_network_and_servers()
@@ -476,9 +469,14 @@
self._check_network_internal_connectivity(network=self.network)
self._check_network_external_connectivity()
self._create_new_network(create_gateway=True)
- self._create_server(self.new_net)
- self._check_network_internal_connectivity(network=self.new_net,
- should_connect=False)
+ new_server = self._create_server(self.new_net)
+ new_server_ips = [addr['addr'] for addr in
+ new_server['addresses'][self.new_net['name']]]
+
+ # Assert that pinging the new VM fails since the new network is not
+ # connected to a router
+ self._check_server_connectivity(self.floating_ip_tuple.floating_ip,
+ new_server_ips, should_connect=False)
router_id = self.router['id']
self.routers_client.add_router_interface(
router_id, subnet_id=self.new_subnet['id'])
@@ -486,8 +484,9 @@
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
self.routers_client.remove_router_interface,
router_id, subnet_id=self.new_subnet['id'])
- self._check_network_internal_connectivity(network=self.new_net,
- should_connect=True)
+
+ self._check_server_connectivity(self.floating_ip_tuple.floating_ip,
+ new_server_ips, should_connect=True)
@decorators.idempotent_id('c5adff73-e961-41f1-b4a9-343614f18cfa')
@testtools.skipUnless(CONF.compute_feature_enabled.interface_attach,
@@ -555,24 +554,25 @@
def test_subnet_details(self):
"""Tests that subnet's extra configuration details are affecting VMs.
- This test relies on non-shared, isolated tenant networks.
+ This test relies on non-shared, isolated tenant networks.
- NOTE: Neutron subnets push data to servers via dhcp-agent, so any
- update in subnet requires server to actively renew its DHCP lease.
+ NOTE: Neutron subnets push data to servers via dhcp-agent, so any
+ update in subnet requires server to actively renew its DHCP lease.
- 1. Configure subnet with dns nameserver
- 2. retrieve the VM's configured dns and verify it matches the one
- configured for the subnet.
- 3. update subnet's dns
- 4. retrieve the VM's configured dns and verify it matches the new one
- configured for the subnet.
+ 1. Configure subnet with dns nameserver
+ 2. retrieve the VM's configured dns and verify it matches the one
+ configured for the subnet.
+ 3. update subnet's dns
+ 4. retrieve the VM's configured dns and verify it matches the new one
+ configured for the subnet.
- TODO(yfried): add host_routes
+ TODO(yfried): add host_routes
- any resolution check would be testing either:
- * l3 forwarding (tested in test_network_basic_ops)
- * Name resolution of an external DNS nameserver - out of scope for
- Tempest
+ any resolution check would be testing either:
+
+ * l3 forwarding (tested in test_network_basic_ops)
+ * Name resolution of an external DNS nameserver - out of scope for
+ Tempest
"""
# this test check only updates (no actual resolution) so using
# arbitrary ip addresses as nameservers, instead of parsing CONF
@@ -742,7 +742,7 @@
2. Remove router from all l3-agents
3. Verify connectivity is down
4. Assign router to new l3-agent (or old one if no new agent is
- available)
+ available)
5. Verify connectivity
"""
@@ -823,7 +823,8 @@
prevents traffic to pass through the VM. Anti-spoof rules are not
required in cases where the VM routes traffic through it.
- The test steps are :
+ The test steps are:
+
1. Create a new network.
2. Connect (hotplug) the VM to a new network.
3. Check the VM can ping a server on the new network ("peer")
@@ -832,7 +833,7 @@
spoofed interface (VM cannot ping the peer).
6. Disable port-security of the spoofed port- set the flag to false.
7. Retest 3rd step and check that the Security Group allows pings via
- the spoofed interface.
+ the spoofed interface.
"""
spoof_mac = "00:00:00:00:00:01"
diff --git a/tempest/scenario/test_object_storage_basic_ops.py b/tempest/scenario/test_object_storage_basic_ops.py
index cbe321e..b635ca0 100644
--- a/tempest/scenario/test_object_storage_basic_ops.py
+++ b/tempest/scenario/test_object_storage_basic_ops.py
@@ -24,15 +24,15 @@
def test_swift_basic_ops(self):
"""Test swift basic ops.
- * get swift stat.
- * create container.
- * upload a file to the created container.
- * list container's objects and assure that the uploaded file is
- present.
- * download the object and check the content
- * delete object from container.
- * list container's objects and assure that the deleted file is gone.
- * delete a container.
+ * get swift stat.
+ * create container.
+ * upload a file to the created container.
+ * list container's objects and assure that the uploaded file is
+ present.
+ * download the object and check the content
+ * delete object from container.
+ * list container's objects and assure that the deleted file is gone.
+ * delete a container.
"""
self.get_swift_stat()
container_name = self.create_container()
diff --git a/tempest/scenario/test_security_groups_basic_ops.py b/tempest/scenario/test_security_groups_basic_ops.py
index 28a2d64..2b7926a 100644
--- a/tempest/scenario/test_security_groups_basic_ops.py
+++ b/tempest/scenario/test_security_groups_basic_ops.py
@@ -63,28 +63,28 @@
a. a security group open to incoming ssh connection
b. a VM with a floating ip
5. create a general empty security group (same as "default", but
- without rules allowing in-tenant traffic)
+ without rules allowing in-tenant traffic)
tests:
1. _verify_network_details
2. _verify_mac_addr: for each access point verify that
- (subnet, fix_ip, mac address) are as defined in the port list
+ (subnet, fix_ip, mac address) are as defined in the port list
3. _test_in_tenant_block: test that in-tenant traffic is disabled
- without rules allowing it
+ without rules allowing it
4. _test_in_tenant_allow: test that in-tenant traffic is enabled
- once an appropriate rule has been created
+ once an appropriate rule has been created
5. _test_cross_tenant_block: test that cross-tenant traffic is disabled
- without a rule allowing it on destination tenant
+ without a rule allowing it on destination tenant
6. _test_cross_tenant_allow:
* test that cross-tenant traffic is enabled once an appropriate
- rule has been created on destination tenant.
+ rule has been created on destination tenant.
* test that reverse traffic is still blocked
* test than reverse traffic is enabled once an appropriate rule has
- been created on source tenant
- 7._test_port_update_new_security_group:
- * test that traffic is blocked with default security group
- * test that traffic is enabled after updating port with new security
- group having appropriate rule
+ been created on source tenant
+ 7. _test_port_update_new_security_group:
+ * test that traffic is blocked with default security group
+ * test that traffic is enabled after updating port with new
+ security group having appropriate rule
8. _test_multiple_security_groups: test multiple security groups can be
associated with the vm
@@ -93,11 +93,13 @@
2. Public network is defined and reachable from the Tempest host
3. Public router can either be:
* defined, in which case all tenants networks can connect directly
- to it, and cross tenant check will be done on the private IP of the
- destination tenant
+ to it, and cross tenant check will be done on the private IP of
+ the destination tenant
+
or
+
* not defined (empty string), in which case each tenant will have
- its own router connected to the public network
+ its own router connected to the public network
"""
credentials = ['primary', 'alt', 'admin']
diff --git a/tempest/test.py b/tempest/test.py
index f2babbb..c3c58dc 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -259,6 +259,7 @@
based on the result of an API call are discouraged.
The following checks are implemented in `test.py` already:
+
- check that alt credentials are available when requested by the test
- check that admin credentials are available when requested by the test
- check that the identity version specified by the test is marked as
@@ -310,6 +311,7 @@
`os_[type]`:
Valid values in `credentials` are:
+
- 'primary':
A normal user is provisioned.
It can be used only once. Multiple entries will be ignored.
@@ -581,7 +583,7 @@
def setUp(self):
super(BaseTestCase, self).setUp()
if not self.__setupclass_called:
- raise RuntimeError("setUpClass does not calls the super's"
+ raise RuntimeError("setUpClass does not calls the super's "
"setUpClass in the " +
self.__class__.__name__)
at_exit_set.add(self.__class__)
diff --git a/tempest/tests/cmd/test_workspace.py b/tempest/tests/cmd/test_workspace.py
index a256368..65481de 100644
--- a/tempest/tests/cmd/test_workspace.py
+++ b/tempest/tests/cmd/test_workspace.py
@@ -140,6 +140,17 @@
self.assertEqual(
self.workspace_manager.get_workspace(self.name), new_path)
+ def test_workspace_manager_move_no_workspace_path(self):
+ new_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(),
+ "None or empty path is specified for workspace."
+ " Please specify correct workspace path.\n")
+
def test_workspace_manager_remove_entry(self):
self.workspace_manager.remove_workspace_entry(self.name)
self.assertIsNone(self.workspace_manager.get_workspace(self.name))
@@ -149,6 +160,18 @@
self.workspace_manager.remove_workspace_directory(path)
self.assertIsNone(self.workspace_manager.get_workspace(self.name))
+ def test_workspace_manager_remove_directory_no_path(self):
+ no_path = ""
+ with patch('sys.stdout', new_callable=StringIO) as mock_stdout:
+ ex = self.assertRaises(SystemExit,
+ self.workspace_manager.
+ remove_workspace_directory,
+ no_path)
+ self.assertEqual(1, ex.code)
+ self.assertEqual(mock_stdout.getvalue(),
+ "None or empty path is specified for workspace."
+ " Please specify correct workspace path.\n")
+
def test_path_expansion(self):
name = data_utils.rand_uuid()
path = os.path.join("~", name)
@@ -207,3 +230,15 @@
self.assertEqual(mock_stdout.getvalue(),
"None or empty name is specified."
" Please specify correct name for workspace.\n")
+
+ def test_register_new_workspace_no_path(self):
+ no_path = ""
+ with patch('sys.stdout', new_callable=StringIO) as mock_stdout:
+ ex = self.assertRaises(SystemExit,
+ self.workspace_manager.
+ register_new_workspace,
+ self.name, no_path)
+ self.assertEqual(1, ex.code)
+ self.assertEqual(mock_stdout.getvalue(),
+ "None or empty path is specified for workspace."
+ " Please specify correct workspace path.\n")
diff --git a/tempest/tests/files/setup.cfg b/tempest/tests/files/setup.cfg
index bd68708..a81d31e 100644
--- a/tempest/tests/files/setup.cfg
+++ b/tempest/tests/files/setup.cfg
@@ -3,7 +3,7 @@
version = 1
summary = Fake Project for testing wrapper scripts
author = OpenStack
-author-email = openstack-dev@lists.openstack.org
+author-email = openstack-discuss@lists.openstack.org
home-page = https://docs.openstack.org/tempest/latest/
classifier =
Intended Audience :: Information Technology
diff --git a/tools/generate-tempest-plugins-list.py b/tools/generate-tempest-plugins-list.py
index 4eb78fb..3772774 100644
--- a/tools/generate-tempest-plugins-list.py
+++ b/tools/generate-tempest-plugins-list.py
@@ -74,7 +74,8 @@
# Gerrit prepends 4 garbage octets to the JSON, in order to counter
# cross-site scripting attacks. Therefore we must discard it so the
# json library won't choke.
-projects = sorted(filter(is_in_openstack_namespace, json.loads(r.read()[4:])))
+content = r.read().decode('utf-8')[4:]
+projects = sorted(filter(is_in_openstack_namespace, json.loads(content)))
# Retrieve projects having no deb, puppet, ui or spec namespace as those
# namespaces do not contains tempest plugins.
diff --git a/tools/generate-tempest-plugins-list.sh b/tools/generate-tempest-plugins-list.sh
index b27b23a..111c9ce 100755
--- a/tools/generate-tempest-plugins-list.sh
+++ b/tools/generate-tempest-plugins-list.sh
@@ -41,8 +41,6 @@
set -ex
(
-declare -A plugins
-
if [[ -r doc/source/data/tempest-plugins-registry.header ]]; then
cat doc/source/data/tempest-plugins-registry.header
fi
diff --git a/tools/tempest-plugin-sanity.sh b/tools/tempest-plugin-sanity.sh
index 8b4f913..661329b 100644
--- a/tools/tempest-plugin-sanity.sh
+++ b/tools/tempest-plugin-sanity.sh
@@ -47,7 +47,7 @@
# retrieve a list of projects having tempest plugins
PROJECT_LIST="$(python tools/generate-tempest-plugins-list.py)"
# List of projects having tempest plugin stale or unmaintained from long time
-BLACKLIST="trio2o"
+BLACKLIST="networking-plumgrid,trio2o"
# Function to clone project using zuul-cloner or from git
function clone_project() {
@@ -105,8 +105,8 @@
# Function to run sanity check on each project
function plugin_sanity_check() {
- clone_project "$1" && install_project "$1" && tempest_sanity "$1" \
- && uninstall_project "$1" && "$TVENV" pip install .
+ clone_project "$1" && install_project "$1" && tempest_sanity "$1" \
+ && uninstall_project "$1" && "$TVENV" pip install .
}
# Log status
diff --git a/tox.ini b/tox.ini
index 4d3c622..4068054 100644
--- a/tox.ini
+++ b/tox.ini
@@ -48,6 +48,10 @@
coverage xml -o cover/coverage.xml
coverage report
+[testenv:debug]
+basepython = python3
+commands = oslo_debug_helper -t tempest/tests {posargs}
+
[testenv:all]
envdir = .tox/tempest
sitepackages = {[tempestenv]sitepackages}