Merge "Break out novnc connection validation to a mixin"
diff --git a/doc/source/plugins/plugin.rst b/doc/source/plugins/plugin.rst
index 31aa134..573aa7d 100644
--- a/doc/source/plugins/plugin.rst
+++ b/doc/source/plugins/plugin.rst
@@ -29,6 +29,10 @@
* tempest.config
* tempest.test_discover.plugins
* tempest.common.credentials_factory
+* tempest.common.compute
+* tempest.common.identity
+* tempest.common.image
+* tempest.common.object_storage
* tempest.clients
* tempest.test
* tempest.scenario.manager
diff --git a/doc/source/supported_version.rst b/doc/source/supported_version.rst
index 9c03e7f..d4b7b4c 100644
--- a/doc/source/supported_version.rst
+++ b/doc/source/supported_version.rst
@@ -12,7 +12,6 @@
* 2025.2
* 2025.1
* 2024.2
-* 2024.1
For older OpenStack Release:
@@ -33,7 +32,7 @@
Tempest master supports the below python versions:
-* Python 3.9
* Python 3.10
* Python 3.11
* Python 3.12
+* Python 3.13
diff --git a/releasenotes/notes/add-alt-manager-dynamic-creds-f8f1007862ea5dfb.yaml b/releasenotes/notes/add-alt-manager-dynamic-creds-f8f1007862ea5dfb.yaml
new file mode 100644
index 0000000..bff36c7
--- /dev/null
+++ b/releasenotes/notes/add-alt-manager-dynamic-creds-f8f1007862ea5dfb.yaml
@@ -0,0 +1,4 @@
+---
+features:
+ - |
+ Add alt manager role to the dynamic credentials provider for project scope.
diff --git a/releasenotes/notes/drop-python-3-9-b8a25c06e4bc0787.yaml b/releasenotes/notes/drop-python-3-9-b8a25c06e4bc0787.yaml
new file mode 100644
index 0000000..f9488d7
--- /dev/null
+++ b/releasenotes/notes/drop-python-3-9-b8a25c06e4bc0787.yaml
@@ -0,0 +1,8 @@
+---
+prelude: >
+ Tempest dropped the support of python 3.9.
+upgrade:
+ - |
+ Python 3.9 support has been dropped. The last release of Tempest
+ to support python 3.9 is Temepst 45.0.0. The minimum version
+ of Python supported by Tempest is python 3.10.
diff --git a/releasenotes/notes/plugin-sytable-interface-18f865ba3a415c70.yaml b/releasenotes/notes/plugin-sytable-interface-18f865ba3a415c70.yaml
new file mode 100644
index 0000000..6d466c7
--- /dev/null
+++ b/releasenotes/notes/plugin-sytable-interface-18f865ba3a415c70.yaml
@@ -0,0 +1,9 @@
+---
+prelude: |
+ Tempest declares the following interface as a stable interface
+ to be used by the tempest plugins:
+
+ * tempest.common.compute
+ * tempest.common.identity
+ * tempest.common.image
+ * tempest.common.object_storage
diff --git a/releasenotes/notes/tempest-2024-2-release-e706f62c7e841bd0.yaml b/releasenotes/notes/tempest-2025-1-release-e706f62c7e841bd0.yaml
similarity index 98%
rename from releasenotes/notes/tempest-2024-2-release-e706f62c7e841bd0.yaml
rename to releasenotes/notes/tempest-2025-1-release-e706f62c7e841bd0.yaml
index 86af60c..24129cf 100644
--- a/releasenotes/notes/tempest-2024-2-release-e706f62c7e841bd0.yaml
+++ b/releasenotes/notes/tempest-2025-1-release-e706f62c7e841bd0.yaml
@@ -1,5 +1,5 @@
---
-prelude: >
+prelude: |
This release is to tag Tempest for OpenStack 2025.1 release.
This release marks the start of 2025.1 release support in Tempest.
After this release, Tempest will support below OpenStack Releases:
diff --git a/roles/run-tempest/tasks/main.yaml b/roles/run-tempest/tasks/main.yaml
index 15b1743..60402ee 100644
--- a/roles/run-tempest/tasks/main.yaml
+++ b/roles/run-tempest/tasks/main.yaml
@@ -25,11 +25,11 @@
target_branch: "{{ zuul.override_checkout }}"
when: zuul.override_checkout is defined
-- name: Use stable branch upper-constraints till 2023.1
+- name: Use stable branch upper-constraints till 2024.1
set_fact:
# TOX_CONSTRAINTS_FILE is new name, UPPER_CONSTRAINTS_FILE is old one, best to set both
tempest_tox_environment: "{{ tempest_tox_environment | combine({'UPPER_CONSTRAINTS_FILE': stable_constraints_file}) | combine({'TOX_CONSTRAINTS_FILE': stable_constraints_file}) }}"
- when: target_branch in ["stable/ocata", "stable/pike", "stable/queens", "stable/rocky", "stable/stein", "stable/train", "stable/ussuri", "stable/2023.1", "unmaintained/victoria", "unmaintained/wallaby", "unmaintained/xena", "unmaintained/yoga", "unmaintained/zed", "unmaintained/2023.1"]
+ when: target_branch in ["stable/ocata", "stable/pike", "stable/queens", "stable/rocky", "stable/stein", "stable/train", "stable/ussuri", "stable/2023.1", "unmaintained/victoria", "unmaintained/wallaby", "unmaintained/xena", "unmaintained/yoga", "unmaintained/zed", "unmaintained/2023.1", "unmaintained/2024.1"]
- name: Use Configured upper-constraints for non-master Tempest
set_fact:
diff --git a/setup.cfg b/setup.cfg
index 67555f4..fa17801 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -14,10 +14,10 @@
Operating System :: POSIX :: Linux
Programming Language :: Python
Programming Language :: Python :: 3
- Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Programming Language :: Python :: 3.11
Programming Language :: Python :: 3.12
+ Programming Language :: Python :: 3.13
Programming Language :: Python :: 3 :: Only
Programming Language :: Python :: Implementation :: CPython
diff --git a/tempest/api/compute/admin/test_live_migration.py b/tempest/api/compute/admin/test_live_migration.py
index bd2e7bf..526c8a7 100644
--- a/tempest/api/compute/admin/test_live_migration.py
+++ b/tempest/api/compute/admin/test_live_migration.py
@@ -58,7 +58,7 @@
cls.subnets_client = cls.os_primary.subnets_client
cls.ports_client = cls.os_primary.ports_client
cls.trunks_client = cls.os_primary.trunks_client
- cls.mgr_server_client = cls.admin_servers_client
+ cls.server_client = cls.admin_servers_client
def _migrate_server_to(self, server_id, dest_host, volume_backed=False,
use_manager_client=False):
@@ -70,13 +70,19 @@
block_migration = (CONF.compute_feature_enabled.
block_migration_for_live_migration and
not volume_backed)
+ # Avoid changing self.server_client permanently because
+ # [compute_feature_enabled]live_migrate_back_and_forth might be
+ # set to True. If it is, the test will live migrate the server back to
+ # the source using the os-migrate-server:migrate_live:host API, which
+ # is not allowed for project manager by default policy.
+ server_client = self.server_client
if use_manager_client:
- self.mgr_server_client = self.os_project_manager.servers_client
+ server_client = self.os_project_manager.servers_client
LOG.info("Using project manager for live migrating server: %s, "
"project manager user id: %s",
- server_id, self.mgr_server_client.user_id)
+ server_id, server_client.user_id)
- self.mgr_server_client.live_migrate_server(
+ server_client.live_migrate_server(
server_id, host=dest_host, block_migration=block_migration,
**kwargs)
diff --git a/tempest/api/compute/flavors/test_flavors.py b/tempest/api/compute/flavors/test_flavors.py
index 9ab75c5..2916de5 100644
--- a/tempest/api/compute/flavors/test_flavors.py
+++ b/tempest/api/compute/flavors/test_flavors.py
@@ -14,18 +14,32 @@
# under the License.
from tempest.api.compute import base
+from tempest import config
from tempest.lib import decorators
+CONF = config.CONF
+
+
class FlavorsV2TestJSON(base.BaseV2ComputeTest):
"""Tests Flavors"""
+ credentials = ['primary', 'project_reader']
+
+ @classmethod
+ def setup_clients(cls):
+ super(FlavorsV2TestJSON, cls).setup_clients()
+ if CONF.enforce_scope.nova:
+ cls.reader_client = cls.os_project_reader.flavors_client
+ else:
+ cls.reader_client = cls.flavors_client
+
@decorators.attr(type='smoke')
@decorators.idempotent_id('e36c0eaa-dff5-4082-ad1f-3f9a80aa3f59')
def test_list_flavors(self):
"""List of all flavors should contain the expected flavor"""
- flavors = self.flavors_client.list_flavors()['flavors']
- flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor']
+ flavors = self.reader_client.list_flavors()['flavors']
+ flavor = self.reader_client.show_flavor(self.flavor_ref)['flavor']
flavor_min_detail = {'id': flavor['id'], 'links': flavor['links'],
'name': flavor['name']}
# description field is added to the response of list_flavors in 2.55
@@ -36,93 +50,93 @@
@decorators.idempotent_id('6e85fde4-b3cd-4137-ab72-ed5f418e8c24')
def test_list_flavors_with_detail(self):
"""Detailed list of all flavors should contain the expected flavor"""
- flavors = self.flavors_client.list_flavors(detail=True)['flavors']
- flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor']
+ flavors = self.reader_client.list_flavors(detail=True)['flavors']
+ flavor = self.reader_client.show_flavor(self.flavor_ref)['flavor']
self.assertIn(flavor, flavors)
@decorators.attr(type='smoke')
@decorators.idempotent_id('1f12046b-753d-40d2-abb6-d8eb8b30cb2f')
def test_get_flavor(self):
"""The expected flavor details should be returned"""
- flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor']
+ flavor = self.reader_client.show_flavor(self.flavor_ref)['flavor']
self.assertEqual(self.flavor_ref, flavor['id'])
@decorators.idempotent_id('8d7691b3-6ed4-411a-abc9-2839a765adab')
def test_list_flavors_limit_results(self):
"""Only the expected number of flavors should be returned"""
params = {'limit': 1}
- flavors = self.flavors_client.list_flavors(**params)['flavors']
+ flavors = self.reader_client.list_flavors(**params)['flavors']
self.assertEqual(1, len(flavors))
@decorators.idempotent_id('b26f6327-2886-467a-82be-cef7a27709cb')
def test_list_flavors_detailed_limit_results(self):
"""Only the expected number of flavors(detailed) should be returned"""
params = {'limit': 1}
- flavors = self.flavors_client.list_flavors(detail=True,
- **params)['flavors']
+ flavors = self.reader_client.list_flavors(detail=True,
+ **params)['flavors']
self.assertEqual(1, len(flavors))
@decorators.idempotent_id('e800f879-9828-4bd0-8eae-4f17189951fb')
def test_list_flavors_using_marker(self):
"""The list of flavors should start from the provided marker"""
- flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor']
+ flavor = self.reader_client.show_flavor(self.flavor_ref)['flavor']
flavor_id = flavor['id']
params = {'marker': flavor_id}
- flavors = self.flavors_client.list_flavors(**params)['flavors']
+ flavors = self.reader_client.list_flavors(**params)['flavors']
self.assertEmpty([i for i in flavors if i['id'] == flavor_id],
'The list of flavors did not start after the marker.')
@decorators.idempotent_id('6db2f0c0-ddee-4162-9c84-0703d3dd1107')
def test_list_flavors_detailed_using_marker(self):
"""The list of flavors should start from the provided marker"""
- flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor']
+ flavor = self.reader_client.show_flavor(self.flavor_ref)['flavor']
flavor_id = flavor['id']
params = {'marker': flavor_id}
- flavors = self.flavors_client.list_flavors(detail=True,
- **params)['flavors']
+ flavors = self.reader_client.list_flavors(detail=True,
+ **params)['flavors']
self.assertEmpty([i for i in flavors if i['id'] == flavor_id],
'The list of flavors did not start after the marker.')
@decorators.idempotent_id('3df2743e-3034-4e57-a4cb-b6527f6eac79')
def test_list_flavors_detailed_filter_by_min_disk(self):
"""The detailed list of flavors should be filtered by disk space"""
- flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor']
+ flavor = self.reader_client.show_flavor(self.flavor_ref)['flavor']
flavor_id = flavor['id']
params = {'minDisk': flavor['disk'] + 1}
- flavors = self.flavors_client.list_flavors(detail=True,
- **params)['flavors']
+ flavors = self.reader_client.list_flavors(detail=True,
+ **params)['flavors']
self.assertEmpty([i for i in flavors if i['id'] == flavor_id])
@decorators.idempotent_id('09fe7509-b4ee-4b34-bf8b-39532dc47292')
def test_list_flavors_detailed_filter_by_min_ram(self):
"""The detailed list of flavors should be filtered by RAM"""
- flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor']
+ flavor = self.reader_client.show_flavor(self.flavor_ref)['flavor']
flavor_id = flavor['id']
params = {'minRam': flavor['ram'] + 1}
- flavors = self.flavors_client.list_flavors(detail=True,
- **params)['flavors']
+ flavors = self.reader_client.list_flavors(detail=True,
+ **params)['flavors']
self.assertEmpty([i for i in flavors if i['id'] == flavor_id])
@decorators.idempotent_id('10645a4d-96f5-443f-831b-730711e11dd4')
def test_list_flavors_filter_by_min_disk(self):
"""The list of flavors should be filtered by disk space"""
- flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor']
+ flavor = self.reader_client.show_flavor(self.flavor_ref)['flavor']
flavor_id = flavor['id']
params = {'minDisk': flavor['disk'] + 1}
- flavors = self.flavors_client.list_flavors(**params)['flavors']
+ flavors = self.reader_client.list_flavors(**params)['flavors']
self.assertEmpty([i for i in flavors if i['id'] == flavor_id])
@decorators.idempotent_id('935cf550-e7c8-4da6-8002-00f92d5edfaa')
def test_list_flavors_filter_by_min_ram(self):
"""The list of flavors should be filtered by RAM"""
- flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor']
+ flavor = self.reader_client.show_flavor(self.flavor_ref)['flavor']
flavor_id = flavor['id']
params = {'minRam': flavor['ram'] + 1}
- flavors = self.flavors_client.list_flavors(**params)['flavors']
+ flavors = self.reader_client.list_flavors(**params)['flavors']
self.assertEmpty([i for i in flavors if i['id'] == flavor_id])
diff --git a/tempest/api/compute/flavors/test_flavors_negative.py b/tempest/api/compute/flavors/test_flavors_negative.py
index efd9cdd..682ca58 100644
--- a/tempest/api/compute/flavors/test_flavors_negative.py
+++ b/tempest/api/compute/flavors/test_flavors_negative.py
@@ -28,6 +28,16 @@
class FlavorsV2NegativeTest(base.BaseV2ComputeTest):
+ credentials = ['primary', 'project_reader']
+
+ @classmethod
+ def setup_clients(cls):
+ super(FlavorsV2NegativeTest, cls).setup_clients()
+ if CONF.enforce_scope.nova:
+ cls.reader_client = cls.os_project_reader.flavors_client
+ else:
+ cls.reader_client = cls.flavors_client
+
@decorators.attr(type=['negative'])
@utils.services('image')
@decorators.idempotent_id('90f0d93a-91c1-450c-91e6-07d18172cefe')
@@ -38,7 +48,7 @@
Try to create server with flavor of insufficient ram size from
that image
"""
- flavor = self.flavors_client.show_flavor(
+ flavor = self.reader_client.show_flavor(
CONF.compute.flavor_ref)['flavor']
min_img_ram = flavor['ram'] + 1
size = random.randint(1024, 4096)
diff --git a/tempest/api/compute/servers/test_create_server.py b/tempest/api/compute/servers/test_create_server.py
index 0b39b8a..1454deb 100644
--- a/tempest/api/compute/servers/test_create_server.py
+++ b/tempest/api/compute/servers/test_create_server.py
@@ -33,7 +33,7 @@
This is to create server booted from image and with disk_config 'AUTO'
"""
-
+ credentials = ['primary', 'project_reader']
disk_config = 'AUTO'
volume_backed = False
@@ -46,6 +46,10 @@
def setup_clients(cls):
super(ServersTestJSON, cls).setup_clients()
cls.client = cls.servers_client
+ if CONF.enforce_scope.nova:
+ cls.reader_client = cls.os_project_reader.servers_client
+ else:
+ cls.reader_client = cls.client
@classmethod
def resource_setup(cls):
@@ -71,7 +75,8 @@
disk_config=disk_config,
adminPass=cls.password,
volume_backed=cls.volume_backed)
- cls.server = cls.client.show_server(server_initial['id'])['server']
+ cls.server = cls.reader_client.show_server(
+ server_initial['id'])['server']
@decorators.attr(type='smoke')
@decorators.idempotent_id('5de47127-9977-400a-936f-abcfbec1218f')
@@ -95,7 +100,7 @@
@decorators.idempotent_id('9a438d88-10c6-4bcd-8b5b-5b6e25e1346f')
def test_list_servers(self):
"""The created server should be in the list of all servers"""
- body = self.client.list_servers()
+ body = self.reader_client.list_servers()
servers = body['servers']
found = [i for i in servers if i['id'] == self.server['id']]
self.assertNotEmpty(found)
@@ -103,7 +108,7 @@
@decorators.idempotent_id('585e934c-448e-43c4-acbf-d06a9b899997')
def test_list_servers_with_detail(self):
"""The created server should be in the detailed list of all servers"""
- body = self.client.list_servers(detail=True)
+ body = self.reader_client.list_servers(detail=True)
servers = body['servers']
found = [i for i in servers if i['id'] == self.server['id']]
self.assertNotEmpty(found)
@@ -193,6 +198,8 @@
server hostname with dashes. This test verifies the same.
"""
+ credentials = ['primary', 'project_reader']
+
@classmethod
def setup_credentials(cls):
cls.prepare_instance_network()
@@ -202,6 +209,10 @@
def setup_clients(cls):
super(ServersTestFqdnHostnames, cls).setup_clients()
cls.client = cls.servers_client
+ if CONF.enforce_scope.nova:
+ cls.reader_client = cls.os_project_reader.servers_client
+ else:
+ cls.reader_client = cls.client
@decorators.idempotent_id('622066d2-39fc-4c09-9eeb-35903c114a0a')
@testtools.skipUnless(
@@ -250,6 +261,7 @@
more than 64 characters
"""
+ credentials = ['primary', 'project_reader']
min_microversion = '2.94'
@classmethod
@@ -261,6 +273,10 @@
def setup_clients(cls):
super(ServersV294TestFqdnHostnames, cls).setup_clients()
cls.client = cls.servers_client
+ if CONF.enforce_scope.nova:
+ cls.reader_client = cls.os_project_reader.servers_client
+ else:
+ cls.reader_client = cls.client
@classmethod
def resource_setup(cls):
@@ -279,7 +295,8 @@
accessIPv4=cls.accessIPv4,
adminPass=cls.password,
hostname=cls.hostname)
- cls.server = cls.client.show_server(cls.test_server['id'])['server']
+ cls.server = cls.reader_client.show_server(
+ cls.test_server['id'])['server']
def verify_metadata_hostname(self, md_json):
md_dict = json.loads(md_json)
diff --git a/tempest/api/compute/servers/test_create_server_multi_nic.py b/tempest/api/compute/servers/test_create_server_multi_nic.py
index 1cbb976..828ee32 100644
--- a/tempest/api/compute/servers/test_create_server_multi_nic.py
+++ b/tempest/api/compute/servers/test_create_server_multi_nic.py
@@ -48,6 +48,8 @@
class ServersTestMultiNic(base.BaseV2ComputeTest):
"""Test multiple networks in servers"""
+ credentials = ['primary', 'project_reader']
+
@classmethod
def skip_checks(cls):
super(ServersTestMultiNic, cls).skip_checks()
@@ -62,7 +64,10 @@
@classmethod
def setup_clients(cls):
super(ServersTestMultiNic, cls).setup_clients()
- cls.client = cls.servers_client
+ if CONF.enforce_scope.nova:
+ cls.reader_client = cls.os_project_reader.servers_client
+ else:
+ cls.reader_client = cls.servers_client
cls.networks_client = cls.os_primary.networks_client
cls.subnets_client = cls.os_primary.subnets_client
@@ -107,7 +112,7 @@
# we're OK.
self.addCleanup(self.delete_server, server_multi_nics['id'])
- addresses = (self.client.list_addresses(server_multi_nics['id'])
+ addresses = (self.reader_client.list_addresses(server_multi_nics['id'])
['addresses'])
# We can't predict the ip addresses assigned to the server on networks.
@@ -142,7 +147,7 @@
networks=networks, wait_until='ACTIVE')
self.addCleanup(self.delete_server, server_multi_nics['id'])
- addresses = (self.client.list_addresses(server_multi_nics['id'])
+ addresses = (self.reader_client.list_addresses(server_multi_nics['id'])
['addresses'])
addr = [addresses[net1['network']['name']][0]['addr'],
diff --git a/tempest/api/compute/servers/test_list_server_filters.py b/tempest/api/compute/servers/test_list_server_filters.py
index 7873296..45f3348 100644
--- a/tempest/api/compute/servers/test_list_server_filters.py
+++ b/tempest/api/compute/servers/test_list_server_filters.py
@@ -28,6 +28,8 @@
class ListServerFiltersTestJSON(base.BaseV2ComputeTest):
"""Test listing servers filtered by specified attribute"""
+ credentials = ['primary', 'project_reader']
+
@classmethod
def setup_credentials(cls):
cls.set_network_resources(network=True, subnet=True, dhcp=True)
@@ -37,6 +39,10 @@
def setup_clients(cls):
super(ListServerFiltersTestJSON, cls).setup_clients()
cls.client = cls.servers_client
+ if CONF.enforce_scope.nova:
+ cls.reader_client = cls.os_project_reader.servers_client
+ else:
+ cls.reader_client = cls.client
@classmethod
def resource_setup(cls):
@@ -80,7 +86,7 @@
def test_list_servers_filter_by_image(self):
"""Filter the list of servers by image"""
params = {'image': self.image_ref}
- body = self.client.list_servers(**params)
+ body = self.reader_client.list_servers(**params)
servers = body['servers']
self.assertIn(self.s1['id'], map(lambda x: x['id'], servers))
@@ -91,7 +97,7 @@
def test_list_servers_filter_by_flavor(self):
"""Filter the list of servers by flavor"""
params = {'flavor': self.flavor_ref_alt}
- body = self.client.list_servers(**params)
+ body = self.reader_client.list_servers(**params)
servers = body['servers']
self.assertNotIn(self.s1['id'], map(lambda x: x['id'], servers))
@@ -102,7 +108,7 @@
def test_list_servers_filter_by_server_name(self):
"""Filter the list of servers by server name"""
params = {'name': self.s1_name}
- body = self.client.list_servers(**params)
+ body = self.reader_client.list_servers(**params)
servers = body['servers']
self.assertIn(self.s1_name, map(lambda x: x['name'], servers))
@@ -113,7 +119,7 @@
def test_list_servers_filter_by_active_status(self):
"""Filter the list of servers by server active status"""
params = {'status': 'active'}
- body = self.client.list_servers(**params)
+ body = self.reader_client.list_servers(**params)
servers = body['servers']
self.assertIn(self.s1['id'], map(lambda x: x['id'], servers))
@@ -127,7 +133,7 @@
self.client.stop_server(self.s1['id'])
waiters.wait_for_server_status(self.client, self.s1['id'],
'SHUTOFF')
- body = self.client.list_servers(**params)
+ body = self.reader_client.list_servers(**params)
self.client.start_server(self.s1['id'])
waiters.wait_for_server_status(self.client, self.s1['id'],
'ACTIVE')
@@ -144,7 +150,7 @@
Verify only the expected number of servers are returned (one server)
"""
params = {'limit': 1}
- servers = self.client.list_servers(**params)
+ servers = self.reader_client.list_servers(**params)
self.assertEqual(1, len([x for x in servers['servers'] if 'id' in x]))
@decorators.idempotent_id('b1495414-2d93-414c-8019-849afe8d319e')
@@ -154,7 +160,7 @@
Verify only the expected number of servers are returned (no server)
"""
params = {'limit': 0}
- servers = self.client.list_servers(**params)
+ servers = self.reader_client.list_servers(**params)
self.assertEmpty(servers['servers'])
@decorators.idempotent_id('37791bbd-90c0-4de0-831e-5f38cba9c6b3')
@@ -164,8 +170,8 @@
Verify only the expected number of servers are returned (all servers)
"""
params = {'limit': 100000}
- servers = self.client.list_servers(**params)
- all_servers = self.client.list_servers()
+ servers = self.reader_client.list_servers(**params)
+ all_servers = self.reader_client.list_servers()
self.assertEqual(len([x for x in all_servers['servers'] if 'id' in x]),
len([x for x in servers['servers'] if 'id' in x]))
@@ -175,7 +181,7 @@
def test_list_servers_detailed_filter_by_image(self):
""""Filter the detailed list of servers by image"""
params = {'image': self.image_ref}
- body = self.client.list_servers(detail=True, **params)
+ body = self.reader_client.list_servers(detail=True, **params)
servers = body['servers']
self.assertIn(self.s1['id'], map(lambda x: x['id'], servers))
@@ -186,7 +192,7 @@
def test_list_servers_detailed_filter_by_flavor(self):
"""Filter the detailed list of servers by flavor"""
params = {'flavor': self.flavor_ref_alt}
- body = self.client.list_servers(detail=True, **params)
+ body = self.reader_client.list_servers(detail=True, **params)
servers = body['servers']
self.assertNotIn(self.s1['id'], map(lambda x: x['id'], servers))
@@ -197,7 +203,7 @@
def test_list_servers_detailed_filter_by_server_name(self):
"""Filter the detailed list of servers by server name"""
params = {'name': self.s1_name}
- body = self.client.list_servers(detail=True, **params)
+ body = self.reader_client.list_servers(detail=True, **params)
servers = body['servers']
self.assertIn(self.s1_name, map(lambda x: x['name'], servers))
@@ -208,7 +214,7 @@
def test_list_servers_detailed_filter_by_server_status(self):
"""Filter the detailed list of servers by server status"""
params = {'status': 'active'}
- body = self.client.list_servers(detail=True, **params)
+ body = self.reader_client.list_servers(detail=True, **params)
servers = body['servers']
test_ids = [s['id'] for s in (self.s1, self.s2, self.s3)]
@@ -223,7 +229,7 @@
"""Filter the list of servers by part of server name"""
# List all servers that contains '-instance' in name
params = {'name': '-instance'}
- body = self.client.list_servers(**params)
+ body = self.reader_client.list_servers(**params)
servers = body['servers']
self.assertIn(self.s1_name, map(lambda x: x['name'], servers))
@@ -234,7 +240,7 @@
part_name = self.s1_name[6:-1]
params = {'name': part_name}
- body = self.client.list_servers(**params)
+ body = self.reader_client.list_servers(**params)
servers = body['servers']
self.assertIn(self.s1_name, map(lambda x: x['name'], servers))
@@ -248,7 +254,7 @@
regexes = [r'^.*\-instance\-[0-9]+$', r'^.*\-instance\-.*$']
for regex in regexes:
params = {'name': regex}
- body = self.client.list_servers(**params)
+ body = self.reader_client.list_servers(**params)
servers = body['servers']
self.assertIn(self.s1_name, map(lambda x: x['name'], servers))
@@ -259,7 +265,7 @@
part_name = self.s1_name[-10:]
params = {'name': part_name}
- body = self.client.list_servers(**params)
+ body = self.reader_client.list_servers(**params)
servers = body['servers']
self.assertIn(self.s1_name, map(lambda x: x['name'], servers))
@@ -279,22 +285,22 @@
# so here look for the longest server ip, and filter by that ip,
# so as to ensure only one server is returned.
ip_list = {}
- self.s1 = self.client.show_server(self.s1['id'])['server']
+ self.s1 = self.reader_client.show_server(self.s1['id'])['server']
# Get first ip address in spite of v4 or v6
ip_addr = self.s1['addresses'][self.fixed_network_name][0]['addr']
ip_list[ip_addr] = self.s1['id']
- self.s2 = self.client.show_server(self.s2['id'])['server']
+ self.s2 = self.reader_client.show_server(self.s2['id'])['server']
ip_addr = self.s2['addresses'][self.fixed_network_name][0]['addr']
ip_list[ip_addr] = self.s2['id']
- self.s3 = self.client.show_server(self.s3['id'])['server']
+ self.s3 = self.reader_client.show_server(self.s3['id'])['server']
ip_addr = self.s3['addresses'][self.fixed_network_name][0]['addr']
ip_list[ip_addr] = self.s3['id']
longest_ip = max([[len(ip), ip] for ip in ip_list])[1]
params = {'ip': longest_ip}
- body = self.client.list_servers(**params)
+ body = self.reader_client.list_servers(**params)
servers = body['servers']
self.assertIn(ip_list[longest_ip], map(lambda x: x['id'], servers))
@@ -311,7 +317,7 @@
# query addresses of the 3 servers
addrs = []
for s in [self.s1, self.s2, self.s3]:
- s_show = self.client.show_server(s['id'])['server']
+ s_show = self.reader_client.show_server(s['id'])['server']
addr_spec = s_show['addresses'][self.fixed_network_name][0]
addrs.append(addr_spec['addr'])
# find common part of the 3 ip addresses
@@ -329,8 +335,8 @@
else:
params = {'ip6': prefix}
# capture all servers in case something goes wrong
- all_servers = self.client.list_servers(detail=True)
- body = self.client.list_servers(**params)
+ all_servers = self.reader_client.list_servers(detail=True)
+ body = self.reader_client.list_servers(**params)
servers = body['servers']
self.assertIn(self.s1_name, map(lambda x: x['name'], servers),
@@ -350,5 +356,5 @@
Verify only the expected number of servers are returned (one server)
"""
params = {'limit': 1}
- servers = self.client.list_servers(detail=True, **params)
+ servers = self.reader_client.list_servers(detail=True, **params)
self.assertEqual(1, len(servers['servers']))
diff --git a/tempest/api/compute/servers/test_list_servers_negative.py b/tempest/api/compute/servers/test_list_servers_negative.py
index 3d55696..140e5c3 100644
--- a/tempest/api/compute/servers/test_list_servers_negative.py
+++ b/tempest/api/compute/servers/test_list_servers_negative.py
@@ -15,19 +15,28 @@
from tempest.api.compute import base
from tempest.common import waiters
+from tempest import config
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
+CONF = config.CONF
+
+
class ListServersNegativeTestJSON(base.BaseV2ComputeTest):
"""Negative tests of listing servers"""
+ credentials = ['primary', 'project_reader']
create_default_network = True
@classmethod
def setup_clients(cls):
super(ListServersNegativeTestJSON, cls).setup_clients()
cls.client = cls.servers_client
+ if CONF.enforce_scope.nova:
+ cls.reader_client = cls.os_project_reader.servers_client
+ else:
+ cls.reader_client = cls.client
@classmethod
def resource_setup(cls):
@@ -49,7 +58,7 @@
def test_list_servers_with_a_deleted_server(self):
"""Test that deleted servers do not show by default in list servers"""
# List servers and verify server not returned
- body = self.client.list_servers()
+ body = self.reader_client.list_servers()
servers = body['servers']
actual = [srv for srv in servers
if srv['id'] == self.deleted_id]
@@ -59,7 +68,7 @@
@decorators.idempotent_id('ff01387d-c7ad-47b4-ae9e-64fa214638fe')
def test_list_servers_by_non_existing_image(self):
"""Test listing servers for a non existing image returns empty list"""
- body = self.client.list_servers(image='non_existing_image')
+ body = self.reader_client.list_servers(image='non_existing_image')
servers = body['servers']
self.assertEmpty(servers)
@@ -67,7 +76,7 @@
@decorators.idempotent_id('5913660b-223b-44d4-a651-a0fbfd44ca75')
def test_list_servers_by_non_existing_flavor(self):
"""Test listing servers by non existing flavor returns empty list"""
- body = self.client.list_servers(flavor='non_existing_flavor')
+ body = self.reader_client.list_servers(flavor='non_existing_flavor')
servers = body['servers']
self.assertEmpty(servers)
@@ -80,7 +89,7 @@
list.
"""
- body = self.client.list_servers(name='non_existing_server_name')
+ body = self.reader_client.list_servers(name='non_existing_server_name')
servers = body['servers']
self.assertEmpty(servers)
@@ -95,12 +104,14 @@
"""
if self.is_requested_microversion_compatible('2.37'):
- body = self.client.list_servers(status='non_existing_status')
+ body = self.reader_client.list_servers(
+ status='non_existing_status')
servers = body['servers']
self.assertEmpty(servers)
else:
- self.assertRaises(lib_exc.BadRequest, self.client.list_servers,
- status='non_existing_status')
+ self.assertRaises(
+ lib_exc.BadRequest, self.reader_client.list_servers,
+ status='non_existing_status')
@decorators.attr(type=['negative'])
@decorators.idempotent_id('d47c17fb-eebd-4287-8e95-f20a7e627b18')
@@ -112,24 +123,24 @@
"""
# Gather the complete list of servers in the project for reference
- full_list = self.client.list_servers()['servers']
+ full_list = self.reader_client.list_servers()['servers']
# List servers by specifying a greater value for limit
limit = len(full_list) + 100
- body = self.client.list_servers(limit=limit)
+ body = self.reader_client.list_servers(limit=limit)
self.assertEqual(len(full_list), len(body['servers']))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('679bc053-5e70-4514-9800-3dfab1a380a6')
def test_list_servers_by_limits_pass_string(self):
"""Test listing servers by non-integer limit should fail"""
- self.assertRaises(lib_exc.BadRequest, self.client.list_servers,
+ self.assertRaises(lib_exc.BadRequest, self.reader_client.list_servers,
limit='testing')
@decorators.attr(type=['negative'])
@decorators.idempotent_id('62610dd9-4713-4ee0-8beb-fd2c1aa7f950')
def test_list_servers_by_limits_pass_negative_value(self):
"""Test listing servers by negative limit should fail"""
- self.assertRaises(lib_exc.BadRequest, self.client.list_servers,
+ self.assertRaises(lib_exc.BadRequest, self.reader_client.list_servers,
limit=-1)
@decorators.attr(type=['negative'])
@@ -137,7 +148,7 @@
def test_list_servers_by_changes_since_invalid_date(self):
"""Test listing servers by invalid changes-since format should fail"""
params = {'changes-since': '2011/01/01'}
- self.assertRaises(lib_exc.BadRequest, self.client.list_servers,
+ self.assertRaises(lib_exc.BadRequest, self.reader_client.list_servers,
**params)
@decorators.attr(type=['negative'])
@@ -154,14 +165,14 @@
# {'status': 'ACTIVE'} along with changes-since as filter.
changes_since = {'changes-since': '2051-01-01T12:34:00Z',
'status': 'ACTIVE'}
- body = self.client.list_servers(**changes_since)
+ body = self.reader_client.list_servers(**changes_since)
self.assertEmpty(body['servers'])
@decorators.attr(type=['negative'])
@decorators.idempotent_id('93055106-2d34-46fe-af68-d9ddbf7ee570')
def test_list_servers_detail_server_is_deleted(self):
"""Test listing servers detail should not contain deleted server"""
- body = self.client.list_servers(detail=True)
+ body = self.reader_client.list_servers(detail=True)
servers = body['servers']
actual = [srv for srv in servers
if srv['id'] == self.deleted_id]
diff --git a/tempest/api/compute/servers/test_server_rescue.py b/tempest/api/compute/servers/test_server_rescue.py
index d6c0324..9f96385 100644
--- a/tempest/api/compute/servers/test_server_rescue.py
+++ b/tempest/api/compute/servers/test_server_rescue.py
@@ -282,6 +282,7 @@
"""
block_device_mapping_v2 = [{
"boot_index": "0",
+ "delete_on_termination": "true",
"source_type": "blank",
"volume_size": CONF.volume.volume_size,
"destination_type": "volume"}]
@@ -300,6 +301,7 @@
"""
block_device_mapping_v2 = [{
"boot_index": "0",
+ "delete_on_termination": "true",
"source_type": "image",
"volume_size": CONF.volume.volume_size,
"uuid": CONF.compute.image_ref,
diff --git a/tempest/api/volume/admin/test_volume_retype.py b/tempest/api/volume/admin/test_volume_retype.py
index 251cf8e..e19038e 100644
--- a/tempest/api/volume/admin/test_volume_retype.py
+++ b/tempest/api/volume/admin/test_volume_retype.py
@@ -213,6 +213,12 @@
volume_max_microversion = 'latest'
@classmethod
+ def skip_checks(cls):
+ super(VolumeRetypeMultiattachTest, cls).skip_checks()
+ if not CONF.compute_feature_enabled.volume_multiattach:
+ raise cls.skipException('Volume multi-attach is not available.')
+
+ @classmethod
def resource_setup(cls):
super(VolumeRetypeMultiattachTest, cls).resource_setup()
extra_specs_src = {"multiattach": '<is> True'}
diff --git a/tempest/lib/api_schema/response/volume/volume_types.py b/tempest/lib/api_schema/response/volume/volume_types.py
index 51b3a72..4d09bcd 100644
--- a/tempest/lib/api_schema/response/volume/volume_types.py
+++ b/tempest/lib/api_schema/response/volume/volume_types.py
@@ -31,8 +31,7 @@
'qos_specs_id': {'type': ['string', 'null'], 'format': 'uuid'}
},
'additionalProperties': False,
- 'required': ['name', 'is_public', 'description', 'id',
- 'os-volume-type-access:is_public']
+ 'required': ['name', 'is_public', 'description', 'id']
}
show_volume_type = {
diff --git a/tempest/lib/common/cred_provider.py b/tempest/lib/common/cred_provider.py
index 93b9586..9be7c5e 100644
--- a/tempest/lib/common/cred_provider.py
+++ b/tempest/lib/common/cred_provider.py
@@ -100,6 +100,10 @@
return
@abc.abstractmethod
+ def get_project_alt_manager_creds(self):
+ return
+
+ @abc.abstractmethod
def get_project_member_creds(self):
return
diff --git a/tempest/lib/common/dynamic_creds.py b/tempest/lib/common/dynamic_creds.py
index 1815dc6..11e7215 100644
--- a/tempest/lib/common/dynamic_creds.py
+++ b/tempest/lib/common/dynamic_creds.py
@@ -427,7 +427,8 @@
elif credential_type in [['admin'], ['alt_admin']]:
credentials = self._create_creds(
admin=True, scope=scope, project_id=project_id)
- elif credential_type in [['alt_member'], ['alt_reader']]:
+ elif credential_type in [['alt_manager'], ['alt_member'],
+ ['alt_reader']]:
cred_type = credential_type[0][4:]
if isinstance(cred_type, str):
cred_type = [cred_type]
@@ -511,6 +512,9 @@
def get_project_manager_creds(self):
return self.get_credentials(['manager'], scope='project')
+ def get_project_alt_manager_creds(self):
+ return self.get_credentials(['alt_manager'], scope='project')
+
def get_project_member_creds(self):
return self.get_credentials(['member'], scope='project')
diff --git a/tempest/lib/common/preprov_creds.py b/tempest/lib/common/preprov_creds.py
index 3ba7db1..f3a84d6 100644
--- a/tempest/lib/common/preprov_creds.py
+++ b/tempest/lib/common/preprov_creds.py
@@ -392,6 +392,10 @@
self._creds['project_manager'] = project_manager
return project_manager
+ def get_project_alt_manager_creds(self):
+ # TODO(msava):Implement alt manager hash.
+ return
+
def get_project_member_creds(self):
if self._creds.get('project_member'):
return self._creds.get('project_member')
diff --git a/tempest/tests/lib/common/test_dynamic_creds.py b/tempest/tests/lib/common/test_dynamic_creds.py
index 4122db3..b62d854 100644
--- a/tempest/tests/lib/common/test_dynamic_creds.py
+++ b/tempest/tests/lib/common/test_dynamic_creds.py
@@ -248,6 +248,7 @@
creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
if test_alt_creds:
admin_func = creds.get_project_alt_admin_creds
+ manager_func = creds.get_project_alt_manager_creds
member_func = creds.get_project_alt_member_creds
reader_func = creds.get_project_alt_reader_creds
else:
@@ -290,11 +291,8 @@
# Now request for the project manager creds which should not create new
# project instead should use the project_id of member_creds already
# created project.
- # TODO(gmaan): test test_alt_creds also once alt project
- # manager is available.
- if not test_alt_creds:
- self._request_and_check_second_creds(
- creds, manager_func, member_creds, show_mock, sm_count=3)
+ self._request_and_check_second_creds(
+ creds, manager_func, member_creds, show_mock, sm_count=3)
def test_creds_within_same_project(self):
self._creds_within_same_project()
diff --git a/tempest/tests/test_test.py b/tempest/tests/test_test.py
index 7fb9bb3..f6f3588 100644
--- a/tempest/tests/test_test.py
+++ b/tempest/tests/test_test.py
@@ -407,7 +407,7 @@
def get_identity_version(cls):
return identity_version
- with testtools.ExpectedException(testtools.testcase.TestSkipped):
+ with testtools.ExpectedException(unittest.SkipTest):
NeedAdmin().skip_checks()
mock_iaa.assert_called_once_with('identity_version')
@@ -417,7 +417,7 @@
class NeedV2(self.parent_test):
identity_version = 'v2'
- with testtools.ExpectedException(testtools.testcase.TestSkipped):
+ with testtools.ExpectedException(unittest.SkipTest):
NeedV2().skip_checks()
def test_skip_checks_identity_v3_not_available(self):
@@ -426,7 +426,7 @@
class NeedV3(self.parent_test):
identity_version = 'v3'
- with testtools.ExpectedException(testtools.testcase.TestSkipped):
+ with testtools.ExpectedException(unittest.SkipTest):
NeedV3().skip_checks()
def test_setup_credentials_all(self):
diff --git a/tools/format.sh b/tools/format.sh
index ef5cc92..9685cdf 100755
--- a/tools/format.sh
+++ b/tools/format.sh
@@ -15,7 +15,7 @@
# isort is not compatible with the default flake8 (H306), maybe flake8-isort
# isort -rc -sl -fss ../tempest ../setup.py
-$AUTOPEP8 --exit-code --max-line-length=79 --experimental --in-place \
+$AUTOPEP8 --exit-code --max-line-length=79 --in-place \
-r ../tempest ../setup.py
ERROR=$?
diff --git a/tox.ini b/tox.ini
index 0fbc252..634b72f 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
[tox]
-envlist = pep8,py39,bashate,pip-check-reqs
+envlist = pep8,py,bashate,pip-check-reqs
minversion = 3.18.0
[tempestenv]
@@ -389,12 +389,14 @@
{[testenv]deps}
autopep8>=2.1.0
commands =
- autopep8 --exit-code --max-line-length=79 --experimental --diff -r tempest setup.py
+ autopep8 --exit-code --max-line-length=79 --diff -r tempest setup.py
flake8 {posargs}
check-uuid
[testenv:autopep8]
deps = autopep8>=2.1.0
+allowlist_externals =
+ {toxinidir}/tools/format.sh
commands =
{toxinidir}/tools/format.sh
@@ -473,8 +475,8 @@
pip-extra-reqs -d --ignore-file=tempest/tests/* tempest
pip-missing-reqs -d --ignore-file=tempest/tests/* tempest
-
[testenv:bindep]
+skip_install = true
# Do not install any requirements. We want this to be fast and work even if
# system dependencies are missing, since it's used to tell you what system
# dependencies are missing! This also means that bindep must be installed
diff --git a/zuul.d/integrated-gate.yaml b/zuul.d/integrated-gate.yaml
index 8e0a9f3..7880bd8 100644
--- a/zuul.d/integrated-gate.yaml
+++ b/zuul.d/integrated-gate.yaml
@@ -452,6 +452,7 @@
# but if project feel that is not required to run for non SLURP releases then they can opt to make it non-voting or remove it.
- grenade-skip-level-always:
branches:
+ - ^.*/2025.2
- ^.*/2025.1
- master
- tempest-integrated-networking
@@ -479,6 +480,7 @@
# but if project feel that is not required to run for non SLURP releases then they can opt to make it non-voting or remove it.
- grenade-skip-level-always:
branches:
+ - ^.*/2025.2
- ^.*/2025.1
- master
# Do not run it on ussuri until below issue is fixed
@@ -523,6 +525,7 @@
- ^.*/2024.1
- ^.*/2024.2
- ^.*/2025.1
+ - ^.*/2025.2
- master
- tempest-integrated-compute
# Do not run it on ussuri until below issue is fixed
@@ -541,6 +544,7 @@
- ^.*/2024.1
- ^.*/2024.2
- ^.*/2025.1
+ - ^.*/2025.2
- master
- tempest-integrated-compute
- openstacksdk-functional-devstack:
@@ -584,6 +588,7 @@
# but if project feel that is not required to run for non SLURP releases then they can opt to make it non-voting or remove it.
- grenade-skip-level-always:
branches:
+ - ^.*/2025.2
- ^.*/2025.1
- master
- tempest-integrated-placement
@@ -611,6 +616,7 @@
# but if project feel that is not required to run for non SLURP releases then they can opt to make it non-voting or remove it.
- grenade-skip-level-always:
branches:
+ - ^.*/2025.2
- ^.*/2025.1
- master
# Do not run it on ussuri until below issue is fixed
@@ -651,6 +657,7 @@
# but if project feel that is not required to run for non SLURP releases then they can opt to make it non-voting or remove it.
- grenade-skip-level-always:
branches:
+ - ^.*/2025.2
- ^.*/2025.1
- master
- tempest-integrated-storage
@@ -677,6 +684,7 @@
# but if project feel that is not required to run for non SLURP releases then they can opt to make it non-voting or remove it.
- grenade-skip-level-always:
branches:
+ - ^.*/2025.2
- ^.*/2025.1
- master
- tempest-integrated-storage
@@ -711,6 +719,7 @@
# but if project feel that is not required to run for non SLURP releases then they can opt to make it non-voting or remove it.
- grenade-skip-level-always:
branches:
+ - ^.*/2025.2
- ^.*/2025.1
- master
- tempest-integrated-object-storage
@@ -737,6 +746,7 @@
# but if project feel that is not required to run for non SLURP releases then they can opt to make it non-voting or remove it.
- grenade-skip-level-always:
branches:
+ - ^.*/2025.2
- ^.*/2025.1
- master
- tempest-integrated-object-storage
diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml
index 9c9bc61..d9c7352 100644
--- a/zuul.d/project.yaml
+++ b/zuul.d/project.yaml
@@ -8,10 +8,10 @@
check:
jobs:
- openstack-tox-pep8
- - openstack-tox-py39
- openstack-tox-py310
- openstack-tox-py311
- openstack-tox-py312
+ - openstack-tox-py313
- tempest-full-py3:
# Define list of irrelevant files to use everywhere else
irrelevant-files: &tempest-irrelevant-files
@@ -37,9 +37,9 @@
# if things are working in latest and oldest it will work in between
# stable branches also. If anything is breaking we will be catching
# those in respective stable branch gate.
- - tempest-full-2025-1:
+ - tempest-full-2025-2:
irrelevant-files: *tempest-irrelevant-files
- - tempest-full-2024-1:
+ - tempest-full-2024-2:
irrelevant-files: *tempest-irrelevant-files
- tempest-multinode-full-py3:
irrelevant-files: *tempest-irrelevant-files
@@ -113,22 +113,20 @@
- neutron-ovs-tempest-dvr:
voting: false
irrelevant-files: *tempest-irrelevant-files
- - interop-tempest-consistency:
- irrelevant-files: *tempest-irrelevant-files
- tempest-full-test-account-py3:
voting: false
irrelevant-files: *tempest-irrelevant-files
- - ironic-tempest-bios-ipmi-direct-tinyipa:
+ - ironic-tempest-bios-ipmi-direct:
irrelevant-files: *tempest-irrelevant-files
- openstack-tox-bashate:
irrelevant-files: *tempest-irrelevant-files-2
gate:
jobs:
- openstack-tox-pep8
- - openstack-tox-py39
- openstack-tox-py310
- openstack-tox-py311
- openstack-tox-py312
+ - openstack-tox-py313
- tempest-slow-py3:
irrelevant-files: *tempest-irrelevant-files
- neutron-ovs-grenade-multinode:
@@ -151,7 +149,7 @@
irrelevant-files: *tempest-irrelevant-files
- nova-live-migration:
irrelevant-files: *tempest-irrelevant-files
- - ironic-tempest-bios-ipmi-direct-tinyipa:
+ - ironic-tempest-bios-ipmi-direct:
irrelevant-files: *tempest-irrelevant-files
experimental:
jobs:
@@ -184,30 +182,31 @@
irrelevant-files: *tempest-irrelevant-files
# Run stable releases jobs except those are running in check
# pipeline already
- - tempest-full-2024-2
- - tempest-multinode-2025-1
- - tempest-multinode-2024-2
- - tempest-multinode-2024-1
- - tempest-slow-2025-1
- - tempest-slow-2024-2
- - tempest-slow-2024-1
- - tempest-full-2025-1-extra-tests
- - tempest-full-2024-2-extra-tests
- - tempest-full-2024-1-extra-tests
- periodic-stable:
- jobs:
- tempest-full-2025-1
- tempest-full-2024-2
- - tempest-full-2024-1
+ - tempest-multinode-2025-2
- tempest-multinode-2025-1
- tempest-multinode-2024-2
- - tempest-multinode-2024-1
+ - tempest-slow-2025-2
- tempest-slow-2025-1
- tempest-slow-2024-2
- - tempest-slow-2024-1
+ - tempest-full-2025-2-extra-tests
- tempest-full-2025-1-extra-tests
- tempest-full-2024-2-extra-tests
- - tempest-full-2024-1-extra-tests
+ periodic-stable:
+ jobs:
+ - tempest-full-2025-2
+ - tempest-full-2025-1
+ - tempest-full-2024-2
+ - tempest-multinode-2025-2
+ - tempest-multinode-2025-1
+ - tempest-multinode-2024-2
+ - tempest-slow-2025-2
+ - tempest-slow-2025-1
+ - tempest-slow-2024-2
+ - tempest-full-2025-2-extra-tests
+ - tempest-full-2025-1-extra-tests
+ - tempest-full-2024-2-extra-tests
periodic:
jobs:
- tempest-all
diff --git a/zuul.d/stable-jobs.yaml b/zuul.d/stable-jobs.yaml
index 27e65b9..6d702fe 100644
--- a/zuul.d/stable-jobs.yaml
+++ b/zuul.d/stable-jobs.yaml
@@ -1,4 +1,11 @@
# NOTE(gmann): This file includes all stable release jobs definition.
+
+- job:
+ name: tempest-full-2025-2
+ parent: tempest-full-py3
+ nodeset: openstack-single-node-noble
+ override-checkout: stable/2025.2
+
- job:
name: tempest-full-2025-1
parent: tempest-full-py3
@@ -12,10 +19,10 @@
override-checkout: stable/2024.2
- job:
- name: tempest-full-2024-1
- parent: tempest-full-py3
- nodeset: openstack-single-node-jammy
- override-checkout: stable/2024.1
+ name: tempest-full-2025-2-extra-tests
+ parent: tempest-extra-tests
+ nodeset: openstack-single-node-noble
+ override-checkout: stable/2025.2
- job:
name: tempest-full-2025-1-extra-tests
@@ -30,10 +37,10 @@
override-checkout: stable/2024.2
- job:
- name: tempest-full-2024-1-extra-tests
- parent: tempest-extra-tests
- nodeset: openstack-single-node-jammy
- override-checkout: stable/2024.1
+ name: tempest-multinode-2025-2
+ parent: tempest-multinode-full-py3
+ nodeset: openstack-two-node-noble
+ override-checkout: stable/2025.2
- job:
name: tempest-multinode-2025-1
@@ -48,10 +55,10 @@
override-checkout: stable/2024.2
- job:
- name: tempest-multinode-2024-1
- parent: tempest-multinode-full-py3
- nodeset: openstack-two-node-jammy
- override-checkout: stable/2024.1
+ name: tempest-slow-2025-2
+ parent: tempest-slow-py3
+ nodeset: openstack-two-node-noble
+ override-checkout: stable/2025.2
- job:
name: tempest-slow-2025-1
@@ -66,12 +73,6 @@
override-checkout: stable/2024.2
- job:
- name: tempest-slow-2024-1
- parent: tempest-slow-py3
- nodeset: openstack-two-node-jammy
- override-checkout: stable/2024.1
-
-- job:
name: tempest-full-py3
parent: devstack-tempest
# This job version is to use the 'full' tox env which