blob: fc846ffabf28061656d2478e05638dc30cd5cd3a [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
Rohan Kanade9ce97df2013-12-10 18:59:35 +053029from tempest.common import fixed_network
nithya-ganesan222efd72015-01-22 12:20:27 +000030import tempest.common.validation_resources as vresources
Attila Fazekasdc216422013-01-29 15:12:14 +010031from tempest import config
Matthew Treinish3787e4c2016-10-07 21:25:33 -040032from tempest.lib.common import cred_client
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 Pittierc5665a62017-04-12 16:42:53 +020047related_bug = debtcollector.moves.moved_function(
48 decorators.related_bug, 'related_bug', __name__,
49 version='Pike', removal_version='?')
50
51
Jordan Pittier3b46d272017-04-12 16:17:28 +020052attr = debtcollector.moves.moved_function(
53 decorators.attr, 'attr', __name__,
54 version='Pike', removal_version='?')
Chris Yeoh55530bb2013-02-08 16:04:27 +103055
56
Andrea Frittoli07acf262017-04-09 19:36:37 +020057class InvalidServiceTag(lib_exc.TempestException):
58 message = "Invalid service tag"
59
60
Matthew Treinish3d8c7322014-08-03 23:53:28 -040061def get_service_list():
Matthew Treinish8afbffd2014-01-21 23:56:13 +000062 service_list = {
63 'compute': CONF.service_available.nova,
64 'image': CONF.service_available.glance,
65 'volume': CONF.service_available.cinder,
Masayuki Igawa9012ba32017-06-09 15:28:59 +090066 # NOTE(masayukig): We have two network services which are neutron and
67 # nova-network. And we have no way to know whether nova-network is
68 # available or not. After the pending removal of nova-network from
69 # nova, we can treat the network/neutron case in the same manner as
70 # the other services.
Matthew Treinish8afbffd2014-01-21 23:56:13 +000071 'network': True,
Masayuki Igawa9012ba32017-06-09 15:28:59 +090072 # NOTE(masayukig): Tempest tests always require the identity service.
73 # So we should set this True here.
Matthew Treinish8afbffd2014-01-21 23:56:13 +000074 'identity': True,
75 'object_storage': CONF.service_available.swift,
Matthew Treinish8afbffd2014-01-21 23:56:13 +000076 }
Matthew Treinish3d8c7322014-08-03 23:53:28 -040077 return service_list
Matthew Treinish16c43792013-09-09 19:55:23 +000078
Matthew Treinish3d8c7322014-08-03 23:53:28 -040079
Yaroslav Lobankovda999f72015-06-30 20:32:55 +030080def services(*args):
Matthew Treinish3d8c7322014-08-03 23:53:28 -040081 """A decorator used to set an attr for each service used in a test case
82
83 This decorator applies a testtools attr for each service that gets
84 exercised by a test case.
85 """
Matthew Treinish16c43792013-09-09 19:55:23 +000086 def decorator(f):
Andrea Frittoli6f053072017-04-09 19:22:47 +020087 known_services = get_service_list()
88
Matthew Treinish16c43792013-09-09 19:55:23 +000089 for service in args:
Andrea Frittoli6f053072017-04-09 19:22:47 +020090 if service not in known_services:
Andrea Frittoli07acf262017-04-09 19:36:37 +020091 raise InvalidServiceTag('%s is not a valid service' % service)
Jordan Pittier3b46d272017-04-12 16:17:28 +020092 decorators.attr(type=list(args))(f)
Matthew Treinish8afbffd2014-01-21 23:56:13 +000093
94 @functools.wraps(f)
95 def wrapper(self, *func_args, **func_kwargs):
Matthew Treinish3d8c7322014-08-03 23:53:28 -040096 service_list = get_service_list()
97
Matthew Treinish8afbffd2014-01-21 23:56:13 +000098 for service in args:
99 if not service_list[service]:
100 msg = 'Skipped because the %s service is not available' % (
101 service)
102 raise testtools.TestCase.skipException(msg)
103 return f(self, *func_args, **func_kwargs)
104 return wrapper
Matthew Treinish16c43792013-09-09 19:55:23 +0000105 return decorator
106
107
Yaroslav Lobankovda999f72015-06-30 20:32:55 +0300108def requires_ext(**kwargs):
Matthew Treinishe3d26142013-11-26 19:14:58 +0000109 """A decorator to skip tests if an extension is not enabled
110
111 @param extension
112 @param service
113 """
114 def decorator(func):
115 @functools.wraps(func)
116 def wrapper(*func_args, **func_kwargs):
117 if not is_extension_enabled(kwargs['extension'],
118 kwargs['service']):
119 msg = "Skipped because %s extension: %s is not enabled" % (
120 kwargs['service'], kwargs['extension'])
121 raise testtools.TestCase.skipException(msg)
122 return func(*func_args, **func_kwargs)
123 return wrapper
124 return decorator
125
126
127def is_extension_enabled(extension_name, service):
128 """A function that will check the list of enabled extensions from config
129
130 """
Matthew Treinishe3d26142013-11-26 19:14:58 +0000131 config_dict = {
Matthew Treinishbc0e03e2014-01-30 16:51:06 +0000132 'compute': CONF.compute_feature_enabled.api_extensions,
Matthew Treinishbc0e03e2014-01-30 16:51:06 +0000133 'volume': CONF.volume_feature_enabled.api_extensions,
134 'network': CONF.network_feature_enabled.api_extensions,
135 'object': CONF.object_storage_feature_enabled.discoverable_apis,
Jane Zadorozhna121576d2015-06-23 12:57:13 +0300136 'identity': CONF.identity_feature_enabled.api_extensions
Matthew Treinishe3d26142013-11-26 19:14:58 +0000137 }
Masayuki Igawa0c0f0142017-04-10 17:22:02 +0900138 if not config_dict[service]:
Simeon Monov5d7effe2014-07-16 07:32:38 +0300139 return False
Matthew Treinishe3d26142013-11-26 19:14:58 +0000140 if config_dict[service][0] == 'all':
141 return True
142 if extension_name in config_dict[service]:
143 return True
144 return False
145
Ian Wienand98c35f32013-07-23 20:34:23 +1000146
Yair Fried95914122016-03-03 09:14:40 +0200147def is_scheduler_filter_enabled(filter_name):
ghanshyam5817e142016-12-01 11:38:46 +0900148 """Check the list of enabled compute scheduler filters from config.
149
150 This function checks whether the given compute scheduler filter is
151 available and configured in the config file. If the
152 scheduler_available_filters option is set to 'all' (Default value. which
153 means default filters are configured in nova) in tempest.conf then, this
154 function returns True with assumption that requested filter 'filter_name'
155 is one of available filter in nova ("nova.scheduler.filters.all_filters").
156 """
Yair Friedca5cfb52016-01-04 15:41:55 +0200157
158 filters = CONF.compute_feature_enabled.scheduler_available_filters
Masayuki Igawa0c0f0142017-04-10 17:22:02 +0900159 if not filters:
Yair Friedca5cfb52016-01-04 15:41:55 +0200160 return False
161 if 'all' in filters:
162 return True
163 if filter_name in filters:
164 return True
165 return False
166
167
Attila Fazekasf86fa312013-07-30 19:56:39 +0200168at_exit_set = set()
169
170
171def validate_tearDownClass():
172 if at_exit_set:
Sean Dagueeb1523b2014-03-10 10:17:44 -0400173 LOG.error(
174 "tearDownClass does not call the super's "
175 "tearDownClass in these classes: \n"
176 + str(at_exit_set))
177
Attila Fazekasf86fa312013-07-30 19:56:39 +0200178
179atexit.register(validate_tearDownClass)
180
Attila Fazekas53943322014-02-10 16:07:34 +0100181
Matthew Treinish2474f412014-11-17 18:11:56 -0500182class BaseTestCase(testtools.testcase.WithAttributes,
183 testtools.TestCase):
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100184 """The test base class defines Tempest framework for class level fixtures.
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000185
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100186 `setUpClass` and `tearDownClass` are defined here and cannot be overwritten
187 by subclasses (enforced via hacking rule T105).
188
189 Set-up is split in a series of steps (setup stages), which can be
190 overwritten by test classes. Set-up stages are:
191 - skip_checks
192 - setup_credentials
193 - setup_clients
194 - resource_setup
195
196 Tear-down is also split in a series of steps (teardown stages), which are
197 stacked for execution only if the corresponding setup stage had been
198 reached during the setup phase. Tear-down stages are:
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700199 - clear_credentials (defined in the base test class)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100200 - resource_cleanup
201 """
Attila Fazekasc43fec82013-04-09 23:17:52 +0200202
Attila Fazekasf86fa312013-07-30 19:56:39 +0200203 setUpClassCalled = False
204
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000205 # NOTE(andreaf) credentials holds a list of the credentials to be allocated
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100206 # at class setup time. Credential types can be 'primary', 'alt', 'admin' or
207 # a list of roles - the first element of the list being a label, and the
208 # rest the actual roles
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000209 credentials = []
nithya-ganesan222efd72015-01-22 12:20:27 +0000210 # Resources required to validate a server using ssh
211 validation_resources = {}
Matthew Treinish9f756a02014-01-15 10:26:07 -0500212 network_resources = {}
213
Sean Dague2ef32ac2014-06-09 11:32:23 -0400214 # NOTE(sdague): log_format is defined inline here instead of using the oslo
215 # default because going through the config path recouples config to the
216 # stress tests too early, and depending on testr order will fail unit tests
217 log_format = ('%(asctime)s %(process)d %(levelname)-8s '
218 '[%(name)s] %(message)s')
219
Ryota MIBU60687e52015-12-09 18:37:39 +0900220 # Client manager class to use in this test case.
221 client_manager = clients.Manager
222
Sean Dague02620fd2016-03-02 15:52:51 -0500223 # A way to adjust slow test classes
224 TIMEOUT_SCALING_FACTOR = 1
225
Pavel Sedlák1053bd32013-04-16 16:47:40 +0200226 @classmethod
227 def setUpClass(cls):
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100228 # It should never be overridden by descendants
Pavel Sedlák1053bd32013-04-16 16:47:40 +0200229 if hasattr(super(BaseTestCase, cls), 'setUpClass'):
230 super(BaseTestCase, cls).setUpClass()
Attila Fazekasf86fa312013-07-30 19:56:39 +0200231 cls.setUpClassCalled = True
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100232 # Stack of (name, callable) to be invoked in reverse order at teardown
233 cls.teardowns = []
234 # All the configuration checks that may generate a skip
235 cls.skip_checks()
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100236 try:
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100237 # Allocation of all required credentials and client managers
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700238 cls.teardowns.append(('credentials', cls.clear_credentials))
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100239 cls.setup_credentials()
240 # Shortcuts to clients
241 cls.setup_clients()
242 # Additional class-wide test resources
243 cls.teardowns.append(('resources', cls.resource_cleanup))
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100244 cls.resource_setup()
245 except Exception:
246 etype, value, trace = sys.exc_info()
Jordan Pittier525ec712016-12-07 17:51:26 +0100247 LOG.info("%s raised in %s.setUpClass. Invoking tearDownClass.",
248 etype, cls.__name__)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100249 cls.tearDownClass()
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100250 try:
Matthew Treinish843227d2015-04-23 10:17:17 -0400251 six.reraise(etype, value, trace)
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100252 finally:
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100253 del trace # to avoid circular refs
Pavel Sedlák1053bd32013-04-16 16:47:40 +0200254
Attila Fazekasf86fa312013-07-30 19:56:39 +0200255 @classmethod
256 def tearDownClass(cls):
Martin Kopecae155b72017-06-26 09:41:21 +0000257 # insert pdb breakpoint when pause_teardown is enabled
258 if CONF.pause_teardown:
259 cls.insert_pdb_breakpoint()
Attila Fazekas5d275302013-08-29 12:35:12 +0200260 at_exit_set.discard(cls)
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100261 # It should never be overridden by descendants
Attila Fazekasf86fa312013-07-30 19:56:39 +0200262 if hasattr(super(BaseTestCase, cls), 'tearDownClass'):
263 super(BaseTestCase, cls).tearDownClass()
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100264 # Save any existing exception, we always want to re-raise the original
265 # exception only
266 etype, value, trace = sys.exc_info()
267 # If there was no exception during setup we shall re-raise the first
268 # exception in teardown
269 re_raise = (etype is None)
270 while cls.teardowns:
271 name, teardown = cls.teardowns.pop()
272 # Catch any exception in tearDown so we can re-raise the original
273 # exception at the end
274 try:
275 teardown()
276 except Exception as te:
277 sys_exec_info = sys.exc_info()
278 tetype = sys_exec_info[0]
279 # TODO(andreaf): Till we have the ability to cleanup only
280 # resources that were successfully setup in resource_cleanup,
281 # log AttributeError as info instead of exception.
282 if tetype is AttributeError and name == 'resources':
Jordan Pittier525ec712016-12-07 17:51:26 +0100283 LOG.info("tearDownClass of %s failed: %s", name, te)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100284 else:
Jordan Pittier525ec712016-12-07 17:51:26 +0100285 LOG.exception("teardown of %s failed: %s", name, te)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100286 if not etype:
287 etype, value, trace = sys_exec_info
Joshua Whitebd769602016-02-02 09:30:11 -0800288 # If exceptions were raised during teardown, and not before, re-raise
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100289 # the first one
290 if re_raise and etype is not None:
291 try:
Matthew Treinish843227d2015-04-23 10:17:17 -0400292 six.reraise(etype, value, trace)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100293 finally:
294 del trace # to avoid circular refs
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100295
Martin Kopecae155b72017-06-26 09:41:21 +0000296 def tearDown(self):
297 super(BaseTestCase, self).tearDown()
298 # insert pdb breakpoint when pause_teardown is enabled
299 if CONF.pause_teardown:
300 BaseTestCase.insert_pdb_breakpoint()
301
302 @classmethod
303 def insert_pdb_breakpoint(cls):
304 """Add pdb breakpoint.
305
306 This can help in debugging process, cleaning of resources is
307 paused, so they can be examined.
308 """
309 import pdb
310 pdb.set_trace()
311
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100312 @classmethod
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100313 def skip_checks(cls):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000314 """Class level skip checks.
315
316 Subclasses verify in here all conditions that might prevent the
317 execution of the entire test class.
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100318 Checks implemented here may not make use API calls, and should rely on
319 configuration alone.
320 In general skip checks that require an API call are discouraged.
321 If one is really needed it may be implemented either in the
322 resource_setup or at test level.
323 """
Andrea Frittoli (andreaf)32d0de12015-10-09 14:43:53 +0100324 identity_version = cls.get_identity_version()
325 if 'admin' in cls.credentials and not credentials.is_admin_available(
326 identity_version=identity_version):
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000327 msg = "Missing Identity Admin API credentials in configuration."
328 raise cls.skipException(msg)
Andrea Frittoli (andreaf)32d0de12015-10-09 14:43:53 +0100329 if 'alt' in cls.credentials and not credentials.is_alt_available(
330 identity_version=identity_version):
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000331 msg = "Missing a 2nd set of API credentials in configuration."
332 raise cls.skipException(msg)
Andrea Frittoli (andreaf)41601412015-05-12 16:39:03 +0100333 if hasattr(cls, 'identity_version'):
334 if cls.identity_version == 'v2':
335 if not CONF.identity_feature_enabled.api_v2:
336 raise cls.skipException("Identity api v2 is not enabled")
337 elif cls.identity_version == 'v3':
338 if not CONF.identity_feature_enabled.api_v3:
339 raise cls.skipException("Identity api v3 is not enabled")
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100340
341 @classmethod
342 def setup_credentials(cls):
edannon6cc6fbc2016-05-03 11:56:12 +0300343 """Allocate credentials and create the client managers from them.
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000344
edannon6cc6fbc2016-05-03 11:56:12 +0300345 For every element of credentials param function creates tenant/user,
346 Then it creates client manager for that credential.
347
348 Network related tests must override this function with
349 set_network_resources() method, otherwise it will create
350 network resources(network resources are created in a later step).
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000351 """
352 for credentials_type in cls.credentials:
353 # This may raise an exception in case credentials are not available
354 # In that case we want to let the exception through and the test
355 # fail accordingly
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100356 if isinstance(credentials_type, six.string_types):
357 manager = cls.get_client_manager(
358 credential_type=credentials_type)
359 setattr(cls, 'os_%s' % credentials_type, manager)
Jordan Pittier8160d312017-04-18 11:52:23 +0200360 # NOTE(jordanP): Tempest should use os_primary, os_admin
361 # and os_alt throughout its code base but we keep the aliases
362 # around for a while for Tempest plugins. Aliases should be
363 # removed eventually.
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100364 # Setup some common aliases
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100365 if credentials_type == 'primary':
Jordan Pittier8160d312017-04-18 11:52:23 +0200366 cls.os = debtcollector.moves.moved_read_only_property(
367 'os', 'os_primary', version='Pike',
Jakub Libosvar7835ca12017-05-04 16:44:23 +0200368 removal_version='Queens')
Jordan Pittier8160d312017-04-18 11:52:23 +0200369 cls.manager =\
370 debtcollector.moves.moved_read_only_property(
371 'manager', 'os_primary', version='Pike',
Jakub Libosvar7835ca12017-05-04 16:44:23 +0200372 removal_version='Queens')
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100373 if credentials_type == 'admin':
Jordan Pittier8160d312017-04-18 11:52:23 +0200374 cls.os_adm = debtcollector.moves.moved_read_only_property(
375 'os_adm', 'os_admin', version='Pike',
Jakub Libosvar7835ca12017-05-04 16:44:23 +0200376 removal_version='Queens')
Jordan Pittier8160d312017-04-18 11:52:23 +0200377 cls.admin_manager =\
378 debtcollector.moves.moved_read_only_property(
379 'admin_manager', 'os_admin', version='Pike',
Jakub Libosvar7835ca12017-05-04 16:44:23 +0200380 removal_version='Queens')
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100381 if credentials_type == 'alt':
Jordan Pittier8160d312017-04-18 11:52:23 +0200382 cls.alt_manager =\
383 debtcollector.moves.moved_read_only_property(
384 'alt_manager', 'os_alt', version='Pike',
Jakub Libosvar7835ca12017-05-04 16:44:23 +0200385 removal_version='Queens')
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100386 elif isinstance(credentials_type, list):
387 manager = cls.get_client_manager(roles=credentials_type[1:],
388 force_new=True)
389 setattr(cls, 'os_roles_%s' % credentials_type[0], manager)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100390
391 @classmethod
392 def setup_clients(cls):
393 """Create links to the clients into the test object."""
394 # TODO(andreaf) There is a fair amount of code that could me moved from
395 # base / test classes in here. Ideally tests should be able to only
396 # specify which client is `client` and nothing else.
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100397 pass
Attila Fazekasf86fa312013-07-30 19:56:39 +0200398
Emily Hugenbruch5bd4cbf2014-12-17 21:38:38 +0000399 @classmethod
400 def resource_setup(cls):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000401 """Class level resource setup for test cases."""
Andrea Frittolicf999a82017-05-24 10:44:46 +0100402 if hasattr(cls, "os_primary"):
nithya-ganesan222efd72015-01-22 12:20:27 +0000403 cls.validation_resources = vresources.create_validation_resources(
Andrea Frittolicf999a82017-05-24 10:44:46 +0100404 cls.os_primary, cls.validation_resources)
nithya-ganesan222efd72015-01-22 12:20:27 +0000405 else:
zhangguoqing6c096642016-01-04 06:17:21 +0000406 LOG.warning("Client manager not found, validation resources not"
407 " created")
Emily Hugenbruch5bd4cbf2014-12-17 21:38:38 +0000408
409 @classmethod
410 def resource_cleanup(cls):
411 """Class level resource cleanup for test cases.
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000412
Emily Hugenbruch5bd4cbf2014-12-17 21:38:38 +0000413 Resource cleanup must be able to handle the case of partially setup
414 resources, in case a failure during `resource_setup` should happen.
415 """
nithya-ganesan222efd72015-01-22 12:20:27 +0000416 if cls.validation_resources:
Andrea Frittolicf999a82017-05-24 10:44:46 +0100417 if hasattr(cls, "os_primary"):
418 vresources.clear_validation_resources(cls.os_primary,
nithya-ganesan222efd72015-01-22 12:20:27 +0000419 cls.validation_resources)
420 cls.validation_resources = {}
421 else:
zhangguoqing6c096642016-01-04 06:17:21 +0000422 LOG.warning("Client manager not found, validation resources "
423 "not deleted")
Emily Hugenbruch5bd4cbf2014-12-17 21:38:38 +0000424
Attila Fazekasf86fa312013-07-30 19:56:39 +0200425 def setUp(self):
426 super(BaseTestCase, self).setUp()
427 if not self.setUpClassCalled:
428 raise RuntimeError("setUpClass does not calls the super's"
429 "setUpClass in the "
430 + self.__class__.__name__)
431 at_exit_set.add(self.__class__)
Matthew Treinish78561ad2013-07-26 11:41:56 -0400432 test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0)
433 try:
Sean Dague02620fd2016-03-02 15:52:51 -0500434 test_timeout = int(test_timeout) * self.TIMEOUT_SCALING_FACTOR
Matthew Treinish78561ad2013-07-26 11:41:56 -0400435 except ValueError:
436 test_timeout = 0
437 if test_timeout > 0:
Attila Fazekasf86fa312013-07-30 19:56:39 +0200438 self.useFixture(fixtures.Timeout(test_timeout, gentle=True))
Matthew Treinish78561ad2013-07-26 11:41:56 -0400439
440 if (os.environ.get('OS_STDOUT_CAPTURE') == 'True' or
441 os.environ.get('OS_STDOUT_CAPTURE') == '1'):
Attila Fazekasf86fa312013-07-30 19:56:39 +0200442 stdout = self.useFixture(fixtures.StringStream('stdout')).stream
443 self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
Matthew Treinish78561ad2013-07-26 11:41:56 -0400444 if (os.environ.get('OS_STDERR_CAPTURE') == 'True' or
445 os.environ.get('OS_STDERR_CAPTURE') == '1'):
Attila Fazekasf86fa312013-07-30 19:56:39 +0200446 stderr = self.useFixture(fixtures.StringStream('stderr')).stream
447 self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
Attila Fazekas31388072013-08-15 08:58:07 +0200448 if (os.environ.get('OS_LOG_CAPTURE') != 'False' and
449 os.environ.get('OS_LOG_CAPTURE') != '0'):
Attila Fazekas31388072013-08-15 08:58:07 +0200450 self.useFixture(fixtures.LoggerFixture(nuke_handlers=False,
Sean Dague2ef32ac2014-06-09 11:32:23 -0400451 format=self.log_format,
Attila Fazekas90445be2013-10-24 16:46:03 +0200452 level=None))
Matthew Treinish78561ad2013-07-26 11:41:56 -0400453
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100454 @property
455 def credentials_provider(self):
456 return self._get_credentials_provider()
457
Jamie Lennox15350172015-08-17 10:54:25 +1000458 @property
459 def identity_utils(self):
460 """A client that abstracts v2 and v3 identity operations.
461
462 This can be used for creating and tearing down projects in tests. It
463 should not be used for testing identity features.
464 """
465 if CONF.identity.auth_version == 'v2':
466 client = self.os_admin.identity_client
Daniel Mellado7aea5342016-02-09 09:10:12 +0000467 users_client = self.os_admin.users_client
Daniel Melladob04da902015-11-20 17:43:12 +0100468 project_client = self.os_admin.tenants_client
Daniel Mellado6b16b922015-12-07 12:43:08 +0000469 roles_client = self.os_admin.roles_client
Daniel Mellado91a26b62016-02-11 11:13:04 +0000470 domains_client = None
Jamie Lennox15350172015-08-17 10:54:25 +1000471 else:
472 client = self.os_admin.identity_v3_client
Daniel Mellado7aea5342016-02-09 09:10:12 +0000473 users_client = self.os_admin.users_v3_client
Arx Cruz24bcb882016-02-10 15:20:16 +0100474 project_client = self.os_admin.projects_client
475 roles_client = self.os_admin.roles_v3_client
Daniel Mellado91a26b62016-02-11 11:13:04 +0000476 domains_client = self.os_admin.domains_client
Jamie Lennox15350172015-08-17 10:54:25 +1000477
478 try:
479 domain = client.auth_provider.credentials.project_domain_name
480 except AttributeError:
481 domain = 'Default'
482
Daniel Melladob04da902015-11-20 17:43:12 +0100483 return cred_client.get_creds_client(client, project_client,
Daniel Mellado82c83a52015-12-09 15:16:49 +0000484 users_client,
Daniel Mellado7aea5342016-02-09 09:10:12 +0000485 roles_client,
Daniel Mellado91a26b62016-02-11 11:13:04 +0000486 domains_client,
Daniel Melladob04da902015-11-20 17:43:12 +0100487 project_domain_name=domain)
Jamie Lennox15350172015-08-17 10:54:25 +1000488
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100489 @classmethod
Andrea Frittoli (andreaf)32d0de12015-10-09 14:43:53 +0100490 def get_identity_version(cls):
491 """Returns the identity version used by the test class"""
492 identity_version = getattr(cls, 'identity_version', None)
493 return identity_version or CONF.identity.auth_version
494
495 @classmethod
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100496 def _get_credentials_provider(cls):
497 """Returns a credentials provider
498
499 If no credential provider exists yet creates one.
Andrea Frittoli9e01dbb2017-04-20 15:28:30 +0100500 It always use the configuration value from identity.auth_version,
501 since we always want to provision accounts with the current version
502 of the identity API.
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100503 """
504 if (not hasattr(cls, '_creds_provider') or not cls._creds_provider or
505 not cls._creds_provider.name == cls.__name__):
506 force_tenant_isolation = getattr(cls, 'force_tenant_isolation',
507 False)
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100508
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700509 cls._creds_provider = credentials.get_credentials_provider(
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100510 name=cls.__name__, network_resources=cls.network_resources,
Andrea Frittoli9e01dbb2017-04-20 15:28:30 +0100511 force_tenant_isolation=force_tenant_isolation)
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100512 return cls._creds_provider
513
Matthew Treinish3e046852013-07-23 16:00:24 -0400514 @classmethod
Andrea Frittoli (andreaf)41601412015-05-12 16:39:03 +0100515 def get_client_manager(cls, credential_type=None, roles=None,
516 force_new=None):
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100517 """Returns an OpenStack client manager
518
519 Returns an OpenStack client manager based on either credential_type
520 or a list of roles. If neither is specified, it defaults to
521 credential_type 'primary'
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100522 :param credential_type: string - primary, alt or admin
523 :param roles: list of roles
524
lei zhangdd552b22015-11-25 20:41:48 +0800525 :returns: the created client manager
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100526 :raises skipException: if the requested credentials are not available
Ryan Hsu6c4bb3d2013-10-21 21:22:50 -0700527 """
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100528 if all([roles, credential_type]):
529 msg = "Cannot get credentials by type and roles at the same time"
530 raise ValueError(msg)
531 if not any([roles, credential_type]):
532 credential_type = 'primary'
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100533 cred_provider = cls._get_credentials_provider()
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100534 if roles:
535 for role in roles:
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100536 if not cred_provider.is_role_available(role):
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100537 skip_msg = (
538 "%s skipped because the configured credential provider"
539 " is not able to provide credentials with the %s role "
540 "assigned." % (cls.__name__, role))
541 raise cls.skipException(skip_msg)
542 params = dict(roles=roles)
543 if force_new is not None:
544 params.update(force_new=force_new)
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100545 creds = cred_provider.get_creds_by_roles(**params)
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000546 else:
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100547 credentials_method = 'get_%s_creds' % credential_type
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100548 if hasattr(cred_provider, credentials_method):
549 creds = getattr(cred_provider, credentials_method)()
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100550 else:
Andrea Frittoli (andreaf)af4f7cf2016-06-13 15:12:26 +0100551 raise lib_exc.InvalidCredentials(
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100552 "Invalid credentials type %s" % credential_type)
Jordan Pittiere4be9072017-01-04 19:17:35 +0100553 manager = cls.client_manager(credentials=creds.credentials)
Andrea Frittoli73224672016-12-09 21:08:19 +0000554 # NOTE(andreaf) Ensure credentials have user and project id fields.
555 # It may not be the case when using pre-provisioned credentials.
556 manager.auth_provider.set_auth()
557 return manager
Ryan Hsu6c4bb3d2013-10-21 21:22:50 -0700558
559 @classmethod
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700560 def clear_credentials(cls):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000561 """Clears creds if set"""
Attila Fazekas5b0d9262015-05-20 10:17:39 +0200562 if hasattr(cls, '_creds_provider'):
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700563 cls._creds_provider.clear_creds()
Ryan Hsu6c4bb3d2013-10-21 21:22:50 -0700564
565 @classmethod
nithya-ganesan222efd72015-01-22 12:20:27 +0000566 def set_validation_resources(cls, keypair=None, floating_ip=None,
567 security_group=None,
568 security_group_rules=None):
569 """Specify which ssh server validation resources should be created.
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000570
nithya-ganesan222efd72015-01-22 12:20:27 +0000571 Each of the argument must be set to either None, True or False, with
572 None - use default from config (security groups and security group
573 rules get created when set to None)
574 False - Do not create the validation resource
575 True - create the validation resource
576
577 @param keypair
578 @param security_group
579 @param security_group_rules
580 @param floating_ip
581 """
Matthew Treinishe5cca002015-05-11 15:36:50 -0400582 if not CONF.validation.run_validation:
583 return
Jordan Pittier79cd1822016-12-08 17:20:35 +0100584
nithya-ganesan222efd72015-01-22 12:20:27 +0000585 if keypair is None:
Jordan Pittier79cd1822016-12-08 17:20:35 +0100586 keypair = (CONF.validation.auth_method.lower() == "keypair")
587
nithya-ganesan222efd72015-01-22 12:20:27 +0000588 if floating_ip is None:
Jordan Pittier79cd1822016-12-08 17:20:35 +0100589 floating_ip = (CONF.validation.connect_method.lower() ==
590 "floating")
591
nithya-ganesan222efd72015-01-22 12:20:27 +0000592 if security_group is None:
Brandon Palmc6cc91d2015-08-19 13:20:21 -0500593 security_group = CONF.validation.security_group
Jordan Pittier79cd1822016-12-08 17:20:35 +0100594
nithya-ganesan222efd72015-01-22 12:20:27 +0000595 if security_group_rules is None:
Brandon Palmc6cc91d2015-08-19 13:20:21 -0500596 security_group_rules = CONF.validation.security_group_rules
597
nithya-ganesan222efd72015-01-22 12:20:27 +0000598 if not cls.validation_resources:
599 cls.validation_resources = {
600 'keypair': keypair,
601 'security_group': security_group,
602 'security_group_rules': security_group_rules,
603 'floating_ip': floating_ip}
604
605 @classmethod
Andrea Frittoli7d5ed592015-02-10 01:10:23 +0000606 def set_network_resources(cls, network=False, router=False, subnet=False,
Matthew Treinish9f756a02014-01-15 10:26:07 -0500607 dhcp=False):
608 """Specify which network resources should be created
609
610 @param network
611 @param router
612 @param subnet
613 @param dhcp
614 """
Salvatore Orlando5a337242014-01-15 22:49:22 +0000615 # network resources should be set only once from callers
616 # in order to ensure that even if it's called multiple times in
617 # a chain of overloaded methods, the attribute is set only
618 # in the leaf class
Andrea Frittoli7d5ed592015-02-10 01:10:23 +0000619 if not cls.network_resources:
620 cls.network_resources = {
Salvatore Orlando5a337242014-01-15 22:49:22 +0000621 'network': network,
622 'router': router,
623 'subnet': subnet,
624 'dhcp': dhcp}
Matthew Treinish9f756a02014-01-15 10:26:07 -0500625
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530626 @classmethod
Ryan Rossiter9228bf72016-02-25 03:06:12 +0000627 def get_tenant_network(cls, credentials_type='primary'):
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530628 """Get the network to be used in testing
629
Ryan Rossiter9228bf72016-02-25 03:06:12 +0000630 :param credentials_type: The type of credentials for which to get the
631 tenant network
632
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530633 :return: network dict including 'id' and 'name'
634 """
Ryan Rossiter9228bf72016-02-25 03:06:12 +0000635 # Get a manager for the given credentials_type, but at least
636 # always fall back on getting the manager for primary credentials
637 if isinstance(credentials_type, six.string_types):
638 manager = cls.get_client_manager(credential_type=credentials_type)
639 elif isinstance(credentials_type, list):
640 manager = cls.get_client_manager(roles=credentials_type[1:])
641 else:
642 manager = cls.get_client_manager()
643
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700644 # Make sure cred_provider exists and get a network client
Ryan Rossiter9228bf72016-02-25 03:06:12 +0000645 networks_client = manager.compute_networks_client
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100646 cred_provider = cls._get_credentials_provider()
Andrea Frittoli700711e2015-04-02 11:39:38 +0100647 # In case of nova network, isolated tenants are not able to list the
Joshua Whitebd769602016-02-02 09:30:11 -0800648 # network configured in fixed_network_name, even if they can use it
Andrea Frittoli700711e2015-04-02 11:39:38 +0100649 # for their servers, so using an admin network client to validate
650 # the network name
651 if (not CONF.service_available.neutron and
Andrea Frittoli (andreaf)32d0de12015-10-09 14:43:53 +0100652 credentials.is_admin_available(
653 identity_version=cls.get_identity_version())):
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100654 admin_creds = cred_provider.get_admin_creds()
Andrea Frittoli (andreaf)848c4a12016-06-09 11:09:02 +0100655 admin_manager = clients.Manager(admin_creds.credentials)
John Warren9487a182015-09-14 18:12:56 -0400656 networks_client = admin_manager.compute_networks_client
Andrea Frittoli (andreaf)940f8c62015-10-30 16:39:24 +0900657 return fixed_network.get_tenant_network(
658 cred_provider, networks_client, CONF.compute.fixed_network_name)
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530659
Andrea Frittoli71c71e92017-04-07 17:45:21 +0100660 def assertEmpty(self, items, msg=None):
661 """Asserts whether a sequence or collection is empty
Mark Maglana5885eb32014-02-28 10:57:34 -0800662
Andrea Frittoli71c71e92017-04-07 17:45:21 +0100663 :param items: sequence or collection to be tested
664 :param msg: message to be passed to the AssertionError
665 :raises AssertionError: when items is not empty
666 """
zhufl92ade4b2017-03-03 15:20:10 +0800667 if msg is None:
Andrea Frittoli71c71e92017-04-07 17:45:21 +0100668 msg = "sequence or collection is not empty: %s" % items
Masayuki Igawa0c0f0142017-04-10 17:22:02 +0900669 self.assertFalse(items, msg)
Andrea Frittoli71c71e92017-04-07 17:45:21 +0100670
671 def assertNotEmpty(self, items, msg=None):
672 """Asserts whether a sequence or collection is not empty
673
674 :param items: sequence or collection to be tested
675 :param msg: message to be passed to the AssertionError
676 :raises AssertionError: when items is empty
677 """
678 if msg is None:
679 msg = "sequence or collection is empty."
Masayuki Igawa0c0f0142017-04-10 17:22:02 +0900680 self.assertTrue(items, msg)