blob: f2a8bd62d80a383fb443c3b7f9977fa3773476b7 [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 Treinish16c43792013-09-09 19:55:23 +000032from tempest import exceptions
Matthew Treinish3787e4c2016-10-07 21:25:33 -040033from tempest.lib.common import cred_client
Andrea Frittoli (andreaf)db9672e2016-02-23 14:07:24 -050034from tempest.lib import decorators
Andrea Frittoli (andreaf)af4f7cf2016-06-13 15:12:26 +010035from tempest.lib import exceptions as lib_exc
Jay Pipes051075a2012-04-28 17:39:37 -040036
37LOG = logging.getLogger(__name__)
38
Sean Dague86bd8422013-12-20 09:56:44 -050039CONF = config.CONF
40
Ken'ichi Ohmichi44f01272017-01-27 18:44:14 -080041# TODO(oomichi): This test.idempotent_id should be removed after all projects
42# switch to use decorators.idempotent_id.
43idempotent_id = debtcollector.moves.moved_function(
44 decorators.idempotent_id, 'idempotent_id', __name__,
45 version='Mitaka', removal_version='?')
Matthew Treinishc1802bc2015-12-03 18:48:11 -050046
Jay Pipes051075a2012-04-28 17:39:37 -040047
Jordan Pittierc5665a62017-04-12 16:42:53 +020048related_bug = debtcollector.moves.moved_function(
49 decorators.related_bug, 'related_bug', __name__,
50 version='Pike', removal_version='?')
51
52
Yaroslav Lobankovda999f72015-06-30 20:32:55 +030053def attr(**kwargs):
liuchenhong00caec52015-07-19 22:40:28 +080054 """A decorator which applies the testtools attr decorator
Chris Yeoh55530bb2013-02-08 16:04:27 +103055
Matthew Treinisha74f5d42014-02-07 20:25:44 -050056 This decorator applies the testtools.testcase.attr if it is in the list of
57 attributes to testtools we want to apply.
Attila Fazekasb2902af2013-02-16 16:22:44 +010058 """
Chris Yeoh55530bb2013-02-08 16:04:27 +103059
60 def decorator(f):
Giulio Fidente4946a052013-05-14 12:23:51 +020061 if 'type' in kwargs and isinstance(kwargs['type'], str):
62 f = testtools.testcase.attr(kwargs['type'])(f)
63 elif 'type' in kwargs and isinstance(kwargs['type'], list):
64 for attr in kwargs['type']:
65 f = testtools.testcase.attr(attr)(f)
Matthew Treinisha74f5d42014-02-07 20:25:44 -050066 return f
Chris Yeoh55530bb2013-02-08 16:04:27 +103067
68 return decorator
69
70
Matthew Treinish3d8c7322014-08-03 23:53:28 -040071def get_service_list():
Matthew Treinish8afbffd2014-01-21 23:56:13 +000072 service_list = {
73 'compute': CONF.service_available.nova,
74 'image': CONF.service_available.glance,
75 'volume': CONF.service_available.cinder,
Matthew Treinish8afbffd2014-01-21 23:56:13 +000076 'network': True,
77 'identity': True,
78 'object_storage': CONF.service_available.swift,
Matthew Treinish8afbffd2014-01-21 23:56:13 +000079 }
Matthew Treinish3d8c7322014-08-03 23:53:28 -040080 return service_list
Matthew Treinish16c43792013-09-09 19:55:23 +000081
Matthew Treinish3d8c7322014-08-03 23:53:28 -040082
Yaroslav Lobankovda999f72015-06-30 20:32:55 +030083def services(*args):
Matthew Treinish3d8c7322014-08-03 23:53:28 -040084 """A decorator used to set an attr for each service used in a test case
85
86 This decorator applies a testtools attr for each service that gets
87 exercised by a test case.
88 """
Matthew Treinish16c43792013-09-09 19:55:23 +000089 def decorator(f):
Masayuki Igawa22b30082016-06-27 16:18:59 +090090 services = ['compute', 'image', 'baremetal', 'volume',
91 'network', 'identity', 'object_storage']
Matthew Treinish16c43792013-09-09 19:55:23 +000092 for service in args:
Matthew Treinish3d8c7322014-08-03 23:53:28 -040093 if service not in services:
94 raise exceptions.InvalidServiceTag('%s is not a valid '
95 'service' % service)
Matthew Treinish16c43792013-09-09 19:55:23 +000096 attr(type=list(args))(f)
Matthew Treinish8afbffd2014-01-21 23:56:13 +000097
98 @functools.wraps(f)
99 def wrapper(self, *func_args, **func_kwargs):
Matthew Treinish3d8c7322014-08-03 23:53:28 -0400100 service_list = get_service_list()
101
Matthew Treinish8afbffd2014-01-21 23:56:13 +0000102 for service in args:
103 if not service_list[service]:
104 msg = 'Skipped because the %s service is not available' % (
105 service)
106 raise testtools.TestCase.skipException(msg)
107 return f(self, *func_args, **func_kwargs)
108 return wrapper
Matthew Treinish16c43792013-09-09 19:55:23 +0000109 return decorator
110
111
Yaroslav Lobankovda999f72015-06-30 20:32:55 +0300112def requires_ext(**kwargs):
Matthew Treinishe3d26142013-11-26 19:14:58 +0000113 """A decorator to skip tests if an extension is not enabled
114
115 @param extension
116 @param service
117 """
118 def decorator(func):
119 @functools.wraps(func)
120 def wrapper(*func_args, **func_kwargs):
121 if not is_extension_enabled(kwargs['extension'],
122 kwargs['service']):
123 msg = "Skipped because %s extension: %s is not enabled" % (
124 kwargs['service'], kwargs['extension'])
125 raise testtools.TestCase.skipException(msg)
126 return func(*func_args, **func_kwargs)
127 return wrapper
128 return decorator
129
130
131def is_extension_enabled(extension_name, service):
132 """A function that will check the list of enabled extensions from config
133
134 """
Matthew Treinishe3d26142013-11-26 19:14:58 +0000135 config_dict = {
Matthew Treinishbc0e03e2014-01-30 16:51:06 +0000136 'compute': CONF.compute_feature_enabled.api_extensions,
Matthew Treinishbc0e03e2014-01-30 16:51:06 +0000137 'volume': CONF.volume_feature_enabled.api_extensions,
138 'network': CONF.network_feature_enabled.api_extensions,
139 'object': CONF.object_storage_feature_enabled.discoverable_apis,
Jane Zadorozhna121576d2015-06-23 12:57:13 +0300140 'identity': CONF.identity_feature_enabled.api_extensions
Matthew Treinishe3d26142013-11-26 19:14:58 +0000141 }
Simeon Monov5d7effe2014-07-16 07:32:38 +0300142 if len(config_dict[service]) == 0:
143 return False
Matthew Treinishe3d26142013-11-26 19:14:58 +0000144 if config_dict[service][0] == 'all':
145 return True
146 if extension_name in config_dict[service]:
147 return True
148 return False
149
Ian Wienand98c35f32013-07-23 20:34:23 +1000150
Yair Fried95914122016-03-03 09:14:40 +0200151def is_scheduler_filter_enabled(filter_name):
ghanshyam5817e142016-12-01 11:38:46 +0900152 """Check the list of enabled compute scheduler filters from config.
153
154 This function checks whether the given compute scheduler filter is
155 available and configured in the config file. If the
156 scheduler_available_filters option is set to 'all' (Default value. which
157 means default filters are configured in nova) in tempest.conf then, this
158 function returns True with assumption that requested filter 'filter_name'
159 is one of available filter in nova ("nova.scheduler.filters.all_filters").
160 """
Yair Friedca5cfb52016-01-04 15:41:55 +0200161
162 filters = CONF.compute_feature_enabled.scheduler_available_filters
163 if len(filters) == 0:
164 return False
165 if 'all' in filters:
166 return True
167 if filter_name in filters:
168 return True
169 return False
170
171
Attila Fazekasf86fa312013-07-30 19:56:39 +0200172at_exit_set = set()
173
174
175def validate_tearDownClass():
176 if at_exit_set:
Sean Dagueeb1523b2014-03-10 10:17:44 -0400177 LOG.error(
178 "tearDownClass does not call the super's "
179 "tearDownClass in these classes: \n"
180 + str(at_exit_set))
181
Attila Fazekasf86fa312013-07-30 19:56:39 +0200182
183atexit.register(validate_tearDownClass)
184
Attila Fazekas53943322014-02-10 16:07:34 +0100185
Matthew Treinish2474f412014-11-17 18:11:56 -0500186class BaseTestCase(testtools.testcase.WithAttributes,
187 testtools.TestCase):
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100188 """The test base class defines Tempest framework for class level fixtures.
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000189
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100190 `setUpClass` and `tearDownClass` are defined here and cannot be overwritten
191 by subclasses (enforced via hacking rule T105).
192
193 Set-up is split in a series of steps (setup stages), which can be
194 overwritten by test classes. Set-up stages are:
195 - skip_checks
196 - setup_credentials
197 - setup_clients
198 - resource_setup
199
200 Tear-down is also split in a series of steps (teardown stages), which are
201 stacked for execution only if the corresponding setup stage had been
202 reached during the setup phase. Tear-down stages are:
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700203 - clear_credentials (defined in the base test class)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100204 - resource_cleanup
205 """
Attila Fazekasc43fec82013-04-09 23:17:52 +0200206
Attila Fazekasf86fa312013-07-30 19:56:39 +0200207 setUpClassCalled = False
208
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000209 # NOTE(andreaf) credentials holds a list of the credentials to be allocated
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100210 # at class setup time. Credential types can be 'primary', 'alt', 'admin' or
211 # a list of roles - the first element of the list being a label, and the
212 # rest the actual roles
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000213 credentials = []
nithya-ganesan222efd72015-01-22 12:20:27 +0000214 # Resources required to validate a server using ssh
215 validation_resources = {}
Matthew Treinish9f756a02014-01-15 10:26:07 -0500216 network_resources = {}
217
Sean Dague2ef32ac2014-06-09 11:32:23 -0400218 # NOTE(sdague): log_format is defined inline here instead of using the oslo
219 # default because going through the config path recouples config to the
220 # stress tests too early, and depending on testr order will fail unit tests
221 log_format = ('%(asctime)s %(process)d %(levelname)-8s '
222 '[%(name)s] %(message)s')
223
Ryota MIBU60687e52015-12-09 18:37:39 +0900224 # Client manager class to use in this test case.
225 client_manager = clients.Manager
226
Sean Dague02620fd2016-03-02 15:52:51 -0500227 # A way to adjust slow test classes
228 TIMEOUT_SCALING_FACTOR = 1
229
Pavel Sedlák1053bd32013-04-16 16:47:40 +0200230 @classmethod
231 def setUpClass(cls):
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100232 # It should never be overridden by descendants
Pavel Sedlák1053bd32013-04-16 16:47:40 +0200233 if hasattr(super(BaseTestCase, cls), 'setUpClass'):
234 super(BaseTestCase, cls).setUpClass()
Attila Fazekasf86fa312013-07-30 19:56:39 +0200235 cls.setUpClassCalled = True
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100236 # Stack of (name, callable) to be invoked in reverse order at teardown
237 cls.teardowns = []
238 # All the configuration checks that may generate a skip
239 cls.skip_checks()
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100240 try:
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100241 # Allocation of all required credentials and client managers
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700242 cls.teardowns.append(('credentials', cls.clear_credentials))
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100243 cls.setup_credentials()
244 # Shortcuts to clients
245 cls.setup_clients()
246 # Additional class-wide test resources
247 cls.teardowns.append(('resources', cls.resource_cleanup))
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100248 cls.resource_setup()
249 except Exception:
250 etype, value, trace = sys.exc_info()
Jordan Pittier525ec712016-12-07 17:51:26 +0100251 LOG.info("%s raised in %s.setUpClass. Invoking tearDownClass.",
252 etype, cls.__name__)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100253 cls.tearDownClass()
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100254 try:
Matthew Treinish843227d2015-04-23 10:17:17 -0400255 six.reraise(etype, value, trace)
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100256 finally:
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100257 del trace # to avoid circular refs
Pavel Sedlák1053bd32013-04-16 16:47:40 +0200258
Attila Fazekasf86fa312013-07-30 19:56:39 +0200259 @classmethod
260 def tearDownClass(cls):
Attila Fazekas5d275302013-08-29 12:35:12 +0200261 at_exit_set.discard(cls)
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100262 # It should never be overridden by descendants
Attila Fazekasf86fa312013-07-30 19:56:39 +0200263 if hasattr(super(BaseTestCase, cls), 'tearDownClass'):
264 super(BaseTestCase, cls).tearDownClass()
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100265 # Save any existing exception, we always want to re-raise the original
266 # exception only
267 etype, value, trace = sys.exc_info()
268 # If there was no exception during setup we shall re-raise the first
269 # exception in teardown
270 re_raise = (etype is None)
271 while cls.teardowns:
272 name, teardown = cls.teardowns.pop()
273 # Catch any exception in tearDown so we can re-raise the original
274 # exception at the end
275 try:
276 teardown()
277 except Exception as te:
278 sys_exec_info = sys.exc_info()
279 tetype = sys_exec_info[0]
280 # TODO(andreaf): Till we have the ability to cleanup only
281 # resources that were successfully setup in resource_cleanup,
282 # log AttributeError as info instead of exception.
283 if tetype is AttributeError and name == 'resources':
Jordan Pittier525ec712016-12-07 17:51:26 +0100284 LOG.info("tearDownClass of %s failed: %s", name, te)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100285 else:
Jordan Pittier525ec712016-12-07 17:51:26 +0100286 LOG.exception("teardown of %s failed: %s", name, te)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100287 if not etype:
288 etype, value, trace = sys_exec_info
Joshua Whitebd769602016-02-02 09:30:11 -0800289 # If exceptions were raised during teardown, and not before, re-raise
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100290 # the first one
291 if re_raise and etype is not None:
292 try:
Matthew Treinish843227d2015-04-23 10:17:17 -0400293 six.reraise(etype, value, trace)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100294 finally:
295 del trace # to avoid circular refs
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100296
297 @classmethod
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100298 def skip_checks(cls):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000299 """Class level skip checks.
300
301 Subclasses verify in here all conditions that might prevent the
302 execution of the entire test class.
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100303 Checks implemented here may not make use API calls, and should rely on
304 configuration alone.
305 In general skip checks that require an API call are discouraged.
306 If one is really needed it may be implemented either in the
307 resource_setup or at test level.
308 """
Andrea Frittoli (andreaf)32d0de12015-10-09 14:43:53 +0100309 identity_version = cls.get_identity_version()
310 if 'admin' in cls.credentials and not credentials.is_admin_available(
311 identity_version=identity_version):
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000312 msg = "Missing Identity Admin API credentials in configuration."
313 raise cls.skipException(msg)
Andrea Frittoli (andreaf)32d0de12015-10-09 14:43:53 +0100314 if 'alt' in cls.credentials and not credentials.is_alt_available(
315 identity_version=identity_version):
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000316 msg = "Missing a 2nd set of API credentials in configuration."
317 raise cls.skipException(msg)
Andrea Frittoli (andreaf)41601412015-05-12 16:39:03 +0100318 if hasattr(cls, 'identity_version'):
319 if cls.identity_version == 'v2':
320 if not CONF.identity_feature_enabled.api_v2:
321 raise cls.skipException("Identity api v2 is not enabled")
322 elif cls.identity_version == 'v3':
323 if not CONF.identity_feature_enabled.api_v3:
324 raise cls.skipException("Identity api v3 is not enabled")
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100325
326 @classmethod
327 def setup_credentials(cls):
edannon6cc6fbc2016-05-03 11:56:12 +0300328 """Allocate credentials and create the client managers from them.
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000329
edannon6cc6fbc2016-05-03 11:56:12 +0300330 For every element of credentials param function creates tenant/user,
331 Then it creates client manager for that credential.
332
333 Network related tests must override this function with
334 set_network_resources() method, otherwise it will create
335 network resources(network resources are created in a later step).
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000336 """
337 for credentials_type in cls.credentials:
338 # This may raise an exception in case credentials are not available
339 # In that case we want to let the exception through and the test
340 # fail accordingly
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100341 if isinstance(credentials_type, six.string_types):
342 manager = cls.get_client_manager(
343 credential_type=credentials_type)
344 setattr(cls, 'os_%s' % credentials_type, manager)
345 # Setup some common aliases
346 # TODO(andreaf) The aliases below are a temporary hack
347 # to avoid changing too much code in one patch. They should
348 # be removed eventually
349 if credentials_type == 'primary':
350 cls.os = cls.manager = cls.os_primary
351 if credentials_type == 'admin':
352 cls.os_adm = cls.admin_manager = cls.os_admin
353 if credentials_type == 'alt':
354 cls.alt_manager = cls.os_alt
355 elif isinstance(credentials_type, list):
356 manager = cls.get_client_manager(roles=credentials_type[1:],
357 force_new=True)
358 setattr(cls, 'os_roles_%s' % credentials_type[0], manager)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100359
360 @classmethod
361 def setup_clients(cls):
362 """Create links to the clients into the test object."""
363 # TODO(andreaf) There is a fair amount of code that could me moved from
364 # base / test classes in here. Ideally tests should be able to only
365 # specify which client is `client` and nothing else.
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100366 pass
Attila Fazekasf86fa312013-07-30 19:56:39 +0200367
Emily Hugenbruch5bd4cbf2014-12-17 21:38:38 +0000368 @classmethod
369 def resource_setup(cls):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000370 """Class level resource setup for test cases."""
nithya-ganesan222efd72015-01-22 12:20:27 +0000371 if hasattr(cls, "os"):
372 cls.validation_resources = vresources.create_validation_resources(
373 cls.os, cls.validation_resources)
374 else:
zhangguoqing6c096642016-01-04 06:17:21 +0000375 LOG.warning("Client manager not found, validation resources not"
376 " created")
Emily Hugenbruch5bd4cbf2014-12-17 21:38:38 +0000377
378 @classmethod
379 def resource_cleanup(cls):
380 """Class level resource cleanup for test cases.
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000381
Emily Hugenbruch5bd4cbf2014-12-17 21:38:38 +0000382 Resource cleanup must be able to handle the case of partially setup
383 resources, in case a failure during `resource_setup` should happen.
384 """
nithya-ganesan222efd72015-01-22 12:20:27 +0000385 if cls.validation_resources:
386 if hasattr(cls, "os"):
387 vresources.clear_validation_resources(cls.os,
388 cls.validation_resources)
389 cls.validation_resources = {}
390 else:
zhangguoqing6c096642016-01-04 06:17:21 +0000391 LOG.warning("Client manager not found, validation resources "
392 "not deleted")
Emily Hugenbruch5bd4cbf2014-12-17 21:38:38 +0000393
Attila Fazekasf86fa312013-07-30 19:56:39 +0200394 def setUp(self):
395 super(BaseTestCase, self).setUp()
396 if not self.setUpClassCalled:
397 raise RuntimeError("setUpClass does not calls the super's"
398 "setUpClass in the "
399 + self.__class__.__name__)
400 at_exit_set.add(self.__class__)
Matthew Treinish78561ad2013-07-26 11:41:56 -0400401 test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0)
402 try:
Sean Dague02620fd2016-03-02 15:52:51 -0500403 test_timeout = int(test_timeout) * self.TIMEOUT_SCALING_FACTOR
Matthew Treinish78561ad2013-07-26 11:41:56 -0400404 except ValueError:
405 test_timeout = 0
406 if test_timeout > 0:
Attila Fazekasf86fa312013-07-30 19:56:39 +0200407 self.useFixture(fixtures.Timeout(test_timeout, gentle=True))
Matthew Treinish78561ad2013-07-26 11:41:56 -0400408
409 if (os.environ.get('OS_STDOUT_CAPTURE') == 'True' or
410 os.environ.get('OS_STDOUT_CAPTURE') == '1'):
Attila Fazekasf86fa312013-07-30 19:56:39 +0200411 stdout = self.useFixture(fixtures.StringStream('stdout')).stream
412 self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
Matthew Treinish78561ad2013-07-26 11:41:56 -0400413 if (os.environ.get('OS_STDERR_CAPTURE') == 'True' or
414 os.environ.get('OS_STDERR_CAPTURE') == '1'):
Attila Fazekasf86fa312013-07-30 19:56:39 +0200415 stderr = self.useFixture(fixtures.StringStream('stderr')).stream
416 self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
Attila Fazekas31388072013-08-15 08:58:07 +0200417 if (os.environ.get('OS_LOG_CAPTURE') != 'False' and
418 os.environ.get('OS_LOG_CAPTURE') != '0'):
Attila Fazekas31388072013-08-15 08:58:07 +0200419 self.useFixture(fixtures.LoggerFixture(nuke_handlers=False,
Sean Dague2ef32ac2014-06-09 11:32:23 -0400420 format=self.log_format,
Attila Fazekas90445be2013-10-24 16:46:03 +0200421 level=None))
Matthew Treinish78561ad2013-07-26 11:41:56 -0400422
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100423 @property
424 def credentials_provider(self):
425 return self._get_credentials_provider()
426
Jamie Lennox15350172015-08-17 10:54:25 +1000427 @property
428 def identity_utils(self):
429 """A client that abstracts v2 and v3 identity operations.
430
431 This can be used for creating and tearing down projects in tests. It
432 should not be used for testing identity features.
433 """
434 if CONF.identity.auth_version == 'v2':
435 client = self.os_admin.identity_client
Daniel Mellado7aea5342016-02-09 09:10:12 +0000436 users_client = self.os_admin.users_client
Daniel Melladob04da902015-11-20 17:43:12 +0100437 project_client = self.os_admin.tenants_client
Daniel Mellado6b16b922015-12-07 12:43:08 +0000438 roles_client = self.os_admin.roles_client
Daniel Mellado91a26b62016-02-11 11:13:04 +0000439 domains_client = None
Jamie Lennox15350172015-08-17 10:54:25 +1000440 else:
441 client = self.os_admin.identity_v3_client
Daniel Mellado7aea5342016-02-09 09:10:12 +0000442 users_client = self.os_admin.users_v3_client
Arx Cruz24bcb882016-02-10 15:20:16 +0100443 project_client = self.os_admin.projects_client
444 roles_client = self.os_admin.roles_v3_client
Daniel Mellado91a26b62016-02-11 11:13:04 +0000445 domains_client = self.os_admin.domains_client
Jamie Lennox15350172015-08-17 10:54:25 +1000446
447 try:
448 domain = client.auth_provider.credentials.project_domain_name
449 except AttributeError:
450 domain = 'Default'
451
Daniel Melladob04da902015-11-20 17:43:12 +0100452 return cred_client.get_creds_client(client, project_client,
Daniel Mellado82c83a52015-12-09 15:16:49 +0000453 users_client,
Daniel Mellado7aea5342016-02-09 09:10:12 +0000454 roles_client,
Daniel Mellado91a26b62016-02-11 11:13:04 +0000455 domains_client,
Daniel Melladob04da902015-11-20 17:43:12 +0100456 project_domain_name=domain)
Jamie Lennox15350172015-08-17 10:54:25 +1000457
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100458 @classmethod
Andrea Frittoli (andreaf)32d0de12015-10-09 14:43:53 +0100459 def get_identity_version(cls):
460 """Returns the identity version used by the test class"""
461 identity_version = getattr(cls, 'identity_version', None)
462 return identity_version or CONF.identity.auth_version
463
464 @classmethod
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100465 def _get_credentials_provider(cls):
466 """Returns a credentials provider
467
468 If no credential provider exists yet creates one.
469 It uses self.identity_version if defined, or the configuration value
470 """
471 if (not hasattr(cls, '_creds_provider') or not cls._creds_provider or
472 not cls._creds_provider.name == cls.__name__):
473 force_tenant_isolation = getattr(cls, 'force_tenant_isolation',
474 False)
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100475
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700476 cls._creds_provider = credentials.get_credentials_provider(
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100477 name=cls.__name__, network_resources=cls.network_resources,
478 force_tenant_isolation=force_tenant_isolation,
Andrea Frittoli (andreaf)32d0de12015-10-09 14:43:53 +0100479 identity_version=cls.get_identity_version())
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100480 return cls._creds_provider
481
Matthew Treinish3e046852013-07-23 16:00:24 -0400482 @classmethod
Andrea Frittoli (andreaf)41601412015-05-12 16:39:03 +0100483 def get_client_manager(cls, credential_type=None, roles=None,
484 force_new=None):
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100485 """Returns an OpenStack client manager
486
487 Returns an OpenStack client manager based on either credential_type
488 or a list of roles. If neither is specified, it defaults to
489 credential_type 'primary'
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100490 :param credential_type: string - primary, alt or admin
491 :param roles: list of roles
492
lei zhangdd552b22015-11-25 20:41:48 +0800493 :returns: the created client manager
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100494 :raises skipException: if the requested credentials are not available
Ryan Hsu6c4bb3d2013-10-21 21:22:50 -0700495 """
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100496 if all([roles, credential_type]):
497 msg = "Cannot get credentials by type and roles at the same time"
498 raise ValueError(msg)
499 if not any([roles, credential_type]):
500 credential_type = 'primary'
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100501 cred_provider = cls._get_credentials_provider()
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100502 if roles:
503 for role in roles:
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100504 if not cred_provider.is_role_available(role):
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100505 skip_msg = (
506 "%s skipped because the configured credential provider"
507 " is not able to provide credentials with the %s role "
508 "assigned." % (cls.__name__, role))
509 raise cls.skipException(skip_msg)
510 params = dict(roles=roles)
511 if force_new is not None:
512 params.update(force_new=force_new)
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100513 creds = cred_provider.get_creds_by_roles(**params)
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000514 else:
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100515 credentials_method = 'get_%s_creds' % credential_type
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100516 if hasattr(cred_provider, credentials_method):
517 creds = getattr(cred_provider, credentials_method)()
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100518 else:
Andrea Frittoli (andreaf)af4f7cf2016-06-13 15:12:26 +0100519 raise lib_exc.InvalidCredentials(
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100520 "Invalid credentials type %s" % credential_type)
Jordan Pittiere4be9072017-01-04 19:17:35 +0100521 manager = cls.client_manager(credentials=creds.credentials)
Andrea Frittoli73224672016-12-09 21:08:19 +0000522 # NOTE(andreaf) Ensure credentials have user and project id fields.
523 # It may not be the case when using pre-provisioned credentials.
524 manager.auth_provider.set_auth()
525 return manager
Ryan Hsu6c4bb3d2013-10-21 21:22:50 -0700526
527 @classmethod
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700528 def clear_credentials(cls):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000529 """Clears creds if set"""
Attila Fazekas5b0d9262015-05-20 10:17:39 +0200530 if hasattr(cls, '_creds_provider'):
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700531 cls._creds_provider.clear_creds()
Ryan Hsu6c4bb3d2013-10-21 21:22:50 -0700532
533 @classmethod
nithya-ganesan222efd72015-01-22 12:20:27 +0000534 def set_validation_resources(cls, keypair=None, floating_ip=None,
535 security_group=None,
536 security_group_rules=None):
537 """Specify which ssh server validation resources should be created.
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000538
nithya-ganesan222efd72015-01-22 12:20:27 +0000539 Each of the argument must be set to either None, True or False, with
540 None - use default from config (security groups and security group
541 rules get created when set to None)
542 False - Do not create the validation resource
543 True - create the validation resource
544
545 @param keypair
546 @param security_group
547 @param security_group_rules
548 @param floating_ip
549 """
Matthew Treinishe5cca002015-05-11 15:36:50 -0400550 if not CONF.validation.run_validation:
551 return
Jordan Pittier79cd1822016-12-08 17:20:35 +0100552
nithya-ganesan222efd72015-01-22 12:20:27 +0000553 if keypair is None:
Jordan Pittier79cd1822016-12-08 17:20:35 +0100554 keypair = (CONF.validation.auth_method.lower() == "keypair")
555
nithya-ganesan222efd72015-01-22 12:20:27 +0000556 if floating_ip is None:
Jordan Pittier79cd1822016-12-08 17:20:35 +0100557 floating_ip = (CONF.validation.connect_method.lower() ==
558 "floating")
559
nithya-ganesan222efd72015-01-22 12:20:27 +0000560 if security_group is None:
Brandon Palmc6cc91d2015-08-19 13:20:21 -0500561 security_group = CONF.validation.security_group
Jordan Pittier79cd1822016-12-08 17:20:35 +0100562
nithya-ganesan222efd72015-01-22 12:20:27 +0000563 if security_group_rules is None:
Brandon Palmc6cc91d2015-08-19 13:20:21 -0500564 security_group_rules = CONF.validation.security_group_rules
565
nithya-ganesan222efd72015-01-22 12:20:27 +0000566 if not cls.validation_resources:
567 cls.validation_resources = {
568 'keypair': keypair,
569 'security_group': security_group,
570 'security_group_rules': security_group_rules,
571 'floating_ip': floating_ip}
572
573 @classmethod
Andrea Frittoli7d5ed592015-02-10 01:10:23 +0000574 def set_network_resources(cls, network=False, router=False, subnet=False,
Matthew Treinish9f756a02014-01-15 10:26:07 -0500575 dhcp=False):
576 """Specify which network resources should be created
577
578 @param network
579 @param router
580 @param subnet
581 @param dhcp
582 """
Salvatore Orlando5a337242014-01-15 22:49:22 +0000583 # network resources should be set only once from callers
584 # in order to ensure that even if it's called multiple times in
585 # a chain of overloaded methods, the attribute is set only
586 # in the leaf class
Andrea Frittoli7d5ed592015-02-10 01:10:23 +0000587 if not cls.network_resources:
588 cls.network_resources = {
Salvatore Orlando5a337242014-01-15 22:49:22 +0000589 'network': network,
590 'router': router,
591 'subnet': subnet,
592 'dhcp': dhcp}
Matthew Treinish9f756a02014-01-15 10:26:07 -0500593
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530594 @classmethod
Ryan Rossiter9228bf72016-02-25 03:06:12 +0000595 def get_tenant_network(cls, credentials_type='primary'):
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530596 """Get the network to be used in testing
597
Ryan Rossiter9228bf72016-02-25 03:06:12 +0000598 :param credentials_type: The type of credentials for which to get the
599 tenant network
600
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530601 :return: network dict including 'id' and 'name'
602 """
Ryan Rossiter9228bf72016-02-25 03:06:12 +0000603 # Get a manager for the given credentials_type, but at least
604 # always fall back on getting the manager for primary credentials
605 if isinstance(credentials_type, six.string_types):
606 manager = cls.get_client_manager(credential_type=credentials_type)
607 elif isinstance(credentials_type, list):
608 manager = cls.get_client_manager(roles=credentials_type[1:])
609 else:
610 manager = cls.get_client_manager()
611
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700612 # Make sure cred_provider exists and get a network client
Ryan Rossiter9228bf72016-02-25 03:06:12 +0000613 networks_client = manager.compute_networks_client
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100614 cred_provider = cls._get_credentials_provider()
Andrea Frittoli700711e2015-04-02 11:39:38 +0100615 # In case of nova network, isolated tenants are not able to list the
Joshua Whitebd769602016-02-02 09:30:11 -0800616 # network configured in fixed_network_name, even if they can use it
Andrea Frittoli700711e2015-04-02 11:39:38 +0100617 # for their servers, so using an admin network client to validate
618 # the network name
619 if (not CONF.service_available.neutron and
Andrea Frittoli (andreaf)32d0de12015-10-09 14:43:53 +0100620 credentials.is_admin_available(
621 identity_version=cls.get_identity_version())):
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100622 admin_creds = cred_provider.get_admin_creds()
Andrea Frittoli (andreaf)848c4a12016-06-09 11:09:02 +0100623 admin_manager = clients.Manager(admin_creds.credentials)
John Warren9487a182015-09-14 18:12:56 -0400624 networks_client = admin_manager.compute_networks_client
Andrea Frittoli (andreaf)940f8c62015-10-30 16:39:24 +0900625 return fixed_network.get_tenant_network(
626 cred_provider, networks_client, CONF.compute.fixed_network_name)
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530627
Andrea Frittoli71c71e92017-04-07 17:45:21 +0100628 def assertEmpty(self, items, msg=None):
629 """Asserts whether a sequence or collection is empty
Mark Maglana5885eb32014-02-28 10:57:34 -0800630
Andrea Frittoli71c71e92017-04-07 17:45:21 +0100631 :param items: sequence or collection to be tested
632 :param msg: message to be passed to the AssertionError
633 :raises AssertionError: when items is not empty
634 """
zhufl92ade4b2017-03-03 15:20:10 +0800635 if msg is None:
Andrea Frittoli71c71e92017-04-07 17:45:21 +0100636 msg = "sequence or collection is not empty: %s" % items
637 self.assertEqual(0, len(items), msg)
638
639 def assertNotEmpty(self, items, msg=None):
640 """Asserts whether a sequence or collection is not empty
641
642 :param items: sequence or collection to be tested
643 :param msg: message to be passed to the AssertionError
644 :raises AssertionError: when items is empty
645 """
646 if msg is None:
647 msg = "sequence or collection is empty."
648 self.assertGreater(len(items), 0, msg)