Merge "Handle properly 404 responses from Neutron"
diff --git a/.gitreview b/.gitreview
index 84b5114..a475594 100644
--- a/.gitreview
+++ b/.gitreview
@@ -1,4 +1,4 @@
[gerrit]
-host=review.openstack.org
+host=review.opendev.org
port=29418
project=openstack/tempest.git
diff --git a/.zuul.yaml b/.zuul.yaml
index 7e3d15b..0d2005b 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -8,10 +8,10 @@
test setup. To run a multi-node test inherit from devstack-tempest and
set the nodeset to a multi-node one.
required-projects:
- - git.openstack.org/openstack/tempest
+ - opendev.org/openstack/tempest
timeout: 7200
roles:
- - zuul: git.openstack.org/openstack-dev/devstack
+ - zuul: opendev.org/openstack/devstack
vars:
devstack_services:
tempest: true
@@ -55,10 +55,10 @@
description: |
Base Tempest IPv6 job.
required-projects:
- - git.openstack.org/openstack/tempest
+ - opendev.org/openstack/tempest
timeout: 7200
roles:
- - zuul: git.openstack.org/openstack-dev/devstack
+ - zuul: opendev.org/openstack/devstack
vars:
devstack_services:
tempest: true
@@ -113,24 +113,24 @@
periodic-tempest-dsvm-oslo-latest-full-master.
timeout: 10800
required-projects:
- - git.openstack.org/openstack/oslo.cache
- - git.openstack.org/openstack/oslo.concurrency
- - git.openstack.org/openstack/oslo.config
- - git.openstack.org/openstack/oslo.context
- - git.openstack.org/openstack/oslo.db
- - git.openstack.org/openstack/oslo.i18n
- - git.openstack.org/openstack/oslo.log
- - git.openstack.org/openstack/oslo.messaging
- - git.openstack.org/openstack/oslo.middleware
- - git.openstack.org/openstack/oslo.policy
- - git.openstack.org/openstack/oslo.privsep
- - git.openstack.org/openstack/oslo.reports
- - git.openstack.org/openstack/oslo.rootwrap
- - git.openstack.org/openstack/oslo.serialization
- - git.openstack.org/openstack/oslo.service
- - git.openstack.org/openstack/oslo.utils
- - git.openstack.org/openstack/oslo.versionedobjects
- - git.openstack.org/openstack/oslo.vmware
+ - opendev.org/openstack/oslo.cache
+ - opendev.org/openstack/oslo.concurrency
+ - opendev.org/openstack/oslo.config
+ - opendev.org/openstack/oslo.context
+ - opendev.org/openstack/oslo.db
+ - opendev.org/openstack/oslo.i18n
+ - opendev.org/openstack/oslo.log
+ - opendev.org/openstack/oslo.messaging
+ - opendev.org/openstack/oslo.middleware
+ - opendev.org/openstack/oslo.policy
+ - opendev.org/openstack/oslo.privsep
+ - opendev.org/openstack/oslo.reports
+ - opendev.org/openstack/oslo.rootwrap
+ - opendev.org/openstack/oslo.serialization
+ - opendev.org/openstack/oslo.service
+ - opendev.org/openstack/oslo.utils
+ - opendev.org/openstack/oslo.versionedobjects
+ - opendev.org/openstack/oslo.vmware
- job:
name: tempest-full-parallel
@@ -354,82 +354,82 @@
- ^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-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/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-tempest-plugin
- - git.openstack.org/openstack/intel-nfv-ci-tests
- - 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
- - git.openstack.org/openstack/kuryr-tempest-plugin
- - git.openstack.org/openstack/magnum
- - git.openstack.org/openstack/magnum-tempest-plugin
- - git.openstack.org/openstack/manila
- - git.openstack.org/openstack/manila-tempest-plugin
- - 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/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-tempest-plugin
- - git.openstack.org/openstack/networking-midonet
- - 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
- - git.openstack.org/openstack/neutron-lbaas
- - git.openstack.org/openstack/neutron-tempest-plugin
- - 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/solum-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/tobiko
- - git.openstack.org/openstack/trio2o
- - 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-tempest-plugin
- - git.openstack.org/openstack/vmware-nsx-tempest-plugin
- - git.openstack.org/openstack/watcher-tempest-plugin
- - git.openstack.org/openstack/zaqar-tempest-plugin
- - git.openstack.org/openstack/zun-tempest-plugin
+ - opendev.org/airship/tempest-plugin
+ - opendev.org/x/almanach
+ - opendev.org/openstack/aodh
+ - opendev.org/openstack/barbican-tempest-plugin
+ - opendev.org/openstack/blazar-tempest-plugin
+ - opendev.org/openstack/ceilometer
+ - opendev.org/openstack/cinder-tempest-plugin
+ - opendev.org/openstack/cloudkitty-tempest-plugin
+ - opendev.org/openstack/congress-tempest-plugin
+ - opendev.org/openstack/cyborg-tempest-plugin
+ - opendev.org/openstack/designate-tempest-plugin
+ - opendev.org/openstack/ec2api-tempest-plugin
+ - opendev.org/openstack/freezer
+ - opendev.org/openstack/freezer-api
+ - opendev.org/openstack/freezer-tempest-plugin
+ - opendev.org/x/gabbi-tempest
+ - opendev.org/x/gce-api
+ - opendev.org/x/glare
+ - opendev.org/openstack/heat-tempest-plugin
+ - opendev.org/x/intel-nfv-ci-tests
+ - opendev.org/openstack/ironic-tempest-plugin
+ - opendev.org/openstack/ironic-inspector
+ - opendev.org/openstack/keystone-tempest-plugin
+ - opendev.org/x/kingbird
+ - opendev.org/openstack/kuryr-tempest-plugin
+ - opendev.org/openstack/magnum
+ - opendev.org/openstack/magnum-tempest-plugin
+ - opendev.org/openstack/manila
+ - opendev.org/openstack/manila-tempest-plugin
+ - opendev.org/openstack/mistral-tempest-plugin
+ - opendev.org/x/mogan
+ - opendev.org/openstack/monasca-api
+ - opendev.org/openstack/monasca-log-api
+ - opendev.org/openstack/monasca-tempest-plugin
+ - opendev.org/openstack/murano-tempest-plugin
+ - opendev.org/x/networking-ansible
+ - opendev.org/openstack/networking-bgpvpn
+ - opendev.org/x/networking-cisco
+ - opendev.org/x/networking-fortinet
+ - opendev.org/openstack/networking-generic-switch
+ - opendev.org/openstack/networking-l2gw-tempest-plugin
+ - opendev.org/openstack/networking-midonet
+ - opendev.org/openstack/networking-sfc
+ - opendev.org/x/networking-spp
+ - opendev.org/openstack/neutron
+ - opendev.org/openstack/neutron-dynamic-routing
+ - opendev.org/openstack/neutron-fwaas
+ - opendev.org/openstack/neutron-lbaas
+ - opendev.org/openstack/neutron-tempest-plugin
+ - opendev.org/openstack/neutron-vpnaas
+ - opendev.org/x/nova-lxd
+ - opendev.org/x/novajoin-tempest-plugin
+ - opendev.org/openstack/octavia-tempest-plugin
+ - opendev.org/openstack/oswin-tempest-plugin
+ - opendev.org/openstack/panko
+ - opendev.org/openstack/patrole
+ - opendev.org/openstack/python-watcherclient
+ - opendev.org/openstack/qinling
+ - opendev.org/openstack/requirements
+ - opendev.org/openstack/sahara-tests
+ - opendev.org/openstack/senlin
+ - opendev.org/openstack/senlin-tempest-plugin
+ - opendev.org/openstack/solum-tempest-plugin
+ - opendev.org/x/tap-as-a-service
+ - opendev.org/openstack/telemetry-tempest-plugin
+ - opendev.org/openstack/tempest-horizon
+ - opendev.org/x/tobiko
+ - opendev.org/x/trio2o
+ - opendev.org/openstack/tripleo-common-tempest-plugin
+ - opendev.org/openstack/trove-tempest-plugin
+ - opendev.org/x/valet
+ - opendev.org/openstack/vitrage-tempest-plugin
+ - opendev.org/x/vmware-nsx-tempest-plugin
+ - opendev.org/openstack/watcher-tempest-plugin
+ - opendev.org/openstack/zaqar-tempest-plugin
+ - opendev.org/openstack/zun-tempest-plugin
- job:
name: tempest-cinder-v2-api
@@ -634,7 +634,6 @@
- tempest-full-queens
- tempest-full-queens-py3
- tempest-full-pike
- - legacy-periodic-tempest-dsvm-neutron-full-ocata
periodic:
jobs:
- tempest-all
diff --git a/HACKING.rst b/HACKING.rst
index 1559fc6..204b3c7 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -457,7 +457,7 @@
by modifying Tempest's `lib installation script`_ for previous branches
(because DevStack is branched).
-.. _lib installation script: https://git.openstack.org/cgit/openstack-dev/devstack/tree/lib/tempest
+.. _lib installation script: https://opendev.org/openstack/devstack/src/branch/master/lib/tempest
2. Bug fix on core project needing Tempest changes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/README.rst b/README.rst
index 73930f1..e8206ee 100644
--- a/README.rst
+++ b/README.rst
@@ -61,7 +61,7 @@
#. You first need to install Tempest. This is done with pip after you check out
the Tempest repo::
- $ git clone https://git.openstack.org/openstack/tempest
+ $ git clone https://opendev.org/openstack/tempest
$ pip install tempest/
This can be done within a venv, but the assumption for this guide is that
diff --git a/REVIEWING.rst b/REVIEWING.rst
index 31fedce..498ce66 100644
--- a/REVIEWING.rst
+++ b/REVIEWING.rst
@@ -187,4 +187,4 @@
Note that such a policy should be used judiciously, as we should strive to
have two +2's on each patch set, prior to approval.
-.. _example: https://review.openstack.org/#/c/611032/
+.. _example: https://review.opendev.org/#/c/611032/
diff --git a/doc/source/plugin.rst b/doc/source/plugin.rst
index dc0e94c..a9e2059 100644
--- a/doc/source/plugin.rst
+++ b/doc/source/plugin.rst
@@ -43,7 +43,7 @@
In order to create the basic structure with base classes and test directories
you can use the tempest-plugin-cookiecutter project::
- > pip install -U cookiecutter && cookiecutter https://git.openstack.org/openstack/tempest-plugin-cookiecutter
+ > pip install -U cookiecutter && cookiecutter https://opendev.org/openstack/tempest-plugin-cookiecutter
Cloning into 'tempest-plugin-cookiecutter'...
remote: Counting objects: 17, done.
diff --git a/releasenotes/notes/add-migrate-volume-and-list-hosts-to-v3-volume-client-library-ad3529260db58f00.yaml b/releasenotes/notes/add-migrate-volume-and-list-hosts-to-v3-volume-client-library-ad3529260db58f00.yaml
new file mode 100644
index 0000000..ca6a78d
--- /dev/null
+++ b/releasenotes/notes/add-migrate-volume-and-list-hosts-to-v3-volume-client-library-ad3529260db58f00.yaml
@@ -0,0 +1,8 @@
+---
+features:
+ - |
+ Add list host API support to the volume v3 client library.
+ This feature enables callers to list all hosts for a given project.
+ - |
+ Add migrate volume API support to the volume v3 client library.
+ This features allows callers to migrate volumes between backends.
diff --git a/releasenotes/notes/add-unstable_test-decorator-a73cf97d4ffcc796.yaml b/releasenotes/notes/add-unstable_test-decorator-a73cf97d4ffcc796.yaml
new file mode 100644
index 0000000..2203fd1
--- /dev/null
+++ b/releasenotes/notes/add-unstable_test-decorator-a73cf97d4ffcc796.yaml
@@ -0,0 +1,11 @@
+---
+features:
+ - |
+ New decorator ``unstable_test`` is added to ``tempest.lib.decorators``.
+ It can be used to mark some test as unstable thus it will be still run
+ by tempest but job will not fail if this test will fail. Such test will
+ be skipped in case of failure.
+ It can be used for example when there is known bug related which cause
+ irregular tests failures. Marking such test as unstable will help other
+ developers to get their job done and still run this test to get additional
+ debug data or to confirm if some potential fix really solved the issue.
diff --git a/releasenotes/notes/correct-port-profile-config-option-d67f5cb31f1bc34c.yaml b/releasenotes/notes/correct-port-profile-config-option-d67f5cb31f1bc34c.yaml
index 7510d47..2830aa2 100644
--- a/releasenotes/notes/correct-port-profile-config-option-d67f5cb31f1bc34c.yaml
+++ b/releasenotes/notes/correct-port-profile-config-option-d67f5cb31f1bc34c.yaml
@@ -1,7 +1,7 @@
---
fixes:
- |
- Patch https://review.openstack.org/#/c/499575/ introduced
+ Patch https://review.opendev.org/#/c/499575/ introduced
support creating Neutron port with certain capabilities.
Currently capabilities list interpreted as string this change
fix it.
diff --git a/releasenotes/notes/deprecate-dns_servers-option-0xf2f297ee47a5ff.yaml b/releasenotes/notes/deprecate-dns_servers-option-0xf2f297ee47a5ff.yaml
new file mode 100644
index 0000000..30551cb
--- /dev/null
+++ b/releasenotes/notes/deprecate-dns_servers-option-0xf2f297ee47a5ff.yaml
@@ -0,0 +1,6 @@
+---
+deprecations:
+ - |
+ The config option ``CONF.network.dns_servers`` is no longer used
+ anywhere, so it is deprecated and will be removed in the future.
+
diff --git a/requirements.txt b/requirements.txt
index 7520d42..bf38fae 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -3,7 +3,7 @@
# process, which may cause wedges in the gate later.
pbr!=2.1.0,>=2.0.0 # Apache-2.0
cliff!=2.9.0,>=2.8.0 # Apache-2.0
-jsonschema<3.0.0,>=2.6.0 # MIT
+jsonschema>=2.6.0 # MIT
testtools>=2.2.0 # MIT
paramiko>=2.0.0 # LGPLv2.1+
netaddr>=0.7.18 # BSD
diff --git a/tempest/api/compute/admin/test_quotas.py b/tempest/api/compute/admin/test_quotas.py
index 12c7255..0060ffe 100644
--- a/tempest/api/compute/admin/test_quotas.py
+++ b/tempest/api/compute/admin/test_quotas.py
@@ -212,7 +212,7 @@
# 'danger' flag.
@decorators.idempotent_id('7932ab0f-5136-4075-b201-c0e2338df51a')
def test_update_default_quotas(self):
- LOG.debug("get the current 'default' quota class values")
+ # get the current 'default' quota class values
body = (self.adm_client.show_quota_class_set('default')
['quota_class_set'])
self.assertEqual('default', body.pop('id'))
@@ -224,9 +224,14 @@
# there is a real chance that we go from -1 (unlimited)
# to a very small number which causes issues.
body[quota] = default + 100
- LOG.debug("update limits for the default quota class set")
+ # update limits for the default quota class set
update_body = self.adm_client.update_quota_class_set(
'default', **body)['quota_class_set']
- LOG.debug("assert that the response has all of the changed values")
+ # assert that the response has all of the changed values
self.assertThat(update_body.items(),
matchers.ContainsAll(body.items()))
+ # check quota values are changed
+ show_body = self.adm_client.show_quota_class_set(
+ 'default')['quota_class_set']
+ self.assertThat(show_body.items(),
+ matchers.ContainsAll(body.items()))
diff --git a/tempest/api/compute/admin/test_volume_swap.py b/tempest/api/compute/admin/test_volume_swap.py
index cc83c04..371b506 100644
--- a/tempest/api/compute/admin/test_volume_swap.py
+++ b/tempest/api/compute/admin/test_volume_swap.py
@@ -142,6 +142,12 @@
if not CONF.compute_feature_enabled.volume_multiattach:
raise cls.skipException('Volume multi-attach is not available.')
+ @classmethod
+ def setup_clients(cls):
+ super(TestMultiAttachVolumeSwap, cls).setup_clients()
+ # Need this to set readonly volumes.
+ cls.admin_volumes_client = cls.os_admin.volumes_client_latest
+
# NOTE(mriedem): This is an uncommon scenario to call the compute API
# to swap volumes directly; swap volume is primarily only for volume
# live migration and retype callbacks from the volume service, and is slow
@@ -162,6 +168,13 @@
# volumes cleanup can happen successfully irrespective of which volume
# is attached to server.
volume1 = self.create_volume(multiattach=True)
+ # Make volume1 read-only since you can't swap from a volume with
+ # multiple read/write attachments, and you can't change the readonly
+ # flag on an in-use volume so we have to do this before attaching
+ # volume1 to anything. If the compute API ever supports per-attachment
+ # attach modes, then we can handle this differently.
+ self.admin_volumes_client.update_volume_readonly(
+ volume1['id'], readonly=True)
volume2 = self.create_volume(multiattach=True)
# Create two servers and wait for them to be ACTIVE.
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index 93bd817..f6c3e73 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -92,6 +92,7 @@
validatable=True,
validation_resources=validation_resources,
wait_until='ACTIVE')
+ self.addCleanup(self.delete_server, newserver['id'])
# The server's password should be set to the provided password
new_password = 'Newpass1234'
self.client.change_password(newserver['id'], adminPass=new_password)
diff --git a/tempest/api/compute/test_extensions.py b/tempest/api/compute/test_extensions.py
index 34faf5f..12e7fea 100644
--- a/tempest/api/compute/test_extensions.py
+++ b/tempest/api/compute/test_extensions.py
@@ -37,7 +37,7 @@
ext = CONF.compute_feature_enabled.api_extensions[0]
# Log extensions list
- extension_list = map(lambda x: x['alias'], extensions)
+ extension_list = [x['alias'] for x in extensions]
LOG.debug("Nova extensions: %s", ','.join(extension_list))
if ext == 'all':
diff --git a/tempest/api/identity/admin/v3/test_endpoint_groups.py b/tempest/api/identity/admin/v3/test_endpoint_groups.py
index 625568d..7d85dc9 100644
--- a/tempest/api/identity/admin/v3/test_endpoint_groups.py
+++ b/tempest/api/identity/admin/v3/test_endpoint_groups.py
@@ -69,6 +69,7 @@
@decorators.idempotent_id('7c69e7a1-f865-402d-a2ea-44493017315a')
def test_create_list_show_check_delete_endpoint_group(self):
service_id = self._create_service()
+ self.addCleanup(self.services_client.delete_service, service_id)
name = data_utils.rand_name('service_group')
description = data_utils.rand_name('description')
filters = {'service_id': service_id}
@@ -129,6 +130,7 @@
# Creating an endpoint group so as to check update endpoint group
# with new values
service1_id = self._create_service()
+ self.addCleanup(self.services_client.delete_service, service1_id)
name = data_utils.rand_name('service_group')
description = data_utils.rand_name('description')
filters = {'service_id': service1_id}
diff --git a/tempest/api/identity/admin/v3/test_roles.py b/tempest/api/identity/admin/v3/test_roles.py
index b67de95..5ba4c9f 100644
--- a/tempest/api/identity/admin/v3/test_roles.py
+++ b/tempest/api/identity/admin/v3/test_roles.py
@@ -25,6 +25,10 @@
class RolesV3TestJSON(base.BaseIdentityV3AdminTest):
+ # NOTE: force_tenant_isolation is true in the base class by default but
+ # overridden to false here to allow test execution for clouds using the
+ # pre-provisioned credentials provider.
+ force_tenant_isolation = False
@classmethod
def resource_setup(cls):
diff --git a/tempest/api/identity/v3/test_catalog.py b/tempest/api/identity/v3/test_catalog.py
index deec2dc..bc95f0d 100644
--- a/tempest/api/identity/v3/test_catalog.py
+++ b/tempest/api/identity/v3/test_catalog.py
@@ -22,8 +22,8 @@
@decorators.idempotent_id('56b57ced-22b8-4127-9b8a-565dfb0207e2')
def test_catalog_standardization(self):
- # http://git.openstack.org/cgit/openstack/service-types-authority
- # /tree/service-types.yaml
+ # https://opendev.org/openstack/service-types-authority
+ # /src/branch/master/service-types.yaml
standard_service_values = [{'name': 'keystone', 'type': 'identity'},
{'name': 'nova', 'type': 'compute'},
{'name': 'glance', 'type': 'image'},
diff --git a/tempest/api/volume/admin/test_volume_retype.py b/tempest/api/volume/admin/test_volume_retype.py
index 1c56eb2..9136139 100644
--- a/tempest/api/volume/admin/test_volume_retype.py
+++ b/tempest/api/volume/admin/test_volume_retype.py
@@ -36,7 +36,7 @@
# process is finished.
fetched_list = self.admin_volume_client.list_volumes(
params={'all_tenants': True,
- 'display_name': vol['name']})['volumes']
+ 'name': vol['name']})['volumes']
for fetched_vol in fetched_list:
if fetched_vol['id'] != vol['id']:
diff --git a/tempest/api/volume/test_volumes_backup.py b/tempest/api/volume/test_volumes_backup.py
index c178272..6ce5d3e 100644
--- a/tempest/api/volume/test_volumes_backup.py
+++ b/tempest/api/volume/test_volumes_backup.py
@@ -50,6 +50,7 @@
'available')
return restored_volume
+ @decorators.skip_because(bug="1483434")
@testtools.skipIf(CONF.volume.storage_protocol == 'ceph',
'ceph does not support arbitrary container names')
@decorators.idempotent_id('a66eb488-8ee1-47d4-8e9f-575a095728c6')
diff --git a/tempest/common/waiters.py b/tempest/common/waiters.py
index 0e86f05..77ec0f8 100644
--- a/tempest/common/waiters.py
+++ b/tempest/common/waiters.py
@@ -104,8 +104,8 @@
body = client.show_server(server_id)['server']
except lib_exc.NotFound:
return
- old_status = server_status = body['status']
- old_task_state = task_state = _get_task_state(body)
+ old_status = body['status']
+ old_task_state = _get_task_state(body)
start_time = int(time.time())
while True:
time.sleep(client.build_interval)
@@ -213,6 +213,31 @@
resource_name, resource_id, status, time.time() - start)
+def wait_for_volume_migration(client, volume_id, new_host):
+ """Waits for a Volume to move to a new host."""
+ body = client.show_volume(volume_id)['volume']
+ host = body['os-vol-host-attr:host']
+ migration_status = body['migration_status']
+ start = int(time.time())
+
+ # new_host is hostname@backend while current_host is hostname@backend#type
+ while migration_status != 'success' or new_host not in host:
+ time.sleep(client.build_interval)
+ body = client.show_volume(volume_id)['volume']
+ host = body['os-vol-host-attr:host']
+ migration_status = body['migration_status']
+
+ if migration_status == 'error':
+ message = ('volume %s failed to migrate.' % (volume_id))
+ raise lib_exc.TempestException(message)
+
+ if int(time.time()) - start >= client.build_timeout:
+ message = ('Volume %s failed to migrate to %s (current %s) '
+ 'within the required time (%s s).' %
+ (volume_id, new_host, host, client.build_timeout))
+ raise lib_exc.TimeoutException(message)
+
+
def wait_for_volume_retype(client, volume_id, new_volume_type):
"""Waits for a Volume to have a new volume type."""
body = client.show_volume(volume_id)['volume']
diff --git a/tempest/config.py b/tempest/config.py
index 24ae3ae..f692a4b 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -685,7 +685,10 @@
cfg.ListOpt('dns_servers',
default=["8.8.8.8", "8.8.4.4"],
help="List of dns servers which should be used"
- " for subnet creation"),
+ " for subnet creation",
+ deprecated_for_removal=True,
+ deprecated_reason="This config option is no longer "
+ "used anywhere, so it can be removed."),
cfg.StrOpt('port_vnic_type',
choices=[None, 'normal', 'direct', 'macvtap'],
help="vnic_type to use when launching instances"
diff --git a/tempest/lib/api_schema/response/compute/v2_1/volumes.py b/tempest/lib/api_schema/response/compute/v2_1/volumes.py
index c35dae9..d367f2a 100644
--- a/tempest/lib/api_schema/response/compute/v2_1/volumes.py
+++ b/tempest/lib/api_schema/response/compute/v2_1/volumes.py
@@ -50,7 +50,8 @@
# If it would come as empty array "[]" then,
# those elements can be defined as 'required'.
}
- }
+ },
+ 'os-vol-host-attr:host': {'type': 'string'},
},
'additionalProperties': False,
'required': ['id', 'status', 'displayName', 'availabilityZone',
diff --git a/tempest/lib/common/api_version_utils.py b/tempest/lib/common/api_version_utils.py
index 709c319..d29362d 100644
--- a/tempest/lib/common/api_version_utils.py
+++ b/tempest/lib/common/api_version_utils.py
@@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import six
import testtools
from tempest.lib.common import api_version_request
@@ -108,10 +109,12 @@
:param api_microversion_header_name: Microversion header name
Example- "X-OpenStack-Nova-API-Version"
- :param api_microversion: Microversion number like "2.10"
+ :param api_microversion: Microversion number like "2.10", type str.
:param response_header: Response header where microversion is
expected to be present.
"""
+ if not isinstance(api_microversion, six.string_types):
+ raise TypeError('api_microversion must be a string')
api_microversion_header_name = api_microversion_header_name.lower()
if (api_microversion_header_name not in response_header or
api_microversion != response_header[api_microversion_header_name]):
diff --git a/tempest/lib/decorators.py b/tempest/lib/decorators.py
index 4064401..808e0fb 100644
--- a/tempest/lib/decorators.py
+++ b/tempest/lib/decorators.py
@@ -154,3 +154,45 @@
return f
return decorator
+
+
+def unstable_test(*args, **kwargs):
+ """A decorator useful to run tests hitting known bugs and skip it if fails
+
+ This decorator can be used in cases like:
+
+ * We have skipped tests with some bug and now bug is claimed to be fixed.
+ Now we want to check the test stability so we use this decorator.
+ The number of skipped cases with that bug can be counted to mark test
+ stable again.
+ * There is test which is failing often, but not always. If there is known
+ bug related to it, and someone is working on fix, this decorator can be
+ used instead of "skip_because". That will ensure that test is still run
+ so new debug data can be collected from jobs' logs but it will not make
+ life of other developers harder by forcing them to recheck jobs more
+ often.
+
+ ``bug`` must be a number for the test to skip.
+
+ :param bug: bug number causing the test to skip (launchpad or storyboard)
+ :param bug_type: 'launchpad' or 'storyboard', default 'launchpad'
+ :raises: testtools.TestCase.skipException if test actually fails,
+ and ``bug`` is included
+ """
+ def decor(f):
+ @functools.wraps(f)
+ def inner(self, *func_args, **func_kwargs):
+ try:
+ return f(self, *func_args, **func_kwargs)
+ except Exception as e:
+ if "bug" in kwargs:
+ bug = kwargs['bug']
+ bug_type = kwargs.get('bug_type', 'launchpad')
+ bug_url = _get_bug_url(bug, bug_type)
+ msg = ("Marked as unstable and skipped because of bug: "
+ "%s, failure was: %s") % (bug_url, e)
+ raise testtools.TestCase.skipException(msg)
+ else:
+ raise e
+ return inner
+ return decor
diff --git a/tempest/lib/services/volume/v3/volumes_client.py b/tempest/lib/services/volume/v3/volumes_client.py
index fec2950..2dbdd11 100644
--- a/tempest/lib/services/volume/v3/volumes_client.py
+++ b/tempest/lib/services/volume/v3/volumes_client.py
@@ -35,6 +35,16 @@
return params
return urllib.urlencode(params)
+ def list_hosts(self):
+ """Lists all hosts summary info that is not disabled.
+
+ https://developer.openstack.org/api-ref/block-storage/v3/index.html#list-all-hosts-for-a-project
+ """
+ resp, body = self.get('os-hosts')
+ body = json.loads(body)
+ self.expected_success(200, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
def list_volumes(self, detail=False, params=None):
"""List all the volumes created.
@@ -55,6 +65,19 @@
self.expected_success(200, resp.status)
return rest_client.ResponseBody(resp, body)
+ def migrate_volume(self, volume_id, **kwargs):
+ """Migrate a volume to a new backend
+
+ For a full list of available parameters please refer to the offical
+ API reference:
+
+ https://developer.openstack.org/api-ref/block-storage/v3/index.html#migrate-a-volume
+ """
+ post_body = json.dumps({'os-migrate_volume': kwargs})
+ resp, body = self.post('volumes/%s/action' % volume_id, post_body)
+ self.expected_success(202, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
def show_volume(self, volume_id):
"""Returns the details of a single volume."""
url = "volumes/%s" % volume_id
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index d2fd021..86d37f1 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -324,11 +324,32 @@
snapshot['id'])['snapshot']
return snapshot
+ def _cleanup_volume_type(self, volume_type):
+ """Clean up a given volume type.
+
+ Ensuring all volumes associated to a type are first removed before
+ attempting to remove the type itself. This includes any image volume
+ cache volumes stored in a separate tenant to the original volumes
+ created from the type.
+ """
+ admin_volume_type_client = self.os_admin.volume_types_client_latest
+ admin_volumes_client = self.os_admin.volumes_client_latest
+ volumes = admin_volumes_client.list_volumes(
+ detail=True, params={'all_tenants': 1})['volumes']
+ type_name = volume_type['name']
+ for volume in [v for v in volumes if v['volume_type'] == type_name]:
+ test_utils.call_and_ignore_notfound_exc(
+ admin_volumes_client.delete_volume, volume['id'])
+ admin_volumes_client.wait_for_resource_deletion(volume['id'])
+ admin_volume_type_client.delete_volume_type(volume_type['id'])
+
def create_volume_type(self, client=None, name=None, backend_name=None):
if not client:
client = self.os_admin.volume_types_client_latest
- randomized_name = name or data_utils.rand_name(
- 'volume-type-' + self.__class__.__name__)
+ if not name:
+ class_name = self.__class__.__name__
+ name = data_utils.rand_name(class_name + '-volume-type')
+ randomized_name = data_utils.rand_name('scenario-type-' + name)
LOG.debug("Creating a volume type: %s on backend %s",
randomized_name, backend_name)
@@ -338,7 +359,7 @@
volume_type = client.create_volume_type(
name=randomized_name, extra_specs=extra_specs)['volume_type']
- self.addCleanup(client.delete_volume_type, volume_type['id'])
+ self.addCleanup(self._cleanup_volume_type, volume_type)
return volume_type
def _create_loginable_secgroup_rule(self, secgroup_id=None):
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index 7992585..f46c7e8 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -292,11 +292,14 @@
% CONF.network.build_timeout)
_, new_nic = self.diff_list[0]
- ssh_client.exec_command("sudo ip addr add %s/%s dev %s" % (
- new_port['fixed_ips'][0]['ip_address'],
- CONF.network.project_network_mask_bits,
- new_nic))
- ssh_client.exec_command("sudo ip link set %s up" % new_nic)
+ ip_output = ssh_client.exec_command('ip a')
+ ip_address = new_port['fixed_ips'][0]['ip_address']
+ ip_mask = CONF.network.project_network_mask_bits
+ # check if the address is not already in use, if not, set it
+ if ' ' + ip_address + '/' + str(ip_mask) not in ip_output:
+ ssh_client.exec_command("sudo ip addr add %s/%s dev %s" % (
+ ip_address, ip_mask, new_nic))
+ ssh_client.exec_command("sudo ip link set %s up" % new_nic)
def _get_server_nics(self, ssh_client):
reg = re.compile(r'(?P<num>\d+): (?P<nic_name>\w+)[@]?.*:')
diff --git a/tempest/scenario/test_volume_migrate_attached.py b/tempest/scenario/test_volume_migrate_attached.py
index c54bb38..106500e 100644
--- a/tempest/scenario/test_volume_migrate_attached.py
+++ b/tempest/scenario/test_volume_migrate_attached.py
@@ -33,6 +33,9 @@
* Write to the volume
* Perform a cinder retype --on-demand of the volume to type of backend #2
* Check written content of migrated volume
+ * Check the type of the volume has been updated.
+ * Check the volume is still in-use and the migration was successful.
+ * Check that the same volume is attached to the instance.
"""
credentials = ['primary', 'admin']
@@ -78,7 +81,8 @@
'src_backend': backend_source,
'dst': dest_body['name'],
'dst_backend': backend_dest})
- return source_body['name'], dest_body['name']
+ return ({'name': source_body['name'], 'host': backend_source},
+ {'name': dest_body['name'], 'host': backend_dest})
def _volume_retype_with_migration(self, volume_id, new_volume_type):
# NOTE: The 'on-demand' migration requires admin operation, so
@@ -93,7 +97,7 @@
@decorators.attr(type='slow')
@decorators.idempotent_id('deadd2c2-beef-4dce-98be-f86765ff311b')
@utils.services('compute', 'volume')
- def test_volume_migrate_attached(self):
+ def test_volume_retype_attached(self):
LOG.info("Creating keypair and security group")
keypair = self.create_keypair()
security_group = self._create_security_group()
@@ -104,11 +108,11 @@
# create an instance from volume
LOG.info("Booting instance from volume")
- volume_origin = self.create_volume(imageRef=CONF.compute.image_ref,
- volume_type=source_type)
+ volume_id = self.create_volume(imageRef=CONF.compute.image_ref,
+ volume_type=source_type['name'])['id']
- instance = self._boot_instance_from_volume(volume_origin['id'],
- keypair, security_group)
+ instance = self._boot_instance_from_volume(volume_id, keypair,
+ security_group)
# write content to volume on instance
LOG.info("Setting timestamp in instance %s", instance['id'])
@@ -118,9 +122,11 @@
server=instance)
# retype volume with migration from backend #1 to backend #2
- LOG.info("Retyping Volume %s to new type %s", volume_origin['id'],
- dest_type)
- self._volume_retype_with_migration(volume_origin['id'], dest_type)
+ LOG.info("Retyping Volume %s to new type %s", volume_id,
+ dest_type['name'])
+ # This method calls for the retype of the volume before calling a
+ # waiter that asserts that the volume type has changed successfully.
+ self._volume_retype_with_migration(volume_id, dest_type['name'])
# check the content of written file
LOG.info("Getting timestamp in postmigrated instance %s",
@@ -129,3 +135,82 @@
private_key=keypair['private_key'],
server=instance)
self.assertEqual(timestamp, timestamp2)
+
+ # Assert that the volume is on the new host, is still in-use and has a
+ # migration_status of success
+ volume = self.admin_volumes_client.show_volume(volume_id)['volume']
+ # dest_type is host@backend, os-vol-host-attr:host is host@backend#type
+ self.assertIn(dest_type['host'], volume['os-vol-host-attr:host'])
+ self.assertEqual('in-use', volume['status'])
+ self.assertEqual('success', volume['migration_status'])
+
+ # Assert that the same volume id is attached to the instance, ensuring
+ # the os-migrate_volume_completion Cinder API has been called.
+ attached_volumes = self.servers_client.list_volume_attachments(
+ instance['id'])['volumeAttachments']
+ self.assertEqual(volume_id, attached_volumes[0]['id'])
+
+ @decorators.attr(type='slow')
+ @decorators.idempotent_id('fe47b1ed-640e-4e3b-a090-200e25607362')
+ @utils.services('compute', 'volume')
+ def test_volume_migrate_attached(self):
+ LOG.info("Creating keypair and security group")
+ keypair = self.create_keypair()
+ security_group = self._create_security_group()
+
+ LOG.info("Creating volume")
+ # Create a unique volume type to avoid using the backend default
+ migratable_type = self.create_volume_type()['name']
+ volume_id = self.create_volume(imageRef=CONF.compute.image_ref,
+ volume_type=migratable_type)['id']
+ volume = self.admin_volumes_client.show_volume(volume_id)
+
+ LOG.info("Booting instance from volume")
+ instance = self._boot_instance_from_volume(volume_id, keypair,
+ security_group)
+
+ # Identify the source and destination hosts for the migration
+ src_host = volume['volume']['os-vol-host-attr:host']
+
+ # Select the first c-vol host that isn't hosting the volume as the dest
+ # host['host_name'] should take the format of host@backend.
+ # src_host should take the format of host@backend#type
+ hosts = self.admin_volumes_client.list_hosts()['hosts']
+ for host in hosts:
+ if (host['service'] == 'cinder-volume' and
+ not src_host.startswith(host['host_name'])):
+ dest_host = host['host_name']
+ break
+
+ ip_instance = self.get_server_ip(instance)
+ timestamp = self.create_timestamp(ip_instance,
+ private_key=keypair['private_key'],
+ server=instance)
+
+ LOG.info("Migrating Volume %s from host %s to host %s",
+ volume_id, src_host, dest_host)
+ self.admin_volumes_client.migrate_volume(volume_id, host=dest_host)
+
+ # This waiter asserts that the migration_status is success and that
+ # the volume has moved to the dest_host
+ waiters.wait_for_volume_migration(self.admin_volumes_client, volume_id,
+ dest_host)
+
+ # check the content of written file
+ LOG.info("Getting timestamp in postmigrated instance %s",
+ instance['id'])
+ timestamp2 = self.get_timestamp(ip_instance,
+ private_key=keypair['private_key'],
+ server=instance)
+ self.assertEqual(timestamp, timestamp2)
+
+ # Assert that the volume is in-use
+ volume = self.admin_volumes_client.show_volume(volume_id)['volume']
+ self.assertEqual('in-use', volume['status'])
+
+ # Assert that the same volume id is attached to the instance, ensuring
+ # the os-migrate_volume_completion Cinder API has been called
+ attached_volumes = self.servers_client.list_volume_attachments(
+ instance['id'])['volumeAttachments']
+ attached_volume_id = attached_volumes[0]['id']
+ self.assertEqual(volume_id, attached_volume_id)
diff --git a/tempest/tests/common/test_waiters.py b/tempest/tests/common/test_waiters.py
index 938d226..d56e8a4 100644
--- a/tempest/tests/common/test_waiters.py
+++ b/tempest/tests/common/test_waiters.py
@@ -148,3 +148,68 @@
list_interfaces.assert_has_calls([mock.call('server_id'),
mock.call('server_id')])
sleep.assert_called_once_with(client.build_interval)
+
+
+class TestVolumeWaiters(base.TestCase):
+ vol_migrating_src_host = {
+ 'volume': {'migration_status': 'migrating',
+ 'os-vol-host-attr:host': 'src_host@backend#type'}}
+ vol_migrating_dst_host = {
+ 'volume': {'migration_status': 'migrating',
+ 'os-vol-host-attr:host': 'dst_host@backend#type'}}
+ vol_migration_success = {
+ 'volume': {'migration_status': 'success',
+ 'os-vol-host-attr:host': 'dst_host@backend#type'}}
+ vol_migration_error = {
+ 'volume': {'migration_status': 'error',
+ 'os-vol-host-attr:host': 'src_host@backend#type'}}
+
+ def test_wait_for_volume_migration_timeout(self):
+ show_volume = mock.MagicMock(return_value=self.vol_migrating_src_host)
+ client = mock.Mock(spec=volumes_client.VolumesClient,
+ resource_type="volume",
+ build_interval=1,
+ build_timeout=1,
+ show_volume=show_volume)
+ self.patch('time.time', side_effect=[0., client.build_timeout + 1.])
+ self.patch('time.sleep')
+ self.assertRaises(lib_exc.TimeoutException,
+ waiters.wait_for_volume_migration,
+ client, mock.sentinel.volume_id, 'dst_host')
+
+ def test_wait_for_volume_migration_error(self):
+ show_volume = mock.MagicMock(side_effect=[
+ self.vol_migrating_src_host,
+ self.vol_migrating_src_host,
+ self.vol_migration_error])
+ client = mock.Mock(spec=volumes_client.VolumesClient,
+ resource_type="volume",
+ build_interval=1,
+ build_timeout=1,
+ show_volume=show_volume)
+ self.patch('time.time', return_value=0.)
+ self.patch('time.sleep')
+ self.assertRaises(lib_exc.TempestException,
+ waiters.wait_for_volume_migration,
+ client, mock.sentinel.volume_id, 'dst_host')
+
+ def test_wait_for_volume_migration_success_and_dst(self):
+ show_volume = mock.MagicMock(side_effect=[
+ self.vol_migrating_src_host,
+ self.vol_migrating_dst_host,
+ self.vol_migration_success])
+ client = mock.Mock(spec=volumes_client.VolumesClient,
+ resource_type="volume",
+ build_interval=1,
+ build_timeout=1,
+ show_volume=show_volume)
+ self.patch('time.time', return_value=0.)
+ self.patch('time.sleep')
+ waiters.wait_for_volume_migration(
+ client, mock.sentinel.volume_id, 'dst_host')
+
+ # Assert that we wait until migration_status is success and dst_host is
+ # part of the returned os-vol-host-attr:host.
+ show_volume.assert_has_calls([mock.call(mock.sentinel.volume_id),
+ mock.call(mock.sentinel.volume_id),
+ mock.call(mock.sentinel.volume_id)])
diff --git a/tempest/tests/lib/test_decorators.py b/tempest/tests/lib/test_decorators.py
index 3e6160e..9c6cac7 100644
--- a/tempest/tests/lib/test_decorators.py
+++ b/tempest/tests/lib/test_decorators.py
@@ -13,7 +13,10 @@
# License for the specific language governing permissions and limitations
# under the License.
+import abc
+
import mock
+import six
import testtools
from tempest.lib import base as test
@@ -66,9 +69,36 @@
condition=True)
-class TestSkipBecauseDecorator(base.TestCase):
- def _test_skip_because_helper(self, expected_to_skip=True,
- **decorator_args):
+@six.add_metaclass(abc.ABCMeta)
+class BaseSkipDecoratorTests(object):
+
+ @abc.abstractmethod
+ def _test_skip_helper(self, raise_exception=True, expected_to_skip=True,
+ **decorator_args):
+ return
+
+ def test_skip_launchpad_bug(self):
+ self._test_skip_helper(bug='12345')
+
+ def test_skip_storyboard_bug(self):
+ self._test_skip_helper(bug='1992', bug_type='storyboard')
+
+ def test_skip_bug_without_bug_never_skips(self):
+ """Never skip without a bug parameter."""
+ self._test_skip_helper(
+ raise_exception=False, expected_to_skip=False, condition=True)
+ self._test_skip_helper(
+ raise_exception=False, expected_to_skip=False)
+
+ def test_skip_invalid_bug_number(self):
+ """Raise InvalidParam if with an invalid bug number"""
+ self.assertRaises(lib_exc.InvalidParam, self._test_skip_helper,
+ bug='critical_bug')
+
+
+class TestSkipBecauseDecorator(base.TestCase, BaseSkipDecoratorTests):
+ def _test_skip_helper(self, raise_exception=True, expected_to_skip=True,
+ **decorator_args):
class TestFoo(test.BaseTestCase):
_interface = 'json'
@@ -90,38 +120,56 @@
# assert that test_bar returned 0
self.assertEqual(TestFoo('test_bar').test_bar(), 0)
- def test_skip_because_launchpad_bug(self):
- self._test_skip_because_helper(bug='12345')
-
def test_skip_because_launchpad_bug_and_condition_true(self):
- self._test_skip_because_helper(bug='12348', condition=True)
+ self._test_skip_helper(bug='12348', condition=True)
def test_skip_because_launchpad_bug_and_condition_false(self):
- self._test_skip_because_helper(expected_to_skip=False,
- bug='12349', condition=False)
-
- def test_skip_because_storyboard_bug(self):
- self._test_skip_because_helper(bug='1992', bug_type='storyboard')
-
- def test_skip_because_storyboard_bug_and_condition_true(self):
- self._test_skip_because_helper(bug='1992', bug_type='storyboard',
- condition=True)
+ self._test_skip_helper(expected_to_skip=False,
+ bug='12349', condition=False)
def test_skip_because_storyboard_bug_and_condition_false(self):
- self._test_skip_because_helper(expected_to_skip=False,
- bug='1992', bug_type='storyboard',
- condition=False)
+ self._test_skip_helper(expected_to_skip=False,
+ bug='1992', bug_type='storyboard',
+ condition=False)
- def test_skip_because_bug_without_bug_never_skips(self):
- """Never skip without a bug parameter."""
- self._test_skip_because_helper(expected_to_skip=False,
- condition=True)
- self._test_skip_because_helper(expected_to_skip=False)
+ def test_skip_because_storyboard_bug_and_condition_true(self):
+ self._test_skip_helper(bug='1992', bug_type='storyboard',
+ condition=True)
- def test_skip_because_invalid_bug_number(self):
- """Raise InvalidParam if with an invalid bug number"""
- self.assertRaises(lib_exc.InvalidParam, self._test_skip_because_helper,
- bug='critical_bug')
+
+class TestUnstableTestDecorator(base.TestCase, BaseSkipDecoratorTests):
+
+ def _test_skip_helper(self, raise_exception=True, expected_to_skip=True,
+ **decorator_args):
+ fail_test_reason = "test_bar failed"
+
+ class TestFoo(test.BaseTestCase):
+
+ @decorators.unstable_test(**decorator_args)
+ def test_bar(self):
+ if raise_exception:
+ raise Exception(fail_test_reason)
+ else:
+ return 0
+
+ t = TestFoo('test_bar')
+ if expected_to_skip:
+ e = self.assertRaises(testtools.TestCase.skipException, t.test_bar)
+ bug = decorator_args['bug']
+ bug_type = decorator_args.get('bug_type', 'launchpad')
+ self.assertRegex(
+ str(e),
+ r'Marked as unstable and skipped because of bug\: %s.*, '
+ 'failure was: %s' % (decorators._get_bug_url(bug, bug_type),
+ fail_test_reason)
+ )
+ else:
+ # assert that test_bar returned 0
+ self.assertEqual(TestFoo('test_bar').test_bar(), 0)
+
+ def test_skip_bug_given_exception_not_raised(self):
+ self._test_skip_helper(raise_exception=False, expected_to_skip=False,
+ bug='1234')
class TestIdempotentIdDecorator(base.TestCase):
diff --git a/tools/generate-tempest-plugins-list.py b/tools/generate-tempest-plugins-list.py
index 3772774..746cb34 100644
--- a/tools/generate-tempest-plugins-list.py
+++ b/tools/generate-tempest-plugins-list.py
@@ -19,9 +19,9 @@
#
# In order to function correctly, the environment in which the
# script runs must have
-# * network access to the review.openstack.org Gerrit API
+# * network access to the review.opendev.org Gerrit API
# working directory
-# * network access to https://git.openstack.org/cgit
+# * network access to https://opendev.org/openstack
import json
import re
@@ -36,7 +36,7 @@
from urllib2 import HTTPError
-url = 'https://review.openstack.org/projects/'
+url = 'https://review.opendev.org/projects/'
# This is what a project looks like
'''
@@ -59,7 +59,8 @@
def has_tempest_plugin(proj):
try:
r = urllib.urlopen(
- "https://git.openstack.org/cgit/%s/plain/setup.cfg" % proj)
+ "https://opendev.org/%s/raw/branch/"
+ "master/setup.cfg" % proj)
except HTTPError as err:
if err.code == 404:
return False
diff --git a/tools/generate-tempest-plugins-list.sh b/tools/generate-tempest-plugins-list.sh
index 17a4059..b4e5430 100755
--- a/tools/generate-tempest-plugins-list.sh
+++ b/tools/generate-tempest-plugins-list.sh
@@ -28,9 +28,9 @@
# * the environment variable git_dir pointing to the location
# * of said git repositories
# ) OR (
-# * network access to the review.openstack.org Gerrit API
+# * network access to the review.opendev.org Gerrit API
# working directory
-# * network access to https://git.openstack.org/cgit
+# * network access to https://opendev.org/openstack
# ))
#
# If a file named doc/source/data/tempest-plugins-registry.header or
@@ -69,8 +69,8 @@
i=0
for plugin in ${sorted_plugins}; do
i=$((i+1))
- giturl="https://git.openstack.org/openstack/${plugin}"
- gitlink="https://git.openstack.org/cgit/openstack/${plugin}"
+ giturl="https://opendev.org/openstack/${plugin}"
+ gitlink="https://opendev.org/openstack/${plugin}"
printf "%-3s %-${name_col_len}s %s\n" "$i" "${plugin}" "\`${giturl} <${gitlink}>\`__"
done
diff --git a/tools/tempest-plugin-sanity.sh b/tools/tempest-plugin-sanity.sh
index 703dce2..015b2b7 100644
--- a/tools/tempest-plugin-sanity.sh
+++ b/tools/tempest-plugin-sanity.sh
@@ -46,23 +46,23 @@
# List of projects having tempest plugin stale or unmaintained for a long time
# (6 months or more)
# TODO(masayukig): Some of these can be removed from BLACKLIST in the future.
-# airship-tempest-plugin: https://review.openstack.org/#/c/634387/
-# barbican-tempest-plugin: https://review.openstack.org/#/c/634631/
-# intel-nfv-ci-tests: https://review.openstack.org/#/c/634640/
-# networking-ansible: https://review.openstack.org/#/c/634647/
-# networking-generic-switch: https://review.openstack.org/#/c/634846/
-# networking-l2gw-tempest-plugin: https://review.openstack.org/#/c/635093/
-# networking-midonet: https://review.openstack.org/#/c/635096/
-# networking-plumgrid: https://review.openstack.org/#/c/635096/
-# networking-spp: https://review.openstack.org/#/c/635098/
-# neutron-dynamic-routing: https://review.openstack.org/#/c/637718/
-# neutron-vpnaas: https://review.openstack.org/#/c/637719/
-# nova-lxd: https://review.openstack.org/#/c/638334/
-# valet: https://review.openstack.org/#/c/638339/
-# vitrage-tempest-plugin: https://review.openstack.org/#/c/639003/
+# barbican-tempest-plugin: https://review.opendev.org/#/c/634631/
+# cyborg-tempest-plugin: https://review.opendev.org/659687
+# intel-nfv-ci-tests: https://review.opendev.org/#/c/634640/
+# networking-ansible: https://review.opendev.org/#/c/634647/
+# networking-generic-switch: https://review.opendev.org/#/c/634846/
+# networking-l2gw-tempest-plugin: https://review.opendev.org/#/c/635093/
+# networking-midonet: https://review.opendev.org/#/c/635096/
+# networking-plumgrid: https://review.opendev.org/#/c/635096/
+# networking-spp: https://review.opendev.org/#/c/635098/
+# neutron-dynamic-routing: https://review.opendev.org/#/c/637718/
+# neutron-vpnaas: https://review.opendev.org/#/c/637719/
+# nova-lxd: https://review.opendev.org/#/c/638334/
+# valet: https://review.opendev.org/#/c/638339/
+# vitrage-tempest-plugin: https://review.opendev.org/#/c/639003/
BLACKLIST="
-airship-tempest-plugin
barbican-tempest-plugin
+cyborg-tempest-plugin
intel-nfv-ci-tests
networking-ansible
networking-generic-switch
@@ -81,11 +81,11 @@
function clone_project() {
if [ -e /usr/zuul-env/bin/zuul-cloner ]; then
/usr/zuul-env/bin/zuul-cloner --cache-dir /opt/git \
- https://git.openstack.org \
+ https://opendev.org \
openstack/"$1"
elif [ -e /usr/bin/git ]; then
- /usr/bin/git clone https://git.openstack.org/openstack/"$1" \
+ /usr/bin/git clone https://opendev.org/openstack/"$1" \
openstack/"$1"
fi
@@ -94,7 +94,7 @@
# function to create virtualenv to perform sanity operation
function prepare_workspace() {
SANITY_DIR=$(pwd)
- virtualenv --clear "$SANITY_DIR"/.venv
+ virtualenv -p python3 --clear "$SANITY_DIR"/.venv
export TVENV="$SANITY_DIR/tools/with_venv.sh"
cd "$SANITY_DIR"
diff --git a/tox.ini b/tox.ini
index 230249f..48a2baa 100644
--- a/tox.ini
+++ b/tox.ini
@@ -9,7 +9,7 @@
VIRTUAL_ENV={envdir}
OS_TEST_PATH=./tempest/test_discover
deps =
- -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt}
+ -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
-r{toxinidir}/requirements.txt
[testenv]
@@ -25,7 +25,7 @@
install_command = pip install {opts} {packages}
whitelist_externals = *
deps =
- -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt}
+ -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
-r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
commands =
@@ -173,7 +173,7 @@
[testenv:venv]
deps =
- -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt}
+ -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
-r{toxinidir}/requirements.txt
-r{toxinidir}/doc/requirements.txt
commands = {posargs}
@@ -188,7 +188,7 @@
[testenv:docs]
basepython = python3
deps =
- -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt}
+ -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
-r{toxinidir}/requirements.txt
-r{toxinidir}/doc/requirements.txt
commands =
@@ -221,7 +221,7 @@
import_exceptions = tempest.services
[flake8]
-# E125 is a won't fix until https://github.com/jcrocholl/pep8/issues/126 is resolved. For further detail see https://review.openstack.org/#/c/36788/
+# E125 is a won't fix until https://github.com/jcrocholl/pep8/issues/126 is resolved. For further detail see https://review.opendev.org/#/c/36788/
# E123 skipped because it is ignored by default in the default pep8
# E129 skipped because it is too limiting when combined with other rules
# W504 skipped because it is overeager and unnecessary
@@ -234,7 +234,7 @@
[testenv:releasenotes]
basepython = python3
deps =
- -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt}
+ -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
-r{toxinidir}/requirements.txt
-r{toxinidir}/doc/requirements.txt
commands =
@@ -265,6 +265,7 @@
[testenv:plugin-sanity-check]
# perform tempest plugin sanity
+basepython = python3
whitelist_externals = bash
commands =
bash tools/tempest-plugin-sanity.sh