blob: 00f99d7c0aff150d06c717f19c48297d8b046f02 [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
Masayuki Igawa80c1b9f2013-10-07 17:19:11 +090017import functools
Ian Wienand98c35f32013-07-23 20:34:23 +100018import os
Attila Fazekas53943322014-02-10 16:07:34 +010019import sys
Jay Pipes051075a2012-04-28 17:39:37 -040020
Jordan Pittier35a63752016-08-30 13:09:12 +020021import debtcollector.moves
Matthew Treinish78561ad2013-07-26 11:41:56 -040022import fixtures
Doug Hellmann583ce2c2015-03-11 14:55:46 +000023from oslo_log import log as logging
Chris Hoge296558c2015-02-19 00:29:49 -060024import six
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
nithya-ganesan222efd72015-01-22 12:20:27 +000029import tempest.common.validation_resources as vresources
Attila Fazekasdc216422013-01-29 15:12:14 +010030from tempest import config
Matthew Treinish3787e4c2016-10-07 21:25:33 -040031from tempest.lib.common import cred_client
Matthew Treinishb19c55d2017-07-17 12:38:35 -040032from tempest.lib.common import fixed_network
Andrea Frittoli (andreaf)db9672e2016-02-23 14:07:24 -050033from tempest.lib import decorators
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
Ken'ichi Ohmichi44f01272017-01-27 18:44:14 -080040# TODO(oomichi): This test.idempotent_id should be removed after all projects
41# switch to use decorators.idempotent_id.
42idempotent_id = debtcollector.moves.moved_function(
43 decorators.idempotent_id, 'idempotent_id', __name__,
44 version='Mitaka', removal_version='?')
Matthew Treinishc1802bc2015-12-03 18:48:11 -050045
Jay Pipes051075a2012-04-28 17:39:37 -040046
Jordan Pittier3b46d272017-04-12 16:17:28 +020047attr = debtcollector.moves.moved_function(
48 decorators.attr, 'attr', __name__,
49 version='Pike', removal_version='?')
Chris Yeoh55530bb2013-02-08 16:04:27 +103050
51
Andrea Frittoli07acf262017-04-09 19:36:37 +020052class InvalidServiceTag(lib_exc.TempestException):
53 message = "Invalid service tag"
54
55
Matthew Treinish3d8c7322014-08-03 23:53:28 -040056def get_service_list():
Matthew Treinish8afbffd2014-01-21 23:56:13 +000057 service_list = {
58 'compute': CONF.service_available.nova,
59 'image': CONF.service_available.glance,
60 'volume': CONF.service_available.cinder,
Masayuki Igawa9012ba32017-06-09 15:28:59 +090061 # NOTE(masayukig): We have two network services which are neutron and
62 # nova-network. And we have no way to know whether nova-network is
63 # available or not. After the pending removal of nova-network from
64 # nova, we can treat the network/neutron case in the same manner as
65 # the other services.
Matthew Treinish8afbffd2014-01-21 23:56:13 +000066 'network': True,
Masayuki Igawa9012ba32017-06-09 15:28:59 +090067 # NOTE(masayukig): Tempest tests always require the identity service.
68 # So we should set this True here.
Matthew Treinish8afbffd2014-01-21 23:56:13 +000069 'identity': True,
70 'object_storage': CONF.service_available.swift,
Matthew Treinish8afbffd2014-01-21 23:56:13 +000071 }
Matthew Treinish3d8c7322014-08-03 23:53:28 -040072 return service_list
Matthew Treinish16c43792013-09-09 19:55:23 +000073
Matthew Treinish3d8c7322014-08-03 23:53:28 -040074
Yaroslav Lobankovda999f72015-06-30 20:32:55 +030075def services(*args):
Matthew Treinish3d8c7322014-08-03 23:53:28 -040076 """A decorator used to set an attr for each service used in a test case
77
78 This decorator applies a testtools attr for each service that gets
79 exercised by a test case.
80 """
Matthew Treinish16c43792013-09-09 19:55:23 +000081 def decorator(f):
Andrea Frittoli6f053072017-04-09 19:22:47 +020082 known_services = get_service_list()
83
Matthew Treinish16c43792013-09-09 19:55:23 +000084 for service in args:
Andrea Frittoli6f053072017-04-09 19:22:47 +020085 if service not in known_services:
Andrea Frittoli07acf262017-04-09 19:36:37 +020086 raise InvalidServiceTag('%s is not a valid service' % service)
Jordan Pittier3b46d272017-04-12 16:17:28 +020087 decorators.attr(type=list(args))(f)
Matthew Treinish8afbffd2014-01-21 23:56:13 +000088
89 @functools.wraps(f)
90 def wrapper(self, *func_args, **func_kwargs):
Matthew Treinish3d8c7322014-08-03 23:53:28 -040091 service_list = get_service_list()
92
Matthew Treinish8afbffd2014-01-21 23:56:13 +000093 for service in args:
94 if not service_list[service]:
95 msg = 'Skipped because the %s service is not available' % (
96 service)
97 raise testtools.TestCase.skipException(msg)
98 return f(self, *func_args, **func_kwargs)
99 return wrapper
Matthew Treinish16c43792013-09-09 19:55:23 +0000100 return decorator
101
102
Yaroslav Lobankovda999f72015-06-30 20:32:55 +0300103def requires_ext(**kwargs):
Matthew Treinishe3d26142013-11-26 19:14:58 +0000104 """A decorator to skip tests if an extension is not enabled
105
106 @param extension
107 @param service
108 """
109 def decorator(func):
110 @functools.wraps(func)
111 def wrapper(*func_args, **func_kwargs):
112 if not is_extension_enabled(kwargs['extension'],
113 kwargs['service']):
114 msg = "Skipped because %s extension: %s is not enabled" % (
115 kwargs['service'], kwargs['extension'])
116 raise testtools.TestCase.skipException(msg)
117 return func(*func_args, **func_kwargs)
118 return wrapper
119 return decorator
120
121
122def is_extension_enabled(extension_name, service):
123 """A function that will check the list of enabled extensions from config
124
125 """
Matthew Treinishe3d26142013-11-26 19:14:58 +0000126 config_dict = {
Matthew Treinishbc0e03e2014-01-30 16:51:06 +0000127 'compute': CONF.compute_feature_enabled.api_extensions,
Matthew Treinishbc0e03e2014-01-30 16:51:06 +0000128 'volume': CONF.volume_feature_enabled.api_extensions,
129 'network': CONF.network_feature_enabled.api_extensions,
130 'object': CONF.object_storage_feature_enabled.discoverable_apis,
Jane Zadorozhna121576d2015-06-23 12:57:13 +0300131 'identity': CONF.identity_feature_enabled.api_extensions
Matthew Treinishe3d26142013-11-26 19:14:58 +0000132 }
Masayuki Igawa0c0f0142017-04-10 17:22:02 +0900133 if not config_dict[service]:
Simeon Monov5d7effe2014-07-16 07:32:38 +0300134 return False
Matthew Treinishe3d26142013-11-26 19:14:58 +0000135 if config_dict[service][0] == 'all':
136 return True
137 if extension_name in config_dict[service]:
138 return True
139 return False
140
Ian Wienand98c35f32013-07-23 20:34:23 +1000141
Attila Fazekasf86fa312013-07-30 19:56:39 +0200142at_exit_set = set()
143
144
145def validate_tearDownClass():
146 if at_exit_set:
Sean Dagueeb1523b2014-03-10 10:17:44 -0400147 LOG.error(
148 "tearDownClass does not call the super's "
149 "tearDownClass in these classes: \n"
150 + str(at_exit_set))
151
Attila Fazekasf86fa312013-07-30 19:56:39 +0200152
153atexit.register(validate_tearDownClass)
154
Attila Fazekas53943322014-02-10 16:07:34 +0100155
Matthew Treinish2474f412014-11-17 18:11:56 -0500156class BaseTestCase(testtools.testcase.WithAttributes,
157 testtools.TestCase):
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100158 """The test base class defines Tempest framework for class level fixtures.
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000159
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100160 `setUpClass` and `tearDownClass` are defined here and cannot be overwritten
161 by subclasses (enforced via hacking rule T105).
162
163 Set-up is split in a series of steps (setup stages), which can be
164 overwritten by test classes. Set-up stages are:
165 - skip_checks
166 - setup_credentials
167 - setup_clients
168 - resource_setup
169
170 Tear-down is also split in a series of steps (teardown stages), which are
171 stacked for execution only if the corresponding setup stage had been
172 reached during the setup phase. Tear-down stages are:
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700173 - clear_credentials (defined in the base test class)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100174 - resource_cleanup
175 """
Attila Fazekasc43fec82013-04-09 23:17:52 +0200176
Attila Fazekasf86fa312013-07-30 19:56:39 +0200177 setUpClassCalled = False
178
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000179 # NOTE(andreaf) credentials holds a list of the credentials to be allocated
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100180 # at class setup time. Credential types can be 'primary', 'alt', 'admin' or
181 # a list of roles - the first element of the list being a label, and the
182 # rest the actual roles
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000183 credentials = []
nithya-ganesan222efd72015-01-22 12:20:27 +0000184 # Resources required to validate a server using ssh
185 validation_resources = {}
Matthew Treinish9f756a02014-01-15 10:26:07 -0500186 network_resources = {}
187
Sean Dague2ef32ac2014-06-09 11:32:23 -0400188 # NOTE(sdague): log_format is defined inline here instead of using the oslo
189 # default because going through the config path recouples config to the
190 # stress tests too early, and depending on testr order will fail unit tests
191 log_format = ('%(asctime)s %(process)d %(levelname)-8s '
192 '[%(name)s] %(message)s')
193
Ryota MIBU60687e52015-12-09 18:37:39 +0900194 # Client manager class to use in this test case.
195 client_manager = clients.Manager
196
Sean Dague02620fd2016-03-02 15:52:51 -0500197 # A way to adjust slow test classes
198 TIMEOUT_SCALING_FACTOR = 1
199
Pavel Sedlák1053bd32013-04-16 16:47:40 +0200200 @classmethod
201 def setUpClass(cls):
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100202 # It should never be overridden by descendants
Pavel Sedlák1053bd32013-04-16 16:47:40 +0200203 if hasattr(super(BaseTestCase, cls), 'setUpClass'):
204 super(BaseTestCase, cls).setUpClass()
Attila Fazekasf86fa312013-07-30 19:56:39 +0200205 cls.setUpClassCalled = True
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100206 # Stack of (name, callable) to be invoked in reverse order at teardown
207 cls.teardowns = []
208 # All the configuration checks that may generate a skip
209 cls.skip_checks()
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100210 try:
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100211 # Allocation of all required credentials and client managers
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700212 cls.teardowns.append(('credentials', cls.clear_credentials))
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100213 cls.setup_credentials()
214 # Shortcuts to clients
215 cls.setup_clients()
216 # Additional class-wide test resources
217 cls.teardowns.append(('resources', cls.resource_cleanup))
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100218 cls.resource_setup()
219 except Exception:
220 etype, value, trace = sys.exc_info()
Jordan Pittier525ec712016-12-07 17:51:26 +0100221 LOG.info("%s raised in %s.setUpClass. Invoking tearDownClass.",
222 etype, cls.__name__)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100223 cls.tearDownClass()
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100224 try:
Matthew Treinish843227d2015-04-23 10:17:17 -0400225 six.reraise(etype, value, trace)
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100226 finally:
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100227 del trace # to avoid circular refs
Pavel Sedlák1053bd32013-04-16 16:47:40 +0200228
Attila Fazekasf86fa312013-07-30 19:56:39 +0200229 @classmethod
230 def tearDownClass(cls):
Martin Kopecae155b72017-06-26 09:41:21 +0000231 # insert pdb breakpoint when pause_teardown is enabled
232 if CONF.pause_teardown:
233 cls.insert_pdb_breakpoint()
Attila Fazekas5d275302013-08-29 12:35:12 +0200234 at_exit_set.discard(cls)
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100235 # It should never be overridden by descendants
Attila Fazekasf86fa312013-07-30 19:56:39 +0200236 if hasattr(super(BaseTestCase, cls), 'tearDownClass'):
237 super(BaseTestCase, cls).tearDownClass()
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100238 # Save any existing exception, we always want to re-raise the original
239 # exception only
240 etype, value, trace = sys.exc_info()
241 # If there was no exception during setup we shall re-raise the first
242 # exception in teardown
243 re_raise = (etype is None)
244 while cls.teardowns:
245 name, teardown = cls.teardowns.pop()
246 # Catch any exception in tearDown so we can re-raise the original
247 # exception at the end
248 try:
249 teardown()
250 except Exception as te:
251 sys_exec_info = sys.exc_info()
252 tetype = sys_exec_info[0]
253 # TODO(andreaf): Till we have the ability to cleanup only
254 # resources that were successfully setup in resource_cleanup,
255 # log AttributeError as info instead of exception.
256 if tetype is AttributeError and name == 'resources':
Jordan Pittier525ec712016-12-07 17:51:26 +0100257 LOG.info("tearDownClass of %s failed: %s", name, te)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100258 else:
Jordan Pittier525ec712016-12-07 17:51:26 +0100259 LOG.exception("teardown of %s failed: %s", name, te)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100260 if not etype:
261 etype, value, trace = sys_exec_info
Joshua Whitebd769602016-02-02 09:30:11 -0800262 # If exceptions were raised during teardown, and not before, re-raise
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100263 # the first one
264 if re_raise and etype is not None:
265 try:
Matthew Treinish843227d2015-04-23 10:17:17 -0400266 six.reraise(etype, value, trace)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100267 finally:
268 del trace # to avoid circular refs
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100269
Martin Kopecae155b72017-06-26 09:41:21 +0000270 def tearDown(self):
271 super(BaseTestCase, self).tearDown()
272 # insert pdb breakpoint when pause_teardown is enabled
273 if CONF.pause_teardown:
274 BaseTestCase.insert_pdb_breakpoint()
275
276 @classmethod
277 def insert_pdb_breakpoint(cls):
278 """Add pdb breakpoint.
279
280 This can help in debugging process, cleaning of resources is
281 paused, so they can be examined.
282 """
283 import pdb
284 pdb.set_trace()
285
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100286 @classmethod
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100287 def skip_checks(cls):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000288 """Class level skip checks.
289
290 Subclasses verify in here all conditions that might prevent the
291 execution of the entire test class.
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100292 Checks implemented here may not make use API calls, and should rely on
293 configuration alone.
294 In general skip checks that require an API call are discouraged.
295 If one is really needed it may be implemented either in the
296 resource_setup or at test level.
297 """
Andrea Frittoli (andreaf)32d0de12015-10-09 14:43:53 +0100298 identity_version = cls.get_identity_version()
299 if 'admin' in cls.credentials and not credentials.is_admin_available(
300 identity_version=identity_version):
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000301 msg = "Missing Identity Admin API credentials in configuration."
302 raise cls.skipException(msg)
Andrea Frittoli (andreaf)32d0de12015-10-09 14:43:53 +0100303 if 'alt' in cls.credentials and not credentials.is_alt_available(
304 identity_version=identity_version):
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000305 msg = "Missing a 2nd set of API credentials in configuration."
306 raise cls.skipException(msg)
Andrea Frittoli (andreaf)41601412015-05-12 16:39:03 +0100307 if hasattr(cls, 'identity_version'):
308 if cls.identity_version == 'v2':
309 if not CONF.identity_feature_enabled.api_v2:
310 raise cls.skipException("Identity api v2 is not enabled")
311 elif cls.identity_version == 'v3':
312 if not CONF.identity_feature_enabled.api_v3:
313 raise cls.skipException("Identity api v3 is not enabled")
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100314
315 @classmethod
316 def setup_credentials(cls):
edannon6cc6fbc2016-05-03 11:56:12 +0300317 """Allocate credentials and create the client managers from them.
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000318
edannon6cc6fbc2016-05-03 11:56:12 +0300319 For every element of credentials param function creates tenant/user,
320 Then it creates client manager for that credential.
321
322 Network related tests must override this function with
323 set_network_resources() method, otherwise it will create
324 network resources(network resources are created in a later step).
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000325 """
326 for credentials_type in cls.credentials:
327 # This may raise an exception in case credentials are not available
328 # In that case we want to let the exception through and the test
329 # fail accordingly
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100330 if isinstance(credentials_type, six.string_types):
331 manager = cls.get_client_manager(
332 credential_type=credentials_type)
333 setattr(cls, 'os_%s' % credentials_type, manager)
Jordan Pittier8160d312017-04-18 11:52:23 +0200334 # NOTE(jordanP): Tempest should use os_primary, os_admin
335 # and os_alt throughout its code base but we keep the aliases
336 # around for a while for Tempest plugins. Aliases should be
337 # removed eventually.
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100338 # Setup some common aliases
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100339 if credentials_type == 'primary':
Jordan Pittier8160d312017-04-18 11:52:23 +0200340 cls.os = debtcollector.moves.moved_read_only_property(
341 'os', 'os_primary', version='Pike',
Jakub Libosvar7835ca12017-05-04 16:44:23 +0200342 removal_version='Queens')
Jordan Pittier8160d312017-04-18 11:52:23 +0200343 cls.manager =\
344 debtcollector.moves.moved_read_only_property(
345 'manager', 'os_primary', version='Pike',
Jakub Libosvar7835ca12017-05-04 16:44:23 +0200346 removal_version='Queens')
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100347 if credentials_type == 'admin':
Jordan Pittier8160d312017-04-18 11:52:23 +0200348 cls.os_adm = debtcollector.moves.moved_read_only_property(
349 'os_adm', 'os_admin', version='Pike',
Jakub Libosvar7835ca12017-05-04 16:44:23 +0200350 removal_version='Queens')
Jordan Pittier8160d312017-04-18 11:52:23 +0200351 cls.admin_manager =\
352 debtcollector.moves.moved_read_only_property(
353 'admin_manager', 'os_admin', version='Pike',
Jakub Libosvar7835ca12017-05-04 16:44:23 +0200354 removal_version='Queens')
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100355 if credentials_type == 'alt':
Jordan Pittier8160d312017-04-18 11:52:23 +0200356 cls.alt_manager =\
357 debtcollector.moves.moved_read_only_property(
358 'alt_manager', 'os_alt', version='Pike',
Jakub Libosvar7835ca12017-05-04 16:44:23 +0200359 removal_version='Queens')
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100360 elif isinstance(credentials_type, list):
361 manager = cls.get_client_manager(roles=credentials_type[1:],
362 force_new=True)
363 setattr(cls, 'os_roles_%s' % credentials_type[0], manager)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100364
365 @classmethod
366 def setup_clients(cls):
367 """Create links to the clients into the test object."""
368 # TODO(andreaf) There is a fair amount of code that could me moved from
369 # base / test classes in here. Ideally tests should be able to only
370 # specify which client is `client` and nothing else.
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100371 pass
Attila Fazekasf86fa312013-07-30 19:56:39 +0200372
Emily Hugenbruch5bd4cbf2014-12-17 21:38:38 +0000373 @classmethod
374 def resource_setup(cls):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000375 """Class level resource setup for test cases."""
Andrea Frittolicf999a82017-05-24 10:44:46 +0100376 if hasattr(cls, "os_primary"):
nithya-ganesan222efd72015-01-22 12:20:27 +0000377 cls.validation_resources = vresources.create_validation_resources(
Andrea Frittolicf999a82017-05-24 10:44:46 +0100378 cls.os_primary, cls.validation_resources)
nithya-ganesan222efd72015-01-22 12:20:27 +0000379 else:
zhangguoqing6c096642016-01-04 06:17:21 +0000380 LOG.warning("Client manager not found, validation resources not"
381 " created")
Emily Hugenbruch5bd4cbf2014-12-17 21:38:38 +0000382
383 @classmethod
384 def resource_cleanup(cls):
385 """Class level resource cleanup for test cases.
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000386
Emily Hugenbruch5bd4cbf2014-12-17 21:38:38 +0000387 Resource cleanup must be able to handle the case of partially setup
388 resources, in case a failure during `resource_setup` should happen.
389 """
nithya-ganesan222efd72015-01-22 12:20:27 +0000390 if cls.validation_resources:
Andrea Frittolicf999a82017-05-24 10:44:46 +0100391 if hasattr(cls, "os_primary"):
392 vresources.clear_validation_resources(cls.os_primary,
nithya-ganesan222efd72015-01-22 12:20:27 +0000393 cls.validation_resources)
394 cls.validation_resources = {}
395 else:
zhangguoqing6c096642016-01-04 06:17:21 +0000396 LOG.warning("Client manager not found, validation resources "
397 "not deleted")
Emily Hugenbruch5bd4cbf2014-12-17 21:38:38 +0000398
Attila Fazekasf86fa312013-07-30 19:56:39 +0200399 def setUp(self):
400 super(BaseTestCase, self).setUp()
401 if not self.setUpClassCalled:
402 raise RuntimeError("setUpClass does not calls the super's"
403 "setUpClass in the "
404 + self.__class__.__name__)
405 at_exit_set.add(self.__class__)
Matthew Treinish78561ad2013-07-26 11:41:56 -0400406 test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0)
407 try:
Sean Dague02620fd2016-03-02 15:52:51 -0500408 test_timeout = int(test_timeout) * self.TIMEOUT_SCALING_FACTOR
Matthew Treinish78561ad2013-07-26 11:41:56 -0400409 except ValueError:
410 test_timeout = 0
411 if test_timeout > 0:
Attila Fazekasf86fa312013-07-30 19:56:39 +0200412 self.useFixture(fixtures.Timeout(test_timeout, gentle=True))
Matthew Treinish78561ad2013-07-26 11:41:56 -0400413
414 if (os.environ.get('OS_STDOUT_CAPTURE') == 'True' or
415 os.environ.get('OS_STDOUT_CAPTURE') == '1'):
Attila Fazekasf86fa312013-07-30 19:56:39 +0200416 stdout = self.useFixture(fixtures.StringStream('stdout')).stream
417 self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
Matthew Treinish78561ad2013-07-26 11:41:56 -0400418 if (os.environ.get('OS_STDERR_CAPTURE') == 'True' or
419 os.environ.get('OS_STDERR_CAPTURE') == '1'):
Attila Fazekasf86fa312013-07-30 19:56:39 +0200420 stderr = self.useFixture(fixtures.StringStream('stderr')).stream
421 self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
Attila Fazekas31388072013-08-15 08:58:07 +0200422 if (os.environ.get('OS_LOG_CAPTURE') != 'False' and
423 os.environ.get('OS_LOG_CAPTURE') != '0'):
Attila Fazekas31388072013-08-15 08:58:07 +0200424 self.useFixture(fixtures.LoggerFixture(nuke_handlers=False,
Sean Dague2ef32ac2014-06-09 11:32:23 -0400425 format=self.log_format,
Attila Fazekas90445be2013-10-24 16:46:03 +0200426 level=None))
Matthew Treinish78561ad2013-07-26 11:41:56 -0400427
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100428 @property
429 def credentials_provider(self):
430 return self._get_credentials_provider()
431
Jamie Lennox15350172015-08-17 10:54:25 +1000432 @property
433 def identity_utils(self):
434 """A client that abstracts v2 and v3 identity operations.
435
436 This can be used for creating and tearing down projects in tests. It
437 should not be used for testing identity features.
438 """
439 if CONF.identity.auth_version == 'v2':
440 client = self.os_admin.identity_client
Daniel Mellado7aea5342016-02-09 09:10:12 +0000441 users_client = self.os_admin.users_client
Daniel Melladob04da902015-11-20 17:43:12 +0100442 project_client = self.os_admin.tenants_client
Daniel Mellado6b16b922015-12-07 12:43:08 +0000443 roles_client = self.os_admin.roles_client
Daniel Mellado91a26b62016-02-11 11:13:04 +0000444 domains_client = None
Jamie Lennox15350172015-08-17 10:54:25 +1000445 else:
446 client = self.os_admin.identity_v3_client
Daniel Mellado7aea5342016-02-09 09:10:12 +0000447 users_client = self.os_admin.users_v3_client
Arx Cruz24bcb882016-02-10 15:20:16 +0100448 project_client = self.os_admin.projects_client
449 roles_client = self.os_admin.roles_v3_client
Daniel Mellado91a26b62016-02-11 11:13:04 +0000450 domains_client = self.os_admin.domains_client
Jamie Lennox15350172015-08-17 10:54:25 +1000451
452 try:
453 domain = client.auth_provider.credentials.project_domain_name
454 except AttributeError:
455 domain = 'Default'
456
Daniel Melladob04da902015-11-20 17:43:12 +0100457 return cred_client.get_creds_client(client, project_client,
Daniel Mellado82c83a52015-12-09 15:16:49 +0000458 users_client,
Daniel Mellado7aea5342016-02-09 09:10:12 +0000459 roles_client,
Daniel Mellado91a26b62016-02-11 11:13:04 +0000460 domains_client,
Daniel Melladob04da902015-11-20 17:43:12 +0100461 project_domain_name=domain)
Jamie Lennox15350172015-08-17 10:54:25 +1000462
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100463 @classmethod
Andrea Frittoli (andreaf)32d0de12015-10-09 14:43:53 +0100464 def get_identity_version(cls):
465 """Returns the identity version used by the test class"""
466 identity_version = getattr(cls, 'identity_version', None)
467 return identity_version or CONF.identity.auth_version
468
469 @classmethod
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100470 def _get_credentials_provider(cls):
471 """Returns a credentials provider
472
473 If no credential provider exists yet creates one.
Andrea Frittoli9e01dbb2017-04-20 15:28:30 +0100474 It always use the configuration value from identity.auth_version,
475 since we always want to provision accounts with the current version
476 of the identity API.
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100477 """
478 if (not hasattr(cls, '_creds_provider') or not cls._creds_provider or
479 not cls._creds_provider.name == cls.__name__):
480 force_tenant_isolation = getattr(cls, 'force_tenant_isolation',
481 False)
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100482
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700483 cls._creds_provider = credentials.get_credentials_provider(
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100484 name=cls.__name__, network_resources=cls.network_resources,
Andrea Frittoli9e01dbb2017-04-20 15:28:30 +0100485 force_tenant_isolation=force_tenant_isolation)
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100486 return cls._creds_provider
487
Matthew Treinish3e046852013-07-23 16:00:24 -0400488 @classmethod
Andrea Frittoli (andreaf)41601412015-05-12 16:39:03 +0100489 def get_client_manager(cls, credential_type=None, roles=None,
490 force_new=None):
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100491 """Returns an OpenStack client manager
492
493 Returns an OpenStack client manager based on either credential_type
494 or a list of roles. If neither is specified, it defaults to
495 credential_type 'primary'
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100496 :param credential_type: string - primary, alt or admin
497 :param roles: list of roles
498
lei zhangdd552b22015-11-25 20:41:48 +0800499 :returns: the created client manager
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100500 :raises skipException: if the requested credentials are not available
Ryan Hsu6c4bb3d2013-10-21 21:22:50 -0700501 """
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100502 if all([roles, credential_type]):
503 msg = "Cannot get credentials by type and roles at the same time"
504 raise ValueError(msg)
505 if not any([roles, credential_type]):
506 credential_type = 'primary'
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100507 cred_provider = cls._get_credentials_provider()
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100508 if roles:
509 for role in roles:
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100510 if not cred_provider.is_role_available(role):
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100511 skip_msg = (
512 "%s skipped because the configured credential provider"
513 " is not able to provide credentials with the %s role "
514 "assigned." % (cls.__name__, role))
515 raise cls.skipException(skip_msg)
516 params = dict(roles=roles)
517 if force_new is not None:
518 params.update(force_new=force_new)
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100519 creds = cred_provider.get_creds_by_roles(**params)
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000520 else:
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100521 credentials_method = 'get_%s_creds' % credential_type
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100522 if hasattr(cred_provider, credentials_method):
523 creds = getattr(cred_provider, credentials_method)()
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100524 else:
Andrea Frittoli (andreaf)af4f7cf2016-06-13 15:12:26 +0100525 raise lib_exc.InvalidCredentials(
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100526 "Invalid credentials type %s" % credential_type)
Jordan Pittiere4be9072017-01-04 19:17:35 +0100527 manager = cls.client_manager(credentials=creds.credentials)
Andrea Frittoli73224672016-12-09 21:08:19 +0000528 # NOTE(andreaf) Ensure credentials have user and project id fields.
529 # It may not be the case when using pre-provisioned credentials.
530 manager.auth_provider.set_auth()
531 return manager
Ryan Hsu6c4bb3d2013-10-21 21:22:50 -0700532
533 @classmethod
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700534 def clear_credentials(cls):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000535 """Clears creds if set"""
Attila Fazekas5b0d9262015-05-20 10:17:39 +0200536 if hasattr(cls, '_creds_provider'):
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700537 cls._creds_provider.clear_creds()
Ryan Hsu6c4bb3d2013-10-21 21:22:50 -0700538
539 @classmethod
nithya-ganesan222efd72015-01-22 12:20:27 +0000540 def set_validation_resources(cls, keypair=None, floating_ip=None,
541 security_group=None,
542 security_group_rules=None):
543 """Specify which ssh server validation resources should be created.
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000544
nithya-ganesan222efd72015-01-22 12:20:27 +0000545 Each of the argument must be set to either None, True or False, with
546 None - use default from config (security groups and security group
547 rules get created when set to None)
548 False - Do not create the validation resource
549 True - create the validation resource
550
551 @param keypair
552 @param security_group
553 @param security_group_rules
554 @param floating_ip
555 """
Matthew Treinishe5cca002015-05-11 15:36:50 -0400556 if not CONF.validation.run_validation:
557 return
Jordan Pittier79cd1822016-12-08 17:20:35 +0100558
nithya-ganesan222efd72015-01-22 12:20:27 +0000559 if keypair is None:
Jordan Pittier79cd1822016-12-08 17:20:35 +0100560 keypair = (CONF.validation.auth_method.lower() == "keypair")
561
nithya-ganesan222efd72015-01-22 12:20:27 +0000562 if floating_ip is None:
Jordan Pittier79cd1822016-12-08 17:20:35 +0100563 floating_ip = (CONF.validation.connect_method.lower() ==
564 "floating")
565
nithya-ganesan222efd72015-01-22 12:20:27 +0000566 if security_group is None:
Brandon Palmc6cc91d2015-08-19 13:20:21 -0500567 security_group = CONF.validation.security_group
Jordan Pittier79cd1822016-12-08 17:20:35 +0100568
nithya-ganesan222efd72015-01-22 12:20:27 +0000569 if security_group_rules is None:
Brandon Palmc6cc91d2015-08-19 13:20:21 -0500570 security_group_rules = CONF.validation.security_group_rules
571
nithya-ganesan222efd72015-01-22 12:20:27 +0000572 if not cls.validation_resources:
573 cls.validation_resources = {
574 'keypair': keypair,
575 'security_group': security_group,
576 'security_group_rules': security_group_rules,
577 'floating_ip': floating_ip}
578
579 @classmethod
Andrea Frittoli7d5ed592015-02-10 01:10:23 +0000580 def set_network_resources(cls, network=False, router=False, subnet=False,
Matthew Treinish9f756a02014-01-15 10:26:07 -0500581 dhcp=False):
582 """Specify which network resources should be created
583
584 @param network
585 @param router
586 @param subnet
587 @param dhcp
588 """
Salvatore Orlando5a337242014-01-15 22:49:22 +0000589 # network resources should be set only once from callers
590 # in order to ensure that even if it's called multiple times in
591 # a chain of overloaded methods, the attribute is set only
592 # in the leaf class
Andrea Frittoli7d5ed592015-02-10 01:10:23 +0000593 if not cls.network_resources:
594 cls.network_resources = {
Salvatore Orlando5a337242014-01-15 22:49:22 +0000595 'network': network,
596 'router': router,
597 'subnet': subnet,
598 'dhcp': dhcp}
Matthew Treinish9f756a02014-01-15 10:26:07 -0500599
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530600 @classmethod
Ryan Rossiter9228bf72016-02-25 03:06:12 +0000601 def get_tenant_network(cls, credentials_type='primary'):
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530602 """Get the network to be used in testing
603
Ryan Rossiter9228bf72016-02-25 03:06:12 +0000604 :param credentials_type: The type of credentials for which to get the
605 tenant network
606
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530607 :return: network dict including 'id' and 'name'
608 """
Ryan Rossiter9228bf72016-02-25 03:06:12 +0000609 # Get a manager for the given credentials_type, but at least
610 # always fall back on getting the manager for primary credentials
611 if isinstance(credentials_type, six.string_types):
612 manager = cls.get_client_manager(credential_type=credentials_type)
613 elif isinstance(credentials_type, list):
614 manager = cls.get_client_manager(roles=credentials_type[1:])
615 else:
616 manager = cls.get_client_manager()
617
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700618 # Make sure cred_provider exists and get a network client
Ryan Rossiter9228bf72016-02-25 03:06:12 +0000619 networks_client = manager.compute_networks_client
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100620 cred_provider = cls._get_credentials_provider()
Andrea Frittoli700711e2015-04-02 11:39:38 +0100621 # In case of nova network, isolated tenants are not able to list the
Joshua Whitebd769602016-02-02 09:30:11 -0800622 # network configured in fixed_network_name, even if they can use it
Andrea Frittoli700711e2015-04-02 11:39:38 +0100623 # for their servers, so using an admin network client to validate
624 # the network name
625 if (not CONF.service_available.neutron and
Andrea Frittoli (andreaf)32d0de12015-10-09 14:43:53 +0100626 credentials.is_admin_available(
627 identity_version=cls.get_identity_version())):
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100628 admin_creds = cred_provider.get_admin_creds()
Andrea Frittoli (andreaf)848c4a12016-06-09 11:09:02 +0100629 admin_manager = clients.Manager(admin_creds.credentials)
John Warren9487a182015-09-14 18:12:56 -0400630 networks_client = admin_manager.compute_networks_client
Andrea Frittoli (andreaf)940f8c62015-10-30 16:39:24 +0900631 return fixed_network.get_tenant_network(
632 cred_provider, networks_client, CONF.compute.fixed_network_name)
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530633
Andrea Frittoli71c71e92017-04-07 17:45:21 +0100634 def assertEmpty(self, items, msg=None):
635 """Asserts whether a sequence or collection is empty
Mark Maglana5885eb32014-02-28 10:57:34 -0800636
Andrea Frittoli71c71e92017-04-07 17:45:21 +0100637 :param items: sequence or collection to be tested
638 :param msg: message to be passed to the AssertionError
639 :raises AssertionError: when items is not empty
640 """
zhufl92ade4b2017-03-03 15:20:10 +0800641 if msg is None:
Andrea Frittoli71c71e92017-04-07 17:45:21 +0100642 msg = "sequence or collection is not empty: %s" % items
Masayuki Igawa0c0f0142017-04-10 17:22:02 +0900643 self.assertFalse(items, msg)
Andrea Frittoli71c71e92017-04-07 17:45:21 +0100644
645 def assertNotEmpty(self, items, msg=None):
646 """Asserts whether a sequence or collection is not empty
647
648 :param items: sequence or collection to be tested
649 :param msg: message to be passed to the AssertionError
650 :raises AssertionError: when items is empty
651 """
652 if msg is None:
653 msg = "sequence or collection is empty."
Masayuki Igawa0c0f0142017-04-10 17:22:02 +0900654 self.assertTrue(items, msg)