blob: 85a6c3628d185c064b2bcc0af6b627f687731a57 [file] [log] [blame]
ZhiQiang Fan39f97222013-09-20 04:49:44 +08001# Copyright 2012 OpenStack Foundation
Jay Pipes051075a2012-04-28 17:39:37 -04002# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15
Attila Fazekasf86fa312013-07-30 19:56:39 +020016import atexit
Ian Wienand98c35f32013-07-23 20:34:23 +100017import os
Attila Fazekas53943322014-02-10 16:07:34 +010018import sys
Jay Pipes051075a2012-04-28 17:39:37 -040019
Jordan Pittier35a63752016-08-30 13:09:12 +020020import debtcollector.moves
Balazs Gibizerdfb30432021-12-14 17:25:16 +010021from fasteners import process_lock
Matthew Treinish78561ad2013-07-26 11:41:56 -040022import fixtures
Balazs Gibizerdfb30432021-12-14 17:25:16 +010023from oslo_concurrency import lockutils
Doug Hellmann583ce2c2015-03-11 14:55:46 +000024from oslo_log import log as logging
ivan-zhu1feeb382013-01-24 10:14:39 +080025import testtools
Jay Pipes051075a2012-04-28 17:39:37 -040026
Matthew Treinish3e046852013-07-23 16:00:24 -040027from tempest import clients
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +010028from tempest.common import credentials_factory as credentials
Attila Fazekasdc216422013-01-29 15:12:14 +010029from tempest import config
Ghanshyam Mann18b45d72021-12-07 12:37:29 -060030from tempest.lib.common import api_microversion_fixture
Matthew Treinishb19c55d2017-07-17 12:38:35 -040031from tempest.lib.common import fixed_network
Ilya Shakhat1291bb42017-11-29 18:08:16 +010032from tempest.lib.common import profiler
Andrea Frittoli0477acc2017-08-09 21:14:53 +010033from tempest.lib.common import validation_resources as vr
Andrea Frittoli (andreaf)af4f7cf2016-06-13 15:12:26 +010034from tempest.lib import exceptions as lib_exc
Jay Pipes051075a2012-04-28 17:39:37 -040035
36LOG = logging.getLogger(__name__)
37
Sean Dague86bd8422013-12-20 09:56:44 -050038CONF = config.CONF
39
Jay Pipes051075a2012-04-28 17:39:37 -040040
Attila Fazekasf86fa312013-07-30 19:56:39 +020041at_exit_set = set()
42
43
44def validate_tearDownClass():
45 if at_exit_set:
Sean Dagueeb1523b2014-03-10 10:17:44 -040046 LOG.error(
Federico Ressi2d6bcaa2018-04-11 12:37:36 +020047 "tearDownClass does not call the super's tearDownClass in "
48 "these classes:\n"
49 " %s", at_exit_set)
Sean Dagueeb1523b2014-03-10 10:17:44 -040050
Attila Fazekasf86fa312013-07-30 19:56:39 +020051
52atexit.register(validate_tearDownClass)
53
Attila Fazekas53943322014-02-10 16:07:34 +010054
Matthew Treinish2474f412014-11-17 18:11:56 -050055class BaseTestCase(testtools.testcase.WithAttributes,
56 testtools.TestCase):
Andrea Frittolia5ddd552014-08-19 18:30:00 +010057 """The test base class defines Tempest framework for class level fixtures.
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +000058
Andrea Frittolia5ddd552014-08-19 18:30:00 +010059 `setUpClass` and `tearDownClass` are defined here and cannot be overwritten
60 by subclasses (enforced via hacking rule T105).
61
62 Set-up is split in a series of steps (setup stages), which can be
63 overwritten by test classes. Set-up stages are:
64 - skip_checks
65 - setup_credentials
66 - setup_clients
67 - resource_setup
68
69 Tear-down is also split in a series of steps (teardown stages), which are
70 stacked for execution only if the corresponding setup stage had been
71 reached during the setup phase. Tear-down stages are:
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -070072 - clear_credentials (defined in the base test class)
Andrea Frittolia5ddd552014-08-19 18:30:00 +010073 - resource_cleanup
74 """
Attila Fazekasc43fec82013-04-09 23:17:52 +020075
Andrea Frittolib21de6c2015-02-06 20:12:38 +000076 # NOTE(andreaf) credentials holds a list of the credentials to be allocated
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +010077 # at class setup time. Credential types can be 'primary', 'alt', 'admin' or
78 # a list of roles - the first element of the list being a label, and the
79 # rest the actual roles
Andrea Frittolib21de6c2015-02-06 20:12:38 +000080 credentials = []
Andrea Frittolibcbf1af12017-08-14 11:53:35 +010081
Andrea Frittoliba712ac2017-09-13 16:54:47 -060082 # Track if setUpClass was invoked
83 __setupclass_called = False
84
Andrea Frittolibcbf1af12017-08-14 11:53:35 +010085 # Network resources to be provisioned for the requested test credentials.
86 # Only used with the dynamic credentials provider.
87 _network_resources = {}
Matthew Treinish9f756a02014-01-15 10:26:07 -050088
Andrea Frittoli3be57482017-08-25 22:41:26 +010089 # Stack of resource cleanups
90 _class_cleanups = []
91
Andrea Frittoli9f416dd2017-08-10 15:38:00 +010092 # Resources required to validate a server using ssh
93 _validation_resources = {}
94
Sean Dague2ef32ac2014-06-09 11:32:23 -040095 # NOTE(sdague): log_format is defined inline here instead of using the oslo
96 # default because going through the config path recouples config to the
97 # stress tests too early, and depending on testr order will fail unit tests
98 log_format = ('%(asctime)s %(process)d %(levelname)-8s '
99 '[%(name)s] %(message)s')
100
Ryota MIBU60687e52015-12-09 18:37:39 +0900101 # Client manager class to use in this test case.
102 client_manager = clients.Manager
103
Sean Dague02620fd2016-03-02 15:52:51 -0500104 # A way to adjust slow test classes
105 TIMEOUT_SCALING_FACTOR = 1
106
Balazs Gibizerdfb30432021-12-14 17:25:16 +0100107 # An interprocess lock to implement serial test execution if requested.
108 # The serial test classes are the writers as only one of them can be
109 # executed. The rest of the test classes are the readers as many of them
110 # can be run in parallel.
111 # Only classes can be decorated with @serial decorator not individual test
112 # cases as tempest allows test class level resource setup which could
113 # interfere with serialized execution on test cases level. I.e. the class
114 # setup of one of the test cases could run before taking a test case level
115 # lock.
116 # We cannot init the lock here as external lock needs oslo configuration
117 # to be loaded first to get the lock_path
118 serial_rw_lock = None
119
120 # Defines if the tests in this class should be run without any parallelism
121 # Use the @serial decorator on your test class to indicate such requirement
122 _serial = False
123
Pavel Sedlák1053bd32013-04-16 16:47:40 +0200124 @classmethod
Andrea Frittoli3be57482017-08-25 22:41:26 +0100125 def _reset_class(cls):
Andrea Frittolibcbf1af12017-08-14 11:53:35 +0100126 cls.__setup_credentials_called = False
Andrea Frittoli (andreaf)08e42d42017-09-07 17:09:13 +0100127 cls.__resource_cleanup_called = False
Andrea Frittoli421dc3c2017-08-15 12:17:42 +0100128 cls.__skip_checks_called = False
Andrea Frittoliba712ac2017-09-13 16:54:47 -0600129 # Stack of callable to be invoked in reverse order
Andrea Frittoli3be57482017-08-25 22:41:26 +0100130 cls._class_cleanups = []
Andrea Frittoliba712ac2017-09-13 16:54:47 -0600131 # Stack of (name, callable) to be invoked in reverse order at teardown
132 cls._teardowns = []
Andrea Frittoli3be57482017-08-25 22:41:26 +0100133
134 @classmethod
Balazs Gibizerdfb30432021-12-14 17:25:16 +0100135 def is_serial_execution_requested(cls):
136 return cls._serial
137
138 @classmethod
Pavel Sedlák1053bd32013-04-16 16:47:40 +0200139 def setUpClass(cls):
Andrea Frittoliba712ac2017-09-13 16:54:47 -0600140 cls.__setupclass_called = True
Balazs Gibizerdfb30432021-12-14 17:25:16 +0100141
142 if cls.serial_rw_lock is None:
143 path = os.path.join(
144 lockutils.get_lock_path(CONF), 'tempest-serial-rw-lock')
145 cls.serial_rw_lock = (
146 process_lock.InterProcessReaderWriterLock(path)
147 )
148
Andrea Frittoli3be57482017-08-25 22:41:26 +0100149 # Reset state
150 cls._reset_class()
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100151 # It should never be overridden by descendants
Pavel Sedlák1053bd32013-04-16 16:47:40 +0200152 if hasattr(super(BaseTestCase, cls), 'setUpClass'):
153 super(BaseTestCase, cls).setUpClass()
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100154 try:
Balazs Gibizerdfb30432021-12-14 17:25:16 +0100155 if cls.is_serial_execution_requested():
156 LOG.debug('%s taking the write lock', cls.__name__)
157 cls.serial_rw_lock.acquire_write_lock()
158 LOG.debug('%s took the write lock', cls.__name__)
159 else:
160 cls.serial_rw_lock.acquire_read_lock()
161
Ghanshyam Mann68ddf412019-09-10 19:40:52 +0000162 cls.skip_checks()
163
164 if not cls.__skip_checks_called:
165 raise RuntimeError(
166 "skip_checks for %s did not call the super's "
167 "skip_checks" % cls.__name__)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100168 # Allocation of all required credentials and client managers
Andrea Frittoli (andreaf)08e42d42017-09-07 17:09:13 +0100169 cls._teardowns.append(('credentials', cls.clear_credentials))
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100170 cls.setup_credentials()
Andrea Frittoli421dc3c2017-08-15 12:17:42 +0100171 if not cls.__setup_credentials_called:
172 raise RuntimeError("setup_credentials for %s did not call the "
173 "super's setup_credentials" % cls.__name__)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100174 # Shortcuts to clients
175 cls.setup_clients()
176 # Additional class-wide test resources
Andrea Frittoli (andreaf)08e42d42017-09-07 17:09:13 +0100177 cls._teardowns.append(('resources', cls.resource_cleanup))
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100178 cls.resource_setup()
179 except Exception:
180 etype, value, trace = sys.exc_info()
Jordan Pittier525ec712016-12-07 17:51:26 +0100181 LOG.info("%s raised in %s.setUpClass. Invoking tearDownClass.",
182 etype, cls.__name__)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100183 cls.tearDownClass()
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100184 try:
songwenpinge6623072021-02-22 14:47:34 +0800185 raise value.with_traceback(trace)
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100186 finally:
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100187 del trace # to avoid circular refs
Pavel Sedlák1053bd32013-04-16 16:47:40 +0200188
Attila Fazekasf86fa312013-07-30 19:56:39 +0200189 @classmethod
190 def tearDownClass(cls):
Martin Kopecae155b72017-06-26 09:41:21 +0000191 # insert pdb breakpoint when pause_teardown is enabled
192 if CONF.pause_teardown:
193 cls.insert_pdb_breakpoint()
Attila Fazekas5d275302013-08-29 12:35:12 +0200194 at_exit_set.discard(cls)
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100195 # It should never be overridden by descendants
Attila Fazekasf86fa312013-07-30 19:56:39 +0200196 if hasattr(super(BaseTestCase, cls), 'tearDownClass'):
197 super(BaseTestCase, cls).tearDownClass()
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100198 # Save any existing exception, we always want to re-raise the original
199 # exception only
200 etype, value, trace = sys.exc_info()
201 # If there was no exception during setup we shall re-raise the first
202 # exception in teardown
203 re_raise = (etype is None)
Balazs Gibizerdfb30432021-12-14 17:25:16 +0100204 try:
205 while cls._teardowns:
206 name, teardown = cls._teardowns.pop()
207 # Catch any exception in tearDown so we can re-raise the
208 # original exception at the end
209 try:
210 teardown()
211 if name == 'resources':
212 if not cls.__resource_cleanup_called:
213 raise RuntimeError(
214 "resource_cleanup for %s did not call the "
215 "super's resource_cleanup" % cls.__name__)
216 except Exception as te:
217 sys_exec_info = sys.exc_info()
218 tetype = sys_exec_info[0]
219 # TODO(andreaf): Resource cleanup is often implemented by
220 # storing an array of resources at class level, and
221 # cleaning them up during `resource_cleanup`.
222 # In case of failure during setup, some resource arrays
223 # might not be defined at all, in which case the cleanup
224 # code might trigger an AttributeError. In such cases we
225 # log AttributeError as info instead of exception. Once all
226 # cleanups are migrated to addClassResourceCleanup we can
227 # remove this.
228 if tetype is AttributeError and name == 'resources':
229 LOG.info("tearDownClass of %s failed: %s", name, te)
230 else:
231 LOG.exception("teardown of %s failed: %s", name, te)
232 if not etype:
233 etype, value, trace = sys_exec_info
234 finally:
235 if cls.is_serial_execution_requested():
236 LOG.debug('%s releasing the write lock', cls.__name__)
237 cls.serial_rw_lock.release_write_lock()
238 LOG.debug('%s released the write lock', cls.__name__)
239 else:
240 cls.serial_rw_lock.release_read_lock()
241
Joshua Whitebd769602016-02-02 09:30:11 -0800242 # If exceptions were raised during teardown, and not before, re-raise
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100243 # the first one
244 if re_raise and etype is not None:
245 try:
songwenpinge6623072021-02-22 14:47:34 +0800246 raise value.with_traceback(trace)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100247 finally:
248 del trace # to avoid circular refs
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100249
Martin Kopecae155b72017-06-26 09:41:21 +0000250 def tearDown(self):
251 super(BaseTestCase, self).tearDown()
252 # insert pdb breakpoint when pause_teardown is enabled
253 if CONF.pause_teardown:
254 BaseTestCase.insert_pdb_breakpoint()
255
Ilya Shakhat1291bb42017-11-29 18:08:16 +0100256 if CONF.profiler.key:
257 profiler.disable()
258
Martin Kopecae155b72017-06-26 09:41:21 +0000259 @classmethod
260 def insert_pdb_breakpoint(cls):
261 """Add pdb breakpoint.
262
263 This can help in debugging process, cleaning of resources is
264 paused, so they can be examined.
265 """
266 import pdb
267 pdb.set_trace()
268
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100269 @classmethod
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100270 def skip_checks(cls):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000271 """Class level skip checks.
272
273 Subclasses verify in here all conditions that might prevent the
Andrea Frittolia5440c82017-08-23 18:11:21 +0100274 execution of the entire test class. Skipping here prevents any other
275 class fixture from being executed i.e. no credentials or other
276 resource allocation will happen.
277
278 Tests defined in the test class will no longer appear in test results.
279 The `setUpClass` for the entire test class will be marked as SKIPPED
280 instead.
281
282 At this stage no test credentials are available, so skip checks
283 should rely on configuration alone. This is deliberate since skips
284 based on the result of an API call are discouraged.
285
286 The following checks are implemented in `test.py` already:
Sergey Vilgelmeac094a2018-11-21 18:27:51 -0600287
Andrea Frittolia5440c82017-08-23 18:11:21 +0100288 - check that alt credentials are available when requested by the test
289 - check that admin credentials are available when requested by the test
290 - check that the identity version specified by the test is marked as
291 enabled in the configuration
292
293 Overriders of skip_checks must always invoke skip_check on `super`
294 first.
295
296 Example::
297
298 @classmethod
299 def skip_checks(cls):
300 super(Example, cls).skip_checks()
301 if not CONF.service_available.my_service:
302 skip_msg = ("%s skipped as my_service is not available")
303 raise cls.skipException(skip_msg % cls.__name__)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100304 """
Andrea Frittoli421dc3c2017-08-15 12:17:42 +0100305 cls.__skip_checks_called = True
Andrea Frittoli (andreaf)32d0de12015-10-09 14:43:53 +0100306 identity_version = cls.get_identity_version()
zhufl75498ba2017-08-25 10:49:35 +0800307 # setting force_tenant_isolation to True also needs admin credentials.
308 if ('admin' in cls.credentials or
Ghanshyam Mann420586c2021-01-29 13:23:18 -0600309 'alt_admin' in cls.credentials or
zhufl75498ba2017-08-25 10:49:35 +0800310 getattr(cls, 'force_tenant_isolation', False)):
311 if not credentials.is_admin_available(
312 identity_version=identity_version):
313 raise cls.skipException(
314 "Missing Identity Admin API credentials in configuration.")
Andrea Frittoli (andreaf)32d0de12015-10-09 14:43:53 +0100315 if 'alt' in cls.credentials and not credentials.is_alt_available(
316 identity_version=identity_version):
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000317 msg = "Missing a 2nd set of API credentials in configuration."
318 raise cls.skipException(msg)
Andrea Frittoli (andreaf)41601412015-05-12 16:39:03 +0100319 if hasattr(cls, 'identity_version'):
320 if cls.identity_version == 'v2':
321 if not CONF.identity_feature_enabled.api_v2:
322 raise cls.skipException("Identity api v2 is not enabled")
323 elif cls.identity_version == 'v3':
324 if not CONF.identity_feature_enabled.api_v3:
325 raise cls.skipException("Identity api v3 is not enabled")
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100326
327 @classmethod
328 def setup_credentials(cls):
edannon6cc6fbc2016-05-03 11:56:12 +0300329 """Allocate credentials and create the client managers from them.
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000330
Andrea Frittolia6c885a2017-08-23 19:37:50 +0100331 `setup_credentials` looks for the content of the `credentials`
332 attribute in the test class. If the value is a non-empty collection,
333 a credentials provider is setup, and credentials are provisioned or
334 allocated based on the content of the collection. Every set of
335 credentials is associated to an object of type `cls.client_manager`.
336 The client manager is accessible by tests via class attribute
337 `os_[type]`:
edannon6cc6fbc2016-05-03 11:56:12 +0300338
Andrea Frittolia6c885a2017-08-23 19:37:50 +0100339 Valid values in `credentials` are:
Sergey Vilgelmeac094a2018-11-21 18:27:51 -0600340
Andrea Frittolia6c885a2017-08-23 19:37:50 +0100341 - 'primary':
342 A normal user is provisioned.
343 It can be used only once. Multiple entries will be ignored.
344 Clients are available at os_primary.
345 - 'alt':
346 A normal user other than 'primary' is provisioned.
347 It can be used only once. Multiple entries will be ignored.
348 Clients are available at os_alt.
349 - 'admin':
350 An admin user is provisioned.
351 It can be used only once. Multiple entries will be ignored.
352 Clients are available at os_admin.
353 - A list in the format ['any_label', 'role1', ... , 'roleN']:
354 A client with roles <list>[1:] is provisioned.
355 It can be used multiple times, with unique labels.
356 Clients are available at os_roles_<list>[0].
357
358 By default network resources are allocated (in case of dynamic
359 credentials). Tests that do not need network or that require a
360 custom network setup must specify which network resources shall
361 be provisioned using the `set_network_resources()` method (note
362 that it must be invoked before the `setup_credentials` is
363 invoked on super).
364
365 Example::
366
367 class TestWithCredentials(test.BaseTestCase):
368
369 credentials = ['primary', 'admin',
370 ['special', 'special_role1']]
371
372 @classmethod
373 def setup_credentials(cls):
374 # set_network_resources must be called first
375 cls.set_network_resources(network=True)
376 super(TestWithCredentials, cls).setup_credentials()
377
378 @classmethod
379 def setup_clients(cls):
380 cls.servers = cls.os_primary.compute.ServersClient()
381 cls.admin_servers = cls.os_admin.compute.ServersClient()
382 # certain API calls may require a user with a specific
383 # role assigned. In this example `special_role1` is
384 # assigned to the user in `cls.os_roles_special`.
385 cls.special_servers = (
386 cls.os_roles_special.compute.ServersClient())
387
388 def test_special_servers(self):
389 # Do something with servers
390 pass
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000391 """
Andrea Frittolibcbf1af12017-08-14 11:53:35 +0100392 cls.__setup_credentials_called = True
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000393 for credentials_type in cls.credentials:
394 # This may raise an exception in case credentials are not available
395 # In that case we want to let the exception through and the test
396 # fail accordingly
songwenpinga6ee2d12021-02-22 10:24:16 +0800397 if isinstance(credentials_type, str):
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100398 manager = cls.get_client_manager(
399 credential_type=credentials_type)
400 setattr(cls, 'os_%s' % credentials_type, manager)
Jordan Pittier8160d312017-04-18 11:52:23 +0200401 # NOTE(jordanP): Tempest should use os_primary, os_admin
402 # and os_alt throughout its code base but we keep the aliases
403 # around for a while for Tempest plugins. Aliases should be
404 # removed eventually.
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100405 # Setup some common aliases
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100406 if credentials_type == 'primary':
Jordan Pittier8160d312017-04-18 11:52:23 +0200407 cls.os = debtcollector.moves.moved_read_only_property(
408 'os', 'os_primary', version='Pike',
Jakub Libosvar7835ca12017-05-04 16:44:23 +0200409 removal_version='Queens')
Jordan Pittier8160d312017-04-18 11:52:23 +0200410 cls.manager =\
411 debtcollector.moves.moved_read_only_property(
412 'manager', 'os_primary', version='Pike',
Jakub Libosvar7835ca12017-05-04 16:44:23 +0200413 removal_version='Queens')
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100414 if credentials_type == 'admin':
Jordan Pittier8160d312017-04-18 11:52:23 +0200415 cls.os_adm = debtcollector.moves.moved_read_only_property(
416 'os_adm', 'os_admin', version='Pike',
Jakub Libosvar7835ca12017-05-04 16:44:23 +0200417 removal_version='Queens')
Jordan Pittier8160d312017-04-18 11:52:23 +0200418 cls.admin_manager =\
419 debtcollector.moves.moved_read_only_property(
420 'admin_manager', 'os_admin', version='Pike',
Jakub Libosvar7835ca12017-05-04 16:44:23 +0200421 removal_version='Queens')
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100422 if credentials_type == 'alt':
Jordan Pittier8160d312017-04-18 11:52:23 +0200423 cls.alt_manager =\
424 debtcollector.moves.moved_read_only_property(
425 'alt_manager', 'os_alt', version='Pike',
Jakub Libosvar7835ca12017-05-04 16:44:23 +0200426 removal_version='Queens')
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100427 elif isinstance(credentials_type, list):
Ghanshyam Mann2d0da042021-03-05 09:09:30 -0600428 scope = 'project'
429 if credentials_type[0].startswith('system'):
430 scope = 'system'
431 elif credentials_type[0].startswith('domain'):
432 scope = 'domain'
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100433 manager = cls.get_client_manager(roles=credentials_type[1:],
Ghanshyam Mann2d0da042021-03-05 09:09:30 -0600434 force_new=True,
435 scope=scope)
436 setattr(cls, 'os_%s' % credentials_type[0], manager)
437 # TODO(gmann): Setting the old style attribute too for
438 # backward compatibility but at some point we should
439 # remove this.
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100440 setattr(cls, 'os_roles_%s' % credentials_type[0], manager)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100441
442 @classmethod
443 def setup_clients(cls):
Andrea Frittoli99583672017-08-24 15:39:20 +0100444 """Create aliases to the clients in the client managers.
445
446 `setup_clients` is invoked after the credential provisioning step.
447 Client manager objects are available to tests already. The purpose
448 of this helper is to setup shortcuts to specific clients that are
449 useful for the tests implemented in the test class.
450
451 Its purpose is mostly for code readability, however it should be used
452 carefully to avoid doing exactly the opposite, i.e. making the code
453 unreadable and hard to debug. If aliases are defined in a super class
454 it won't be obvious what they refer to, so it's good practice to define
455 all aliases used in the class. Aliases are meant to be shortcuts to
456 be used in tests, not shortcuts to avoid helper method attributes.
457 If an helper method starts relying on a client alias and a subclass
458 overrides that alias, it will become rather difficult to understand
459 what the helper method actually does.
460
461 Example::
462
463 class TestDoneItRight(test.BaseTestCase):
464
465 credentials = ['primary', 'alt']
466
467 @classmethod
468 def setup_clients(cls):
469 super(TestDoneItRight, cls).setup_clients()
470 cls.servers = cls.os_primary.ServersClient()
471 cls.servers_alt = cls.os_alt.ServersClient()
472
473 def _a_good_helper(self, clients):
474 # Some complex logic we're going to use many times
475 servers = clients.ServersClient()
476 vm = servers.create_server(...)
477
478 def delete_server():
479 test_utils.call_and_ignore_notfound_exc(
480 servers.delete_server, vm['id'])
481
482 self.addCleanup(self.delete_server)
483 return vm
484
485 def test_with_servers(self):
486 vm = self._a_good_helper(os.primary)
487 vm_alt = self._a_good_helper(os.alt)
488 cls.servers.show_server(vm['id'])
489 cls.servers_alt.show_server(vm_alt['id'])
490 """
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100491 pass
Attila Fazekasf86fa312013-07-30 19:56:39 +0200492
Emily Hugenbruch5bd4cbf2014-12-17 21:38:38 +0000493 @classmethod
Ghanshyam Mann18b45d72021-12-07 12:37:29 -0600494 def setup_api_microversion_fixture(
495 cls, compute_microversion=None, volume_microversion=None,
496 placement_microversion=None):
497 """Set up api microversion fixture on service clients.
498
499 `setup_api_microversion_fixture` is used to set the api microversion
500 on service clients. This can be invoked from resource_setup() method.
501
502 Example::
503
504 @classmethod
505 def resource_setup(cls):
506 super(MyTest, cls).resource_setup()
507 cls.setup_api_microversion_fixture(
508 compute_microversion=cls.compute_request_microversion,
509 volume_microversion=cls.volume_request_microversion,
510 placement_microversion=cls.placement_request_microversion)
511
512 """
513
514 api_fixture = api_microversion_fixture.APIMicroversionFixture(
515 compute_microversion=compute_microversion,
516 volume_microversion=volume_microversion,
517 placement_microversion=placement_microversion)
518 api_fixture.setUp()
519 cls.addClassResourceCleanup(api_fixture._reset_microversion)
520
521 @classmethod
Emily Hugenbruch5bd4cbf2014-12-17 21:38:38 +0000522 def resource_setup(cls):
Andrea Frittoli3be57482017-08-25 22:41:26 +0100523 """Class level resource setup for test cases.
524
525 `resource_setup` is invoked once all credentials (and related network
526 resources have been provisioned and after client aliases - if any -
527 have been defined.
528
529 The use case for `resource_setup` is test optimization: provisioning
530 of project-specific "expensive" resources that are not dirtied by tests
531 and can thus safely be re-used by multiple tests.
532
533 System wide resources shared by all tests could instead be provisioned
534 only once, before the test run.
535
536 Resources provisioned here must be cleaned up during
537 `resource_cleanup`. This is best achieved by scheduling a cleanup via
538 `addClassResourceCleanup`.
539
540 Some test resources have an asynchronous delete process. It's best
541 practice for them to schedule a wait for delete via
542 `addClassResourceCleanup` to avoid having resources in process of
543 deletion when we reach the credentials cleanup step.
544
545 Example::
546
547 @classmethod
548 def resource_setup(cls):
549 super(MyTest, cls).resource_setup()
550 servers = cls.os_primary.compute.ServersClient()
551 # Schedule delete and wait so that we can first delete the
552 # two servers and then wait for both to delete
553 # Create server 1
554 cls.shared_server = servers.create_server()
555 # Create server 2. If something goes wrong we schedule cleanup
556 # of server 1 anyways.
557 try:
558 cls.shared_server2 = servers.create_server()
559 # Wait server 2
560 cls.addClassResourceCleanup(
561 waiters.wait_for_server_termination,
562 servers, cls.shared_server2['id'],
563 ignore_error=False)
564 finally:
565 # Wait server 1
566 cls.addClassResourceCleanup(
567 waiters.wait_for_server_termination,
568 servers, cls.shared_server['id'],
569 ignore_error=False)
570 # Delete server 1
571 cls.addClassResourceCleanup(
572 test_utils.call_and_ignore_notfound_exc,
573 servers.delete_server,
574 cls.shared_server['id'])
575 # Delete server 2 (if it was created)
576 if hasattr(cls, 'shared_server2'):
577 cls.addClassResourceCleanup(
578 test_utils.call_and_ignore_notfound_exc,
579 servers.delete_server,
580 cls.shared_server2['id'])
581 """
Andrea Frittoli9f416dd2017-08-10 15:38:00 +0100582 pass
Emily Hugenbruch5bd4cbf2014-12-17 21:38:38 +0000583
584 @classmethod
585 def resource_cleanup(cls):
586 """Class level resource cleanup for test cases.
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000587
Andrea Frittoli9f416dd2017-08-10 15:38:00 +0100588 Resource cleanup processes the stack of cleanups produced by
Andrea Frittoli3be57482017-08-25 22:41:26 +0100589 `addClassResourceCleanup` and then cleans up validation resources
590 if any were provisioned.
591
592 All cleanups are processed whatever the outcome. Exceptions are
593 accumulated and re-raised as a `MultipleExceptions` at the end.
594
595 In most cases test cases won't need to override `resource_cleanup`,
596 but if they do they must invoke `resource_cleanup` on super.
597
598 Example::
599
600 class TestWithReallyComplexCleanup(test.BaseTestCase):
601
602 @classmethod
603 def resource_setup(cls):
604 # provision resource A
605 cls.addClassResourceCleanup(delete_resource, A)
606 # provision resource B
607 cls.addClassResourceCleanup(delete_resource, B)
608
609 @classmethod
610 def resource_cleanup(cls):
611 # It's possible to override resource_cleanup but in most
612 # cases it shouldn't be required. Nothing that may fail
613 # should be executed before the call to super since it
614 # might cause resource leak in case of error.
615 super(TestWithReallyComplexCleanup, cls).resource_cleanup()
616 # At this point test credentials are still available but
617 # anything from the cleanup stack has been already deleted.
Emily Hugenbruch5bd4cbf2014-12-17 21:38:38 +0000618 """
Andrea Frittoli (andreaf)08e42d42017-09-07 17:09:13 +0100619 cls.__resource_cleanup_called = True
Andrea Frittoli3be57482017-08-25 22:41:26 +0100620 cleanup_errors = []
621 while cls._class_cleanups:
622 try:
623 fn, args, kwargs = cls._class_cleanups.pop()
624 fn(*args, **kwargs)
625 except Exception:
626 cleanup_errors.append(sys.exc_info())
Andrea Frittoli3be57482017-08-25 22:41:26 +0100627 if cleanup_errors:
628 raise testtools.MultipleExceptions(*cleanup_errors)
629
630 @classmethod
631 def addClassResourceCleanup(cls, fn, *arguments, **keywordArguments):
632 """Add a cleanup function to be called during resource_cleanup.
633
634 Functions added with addClassResourceCleanup will be called in reverse
635 order of adding at the beginning of resource_cleanup, before any
636 credential, networking or validation resources cleanup is processed.
637
638 If a function added with addClassResourceCleanup raises an exception,
639 the error will be recorded as a test error, and the next cleanup will
640 then be run.
641
642 Cleanup functions are always called during the test class tearDown
Rajesh Tailora85bdb42024-04-02 12:01:53 +0530643 fixture, even if an exception occurred during setUp or tearDown.
Andrea Frittoli3be57482017-08-25 22:41:26 +0100644 """
645 cls._class_cleanups.append((fn, arguments, keywordArguments))
Emily Hugenbruch5bd4cbf2014-12-17 21:38:38 +0000646
Attila Fazekasf86fa312013-07-30 19:56:39 +0200647 def setUp(self):
648 super(BaseTestCase, self).setUp()
Andrea Frittoliba712ac2017-09-13 16:54:47 -0600649 if not self.__setupclass_called:
zhuflde676372018-11-16 15:34:56 +0800650 raise RuntimeError("setUpClass does not calls the super's "
Federico Ressi2d6bcaa2018-04-11 12:37:36 +0200651 "setUpClass in the " +
652 self.__class__.__name__)
Attila Fazekasf86fa312013-07-30 19:56:39 +0200653 at_exit_set.add(self.__class__)
Matthew Treinish78561ad2013-07-26 11:41:56 -0400654 test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0)
655 try:
Sean Dague02620fd2016-03-02 15:52:51 -0500656 test_timeout = int(test_timeout) * self.TIMEOUT_SCALING_FACTOR
Matthew Treinish78561ad2013-07-26 11:41:56 -0400657 except ValueError:
658 test_timeout = 0
659 if test_timeout > 0:
Attila Fazekasf86fa312013-07-30 19:56:39 +0200660 self.useFixture(fixtures.Timeout(test_timeout, gentle=True))
Matthew Treinish78561ad2013-07-26 11:41:56 -0400661
662 if (os.environ.get('OS_STDOUT_CAPTURE') == 'True' or
663 os.environ.get('OS_STDOUT_CAPTURE') == '1'):
Attila Fazekasf86fa312013-07-30 19:56:39 +0200664 stdout = self.useFixture(fixtures.StringStream('stdout')).stream
665 self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
Matthew Treinish78561ad2013-07-26 11:41:56 -0400666 if (os.environ.get('OS_STDERR_CAPTURE') == 'True' or
667 os.environ.get('OS_STDERR_CAPTURE') == '1'):
Attila Fazekasf86fa312013-07-30 19:56:39 +0200668 stderr = self.useFixture(fixtures.StringStream('stderr')).stream
669 self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
Attila Fazekas31388072013-08-15 08:58:07 +0200670 if (os.environ.get('OS_LOG_CAPTURE') != 'False' and
Federico Ressi2d6bcaa2018-04-11 12:37:36 +0200671 os.environ.get('OS_LOG_CAPTURE') != '0'):
Attila Fazekas31388072013-08-15 08:58:07 +0200672 self.useFixture(fixtures.LoggerFixture(nuke_handlers=False,
Sean Dague2ef32ac2014-06-09 11:32:23 -0400673 format=self.log_format,
Attila Fazekas90445be2013-10-24 16:46:03 +0200674 level=None))
Ilya Shakhat1291bb42017-11-29 18:08:16 +0100675 if CONF.profiler.key:
676 profiler.enable(CONF.profiler.key)
Matthew Treinish78561ad2013-07-26 11:41:56 -0400677
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100678 @property
679 def credentials_provider(self):
680 return self._get_credentials_provider()
681
682 @classmethod
Andrea Frittoli (andreaf)32d0de12015-10-09 14:43:53 +0100683 def get_identity_version(cls):
684 """Returns the identity version used by the test class"""
685 identity_version = getattr(cls, 'identity_version', None)
686 return identity_version or CONF.identity.auth_version
687
688 @classmethod
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100689 def _get_credentials_provider(cls):
690 """Returns a credentials provider
691
692 If no credential provider exists yet creates one.
Andrea Frittoli9e01dbb2017-04-20 15:28:30 +0100693 It always use the configuration value from identity.auth_version,
694 since we always want to provision accounts with the current version
695 of the identity API.
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100696 """
697 if (not hasattr(cls, '_creds_provider') or not cls._creds_provider or
698 not cls._creds_provider.name == cls.__name__):
699 force_tenant_isolation = getattr(cls, 'force_tenant_isolation',
700 False)
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100701
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700702 cls._creds_provider = credentials.get_credentials_provider(
Andrea Frittolibcbf1af12017-08-14 11:53:35 +0100703 name=cls.__name__, network_resources=cls._network_resources,
Andrea Frittoli9e01dbb2017-04-20 15:28:30 +0100704 force_tenant_isolation=force_tenant_isolation)
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100705 return cls._creds_provider
706
Matthew Treinish3e046852013-07-23 16:00:24 -0400707 @classmethod
Andrea Frittoli (andreaf)41601412015-05-12 16:39:03 +0100708 def get_client_manager(cls, credential_type=None, roles=None,
Ghanshyam Mann2d0da042021-03-05 09:09:30 -0600709 force_new=None, scope=None):
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100710 """Returns an OpenStack client manager
711
712 Returns an OpenStack client manager based on either credential_type
713 or a list of roles. If neither is specified, it defaults to
714 credential_type 'primary'
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100715 :param credential_type: string - primary, alt or admin
716 :param roles: list of roles
Ghanshyam Mann2d0da042021-03-05 09:09:30 -0600717 :param scope: scope for the test user
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100718
lei zhangdd552b22015-11-25 20:41:48 +0800719 :returns: the created client manager
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100720 :raises skipException: if the requested credentials are not available
Ryan Hsu6c4bb3d2013-10-21 21:22:50 -0700721 """
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100722 if all([roles, credential_type]):
723 msg = "Cannot get credentials by type and roles at the same time"
724 raise ValueError(msg)
725 if not any([roles, credential_type]):
726 credential_type = 'primary'
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100727 cred_provider = cls._get_credentials_provider()
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100728 if roles:
729 for role in roles:
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100730 if not cred_provider.is_role_available(role):
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100731 skip_msg = (
732 "%s skipped because the configured credential provider"
733 " is not able to provide credentials with the %s role "
734 "assigned." % (cls.__name__, role))
735 raise cls.skipException(skip_msg)
Ghanshyam Mann2d0da042021-03-05 09:09:30 -0600736 params = dict(roles=roles, scope=scope)
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100737 if force_new is not None:
738 params.update(force_new=force_new)
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100739 creds = cred_provider.get_creds_by_roles(**params)
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000740 else:
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100741 credentials_method = 'get_%s_creds' % credential_type
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100742 if hasattr(cred_provider, credentials_method):
743 creds = getattr(cred_provider, credentials_method)()
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100744 else:
Andrea Frittoli (andreaf)af4f7cf2016-06-13 15:12:26 +0100745 raise lib_exc.InvalidCredentials(
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100746 "Invalid credentials type %s" % credential_type)
Jordan Pittiere4be9072017-01-04 19:17:35 +0100747 manager = cls.client_manager(credentials=creds.credentials)
Andrea Frittoli73224672016-12-09 21:08:19 +0000748 # NOTE(andreaf) Ensure credentials have user and project id fields.
749 # It may not be the case when using pre-provisioned credentials.
750 manager.auth_provider.set_auth()
751 return manager
Ryan Hsu6c4bb3d2013-10-21 21:22:50 -0700752
753 @classmethod
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700754 def clear_credentials(cls):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000755 """Clears creds if set"""
Attila Fazekas5b0d9262015-05-20 10:17:39 +0200756 if hasattr(cls, '_creds_provider'):
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700757 cls._creds_provider.clear_creds()
Ryan Hsu6c4bb3d2013-10-21 21:22:50 -0700758
Andrea Frittoli9f416dd2017-08-10 15:38:00 +0100759 @staticmethod
760 def _validation_resources_params_from_conf():
761 return dict(
762 keypair=(CONF.validation.auth_method.lower() == "keypair"),
763 floating_ip=(CONF.validation.connect_method.lower() == "floating"),
764 security_group=CONF.validation.security_group,
765 security_group_rules=CONF.validation.security_group_rules,
766 use_neutron=CONF.service_available.neutron,
767 ethertype='IPv' + str(CONF.validation.ip_version_for_ssh),
768 floating_network_id=CONF.network.public_network_id,
769 floating_network_name=CONF.network.floating_network_name)
770
Ryan Hsu6c4bb3d2013-10-21 21:22:50 -0700771 @classmethod
Andrea Frittoli9f416dd2017-08-10 15:38:00 +0100772 def get_class_validation_resources(cls, os_clients):
773 """Provision validation resources according to configuration
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000774
Andrea Frittoli9f416dd2017-08-10 15:38:00 +0100775 This is a wrapper around `create_validation_resources` from
776 `tempest.common.validation_resources` that passes parameters from
777 Tempest configuration. Only one instance of class level
778 validation resources is managed by the helper, so If resources
779 were already provisioned before, existing ones will be returned.
nithya-ganesan222efd72015-01-22 12:20:27 +0000780
Andrea Frittoli9f416dd2017-08-10 15:38:00 +0100781 Resources are returned as a dictionary. They are also scheduled for
782 automatic cleanup during class teardown using
783 `addClassResourcesCleanup`.
784
785 If `CONF.validation.run_validation` is False no resource will be
786 provisioned at all.
787
788 @param os_clients: Clients to be used to provision the resources.
nithya-ganesan222efd72015-01-22 12:20:27 +0000789 """
Matthew Treinishe5cca002015-05-11 15:36:50 -0400790 if not CONF.validation.run_validation:
Dan Smith8f9c77b2023-05-01 14:02:46 -0700791 return {}
Jordan Pittier79cd1822016-12-08 17:20:35 +0100792
Andrea Frittoli9f416dd2017-08-10 15:38:00 +0100793 if os_clients in cls._validation_resources:
794 return cls._validation_resources[os_clients]
Jordan Pittier79cd1822016-12-08 17:20:35 +0100795
Andrea Frittoli9f416dd2017-08-10 15:38:00 +0100796 if (CONF.validation.ip_version_for_ssh not in (4, 6) and
797 CONF.service_available.neutron):
798 msg = "Invalid IP version %s in ip_version_for_ssh. Use 4 or 6"
799 raise lib_exc.InvalidConfiguration(
800 msg % CONF.validation.ip_version_for_ssh)
Jordan Pittier79cd1822016-12-08 17:20:35 +0100801
Andrea Frittoli9f416dd2017-08-10 15:38:00 +0100802 resources = vr.create_validation_resources(
803 os_clients,
804 **cls._validation_resources_params_from_conf())
Jordan Pittier79cd1822016-12-08 17:20:35 +0100805
Andrea Frittoli9f416dd2017-08-10 15:38:00 +0100806 cls.addClassResourceCleanup(
807 vr.clear_validation_resources, os_clients,
808 use_neutron=CONF.service_available.neutron,
809 **resources)
810 cls._validation_resources[os_clients] = resources
811 return resources
Brandon Palmc6cc91d2015-08-19 13:20:21 -0500812
Andrea Frittoli9f416dd2017-08-10 15:38:00 +0100813 def get_test_validation_resources(self, os_clients):
814 """Returns a dict of validation resources according to configuration
815
816 Initialise a validation resources fixture based on configuration.
817 Start the fixture and returns the validation resources.
818
819 If `CONF.validation.run_validation` is False no resource will be
820 provisioned at all.
821
822 @param os_clients: Clients to be used to provision the resources.
823 """
824
825 params = {}
826 # Test will try to use the fixture, so for this to be useful
827 # we must return a fixture. If validation is disabled though
828 # we don't need to provision anything, which is the default
829 # behavior for the fixture.
830 if CONF.validation.run_validation:
831 params = self._validation_resources_params_from_conf()
832
833 validation = self.useFixture(
834 vr.ValidationResourcesFixture(os_clients, **params))
835 return validation.resources
nithya-ganesan222efd72015-01-22 12:20:27 +0000836
837 @classmethod
Andrea Frittoli7d5ed592015-02-10 01:10:23 +0000838 def set_network_resources(cls, network=False, router=False, subnet=False,
Matthew Treinish9f756a02014-01-15 10:26:07 -0500839 dhcp=False):
840 """Specify which network resources should be created
841
Andrea Frittolibcbf1af12017-08-14 11:53:35 +0100842 The dynamic credentials provider by default provisions network
843 resources for each user/project that is provisioned. This behavior
844 can be altered using this method, which allows tests to define which
845 specific network resources to be provisioned - none if no parameter
846 is specified.
847
Andrea Frittolia6c885a2017-08-23 19:37:50 +0100848 This method is designed so that only the network resources set on the
849 leaf class are honoured.
850
Andrea Frittolibcbf1af12017-08-14 11:53:35 +0100851 Credentials are provisioned as part of the class setup fixture,
852 during the `setup_credentials` step. For this to be effective this
853 helper must be invoked before super's `setup_credentials` is executed.
854
Matthew Treinish9f756a02014-01-15 10:26:07 -0500855 @param network
856 @param router
857 @param subnet
858 @param dhcp
Andrea Frittolibcbf1af12017-08-14 11:53:35 +0100859
860 Example::
861
862 @classmethod
863 def setup_credentials(cls):
864 # Do not setup network resources for this test
865 cls.set_network_resources()
866 super(MyTest, cls).setup_credentials()
Matthew Treinish9f756a02014-01-15 10:26:07 -0500867 """
Andrea Frittolibcbf1af12017-08-14 11:53:35 +0100868 # If this is invoked after the credentials are setup, it won't take
869 # any effect. To avoid this situation, fail the test in case this was
870 # invoked too late in the test lifecycle.
871 if cls.__setup_credentials_called:
872 raise RuntimeError(
873 "set_network_resources invoked after setup_credentials on the "
874 "super class has been already invoked. For "
875 "set_network_resources to have effect please invoke it before "
876 "the call to super().setup_credentials")
877
878 # Network resources should be set only once from callers
Salvatore Orlando5a337242014-01-15 22:49:22 +0000879 # in order to ensure that even if it's called multiple times in
880 # a chain of overloaded methods, the attribute is set only
Andrea Frittolibcbf1af12017-08-14 11:53:35 +0100881 # in the leaf class.
882 if not cls._network_resources:
883 cls._network_resources = {
Salvatore Orlando5a337242014-01-15 22:49:22 +0000884 'network': network,
885 'router': router,
886 'subnet': subnet,
887 'dhcp': dhcp}
Matthew Treinish9f756a02014-01-15 10:26:07 -0500888
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530889 @classmethod
Ryan Rossiter9228bf72016-02-25 03:06:12 +0000890 def get_tenant_network(cls, credentials_type='primary'):
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530891 """Get the network to be used in testing
892
Ryan Rossiter9228bf72016-02-25 03:06:12 +0000893 :param credentials_type: The type of credentials for which to get the
894 tenant network
895
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530896 :return: network dict including 'id' and 'name'
897 """
Ryan Rossiter9228bf72016-02-25 03:06:12 +0000898 # Get a manager for the given credentials_type, but at least
899 # always fall back on getting the manager for primary credentials
songwenpinga6ee2d12021-02-22 10:24:16 +0800900 if isinstance(credentials_type, str):
Ryan Rossiter9228bf72016-02-25 03:06:12 +0000901 manager = cls.get_client_manager(credential_type=credentials_type)
902 elif isinstance(credentials_type, list):
Ghanshyam Mann2d0da042021-03-05 09:09:30 -0600903 scope = 'project'
904 if credentials_type[0].startswith('system'):
905 scope = 'system'
906 elif credentials_type[0].startswith('domain'):
907 scope = 'domain'
908 manager = cls.get_client_manager(roles=credentials_type[1:],
909 scope=scope)
Ryan Rossiter9228bf72016-02-25 03:06:12 +0000910 else:
911 manager = cls.get_client_manager()
912
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700913 # Make sure cred_provider exists and get a network client
zhufl33289a22018-01-04 15:02:00 +0800914 networks_client = manager.networks_client
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100915 cred_provider = cls._get_credentials_provider()
Andrea Frittoli700711e2015-04-02 11:39:38 +0100916 # In case of nova network, isolated tenants are not able to list the
Joshua Whitebd769602016-02-02 09:30:11 -0800917 # network configured in fixed_network_name, even if they can use it
Andrea Frittoli700711e2015-04-02 11:39:38 +0100918 # for their servers, so using an admin network client to validate
919 # the network name
920 if (not CONF.service_available.neutron and
Andrea Frittoli (andreaf)32d0de12015-10-09 14:43:53 +0100921 credentials.is_admin_available(
922 identity_version=cls.get_identity_version())):
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100923 admin_creds = cred_provider.get_admin_creds()
Andrea Frittoli (andreaf)848c4a12016-06-09 11:09:02 +0100924 admin_manager = clients.Manager(admin_creds.credentials)
John Warren9487a182015-09-14 18:12:56 -0400925 networks_client = admin_manager.compute_networks_client
Andrea Frittoli (andreaf)940f8c62015-10-30 16:39:24 +0900926 return fixed_network.get_tenant_network(
927 cred_provider, networks_client, CONF.compute.fixed_network_name)
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530928
Andrea Frittoli71c71e92017-04-07 17:45:21 +0100929 def assertEmpty(self, items, msg=None):
930 """Asserts whether a sequence or collection is empty
Mark Maglana5885eb32014-02-28 10:57:34 -0800931
Andrea Frittoli71c71e92017-04-07 17:45:21 +0100932 :param items: sequence or collection to be tested
933 :param msg: message to be passed to the AssertionError
934 :raises AssertionError: when items is not empty
935 """
zhufl92ade4b2017-03-03 15:20:10 +0800936 if msg is None:
Andrea Frittoli71c71e92017-04-07 17:45:21 +0100937 msg = "sequence or collection is not empty: %s" % items
Masayuki Igawa0c0f0142017-04-10 17:22:02 +0900938 self.assertFalse(items, msg)
Andrea Frittoli71c71e92017-04-07 17:45:21 +0100939
940 def assertNotEmpty(self, items, msg=None):
941 """Asserts whether a sequence or collection is not empty
942
943 :param items: sequence or collection to be tested
944 :param msg: message to be passed to the AssertionError
945 :raises AssertionError: when items is empty
946 """
947 if msg is None:
948 msg = "sequence or collection is empty."
Masayuki Igawa0c0f0142017-04-10 17:22:02 +0900949 self.assertTrue(items, msg)