blob: f5121d8ac0cda23ff24ea78d440afba840461239 [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
Jordan Pittier35a63752016-08-30 13:09:12 +020034from tempest.lib.common.utils import test_utils
Andrea Frittoli (andreaf)db9672e2016-02-23 14:07:24 -050035from tempest.lib import decorators
Andrea Frittoli (andreaf)af4f7cf2016-06-13 15:12:26 +010036from tempest.lib import exceptions as lib_exc
Jay Pipes051075a2012-04-28 17:39:37 -040037
38LOG = logging.getLogger(__name__)
39
Sean Dague86bd8422013-12-20 09:56:44 -050040CONF = config.CONF
41
Matthew Treinishc1802bc2015-12-03 18:48:11 -050042idempotent_id = decorators.idempotent_id
43
Jay Pipes051075a2012-04-28 17:39:37 -040044
Yaroslav Lobankovda999f72015-06-30 20:32:55 +030045def attr(**kwargs):
liuchenhong00caec52015-07-19 22:40:28 +080046 """A decorator which applies the testtools attr decorator
Chris Yeoh55530bb2013-02-08 16:04:27 +103047
Matthew Treinisha74f5d42014-02-07 20:25:44 -050048 This decorator applies the testtools.testcase.attr if it is in the list of
49 attributes to testtools we want to apply.
Attila Fazekasb2902af2013-02-16 16:22:44 +010050 """
Chris Yeoh55530bb2013-02-08 16:04:27 +103051
52 def decorator(f):
Giulio Fidente4946a052013-05-14 12:23:51 +020053 if 'type' in kwargs and isinstance(kwargs['type'], str):
54 f = testtools.testcase.attr(kwargs['type'])(f)
55 elif 'type' in kwargs and isinstance(kwargs['type'], list):
56 for attr in kwargs['type']:
57 f = testtools.testcase.attr(attr)(f)
Matthew Treinisha74f5d42014-02-07 20:25:44 -050058 return f
Chris Yeoh55530bb2013-02-08 16:04:27 +103059
60 return decorator
61
62
Matthew Treinish3d8c7322014-08-03 23:53:28 -040063def get_service_list():
Matthew Treinish8afbffd2014-01-21 23:56:13 +000064 service_list = {
65 'compute': CONF.service_available.nova,
66 'image': CONF.service_available.glance,
Adam Gandelman4a48a602014-03-20 18:23:18 -070067 'baremetal': CONF.service_available.ironic,
Matthew Treinish8afbffd2014-01-21 23:56:13 +000068 'volume': CONF.service_available.cinder,
Matthew Treinish8afbffd2014-01-21 23:56:13 +000069 'network': True,
70 'identity': True,
71 'object_storage': CONF.service_available.swift,
Matthew Treinish8afbffd2014-01-21 23:56:13 +000072 }
Matthew Treinish3d8c7322014-08-03 23:53:28 -040073 return service_list
Matthew Treinish16c43792013-09-09 19:55:23 +000074
Matthew Treinish3d8c7322014-08-03 23:53:28 -040075
Yaroslav Lobankovda999f72015-06-30 20:32:55 +030076def services(*args):
Matthew Treinish3d8c7322014-08-03 23:53:28 -040077 """A decorator used to set an attr for each service used in a test case
78
79 This decorator applies a testtools attr for each service that gets
80 exercised by a test case.
81 """
Matthew Treinish16c43792013-09-09 19:55:23 +000082 def decorator(f):
Masayuki Igawa22b30082016-06-27 16:18:59 +090083 services = ['compute', 'image', 'baremetal', 'volume',
84 'network', 'identity', 'object_storage']
Matthew Treinish16c43792013-09-09 19:55:23 +000085 for service in args:
Matthew Treinish3d8c7322014-08-03 23:53:28 -040086 if service not in services:
87 raise exceptions.InvalidServiceTag('%s is not a valid '
88 'service' % service)
Matthew Treinish16c43792013-09-09 19:55:23 +000089 attr(type=list(args))(f)
Matthew Treinish8afbffd2014-01-21 23:56:13 +000090
91 @functools.wraps(f)
92 def wrapper(self, *func_args, **func_kwargs):
Matthew Treinish3d8c7322014-08-03 23:53:28 -040093 service_list = get_service_list()
94
Matthew Treinish8afbffd2014-01-21 23:56:13 +000095 for service in args:
96 if not service_list[service]:
97 msg = 'Skipped because the %s service is not available' % (
98 service)
99 raise testtools.TestCase.skipException(msg)
100 return f(self, *func_args, **func_kwargs)
101 return wrapper
Matthew Treinish16c43792013-09-09 19:55:23 +0000102 return decorator
103
104
Yaroslav Lobankovda999f72015-06-30 20:32:55 +0300105def requires_ext(**kwargs):
Matthew Treinishe3d26142013-11-26 19:14:58 +0000106 """A decorator to skip tests if an extension is not enabled
107
108 @param extension
109 @param service
110 """
111 def decorator(func):
112 @functools.wraps(func)
113 def wrapper(*func_args, **func_kwargs):
114 if not is_extension_enabled(kwargs['extension'],
115 kwargs['service']):
116 msg = "Skipped because %s extension: %s is not enabled" % (
117 kwargs['service'], kwargs['extension'])
118 raise testtools.TestCase.skipException(msg)
119 return func(*func_args, **func_kwargs)
120 return wrapper
121 return decorator
122
123
124def is_extension_enabled(extension_name, service):
125 """A function that will check the list of enabled extensions from config
126
127 """
Matthew Treinishe3d26142013-11-26 19:14:58 +0000128 config_dict = {
Matthew Treinishbc0e03e2014-01-30 16:51:06 +0000129 'compute': CONF.compute_feature_enabled.api_extensions,
Matthew Treinishbc0e03e2014-01-30 16:51:06 +0000130 'volume': CONF.volume_feature_enabled.api_extensions,
131 'network': CONF.network_feature_enabled.api_extensions,
132 'object': CONF.object_storage_feature_enabled.discoverable_apis,
Jane Zadorozhna121576d2015-06-23 12:57:13 +0300133 'identity': CONF.identity_feature_enabled.api_extensions
Matthew Treinishe3d26142013-11-26 19:14:58 +0000134 }
Simeon Monov5d7effe2014-07-16 07:32:38 +0300135 if len(config_dict[service]) == 0:
136 return False
Matthew Treinishe3d26142013-11-26 19:14:58 +0000137 if config_dict[service][0] == 'all':
138 return True
139 if extension_name in config_dict[service]:
140 return True
141 return False
142
Ian Wienand98c35f32013-07-23 20:34:23 +1000143
Ken'ichi Ohmichia1111c52016-12-01 19:42:03 -0800144def related_bug(bug, status_code=None):
145 """A decorator useful to know solutions from launchpad bug reports
146
147 @param bug: The launchpad bug number causing the test
148 @param status_code: The status code related to the bug report
149 """
150 def decorator(f):
151 @functools.wraps(f)
152 def wrapper(self, *func_args, **func_kwargs):
153 try:
154 return f(self, *func_args, **func_kwargs)
155 except Exception as exc:
156 exc_status_code = getattr(exc, 'status_code', None)
157 if status_code is None or status_code == exc_status_code:
158 LOG.error('Hints: This test was made for the bug %s. '
159 'The failure could be related to '
160 'https://launchpad.net/bugs/%s' % (bug, bug))
161 raise exc
162 return wrapper
163 return decorator
164
165
Yair Fried95914122016-03-03 09:14:40 +0200166def is_scheduler_filter_enabled(filter_name):
Yair Friedca5cfb52016-01-04 15:41:55 +0200167 """Check the list of enabled compute scheduler filters from config. """
168
169 filters = CONF.compute_feature_enabled.scheduler_available_filters
170 if len(filters) == 0:
171 return False
172 if 'all' in filters:
173 return True
174 if filter_name in filters:
175 return True
176 return False
177
178
Attila Fazekasf86fa312013-07-30 19:56:39 +0200179at_exit_set = set()
180
181
182def validate_tearDownClass():
183 if at_exit_set:
Sean Dagueeb1523b2014-03-10 10:17:44 -0400184 LOG.error(
185 "tearDownClass does not call the super's "
186 "tearDownClass in these classes: \n"
187 + str(at_exit_set))
188
Attila Fazekasf86fa312013-07-30 19:56:39 +0200189
190atexit.register(validate_tearDownClass)
191
Attila Fazekas53943322014-02-10 16:07:34 +0100192
Matthew Treinish2474f412014-11-17 18:11:56 -0500193class BaseTestCase(testtools.testcase.WithAttributes,
194 testtools.TestCase):
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100195 """The test base class defines Tempest framework for class level fixtures.
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000196
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100197 `setUpClass` and `tearDownClass` are defined here and cannot be overwritten
198 by subclasses (enforced via hacking rule T105).
199
200 Set-up is split in a series of steps (setup stages), which can be
201 overwritten by test classes. Set-up stages are:
202 - skip_checks
203 - setup_credentials
204 - setup_clients
205 - resource_setup
206
207 Tear-down is also split in a series of steps (teardown stages), which are
208 stacked for execution only if the corresponding setup stage had been
209 reached during the setup phase. Tear-down stages are:
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700210 - clear_credentials (defined in the base test class)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100211 - resource_cleanup
212 """
Attila Fazekasc43fec82013-04-09 23:17:52 +0200213
Attila Fazekasf86fa312013-07-30 19:56:39 +0200214 setUpClassCalled = False
Marc Koderer24eb89c2014-01-31 11:23:33 +0100215 _service = None
Attila Fazekasf86fa312013-07-30 19:56:39 +0200216
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000217 # NOTE(andreaf) credentials holds a list of the credentials to be allocated
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100218 # at class setup time. Credential types can be 'primary', 'alt', 'admin' or
219 # a list of roles - the first element of the list being a label, and the
220 # rest the actual roles
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000221 credentials = []
nithya-ganesan222efd72015-01-22 12:20:27 +0000222 # Resources required to validate a server using ssh
223 validation_resources = {}
Matthew Treinish9f756a02014-01-15 10:26:07 -0500224 network_resources = {}
225
Sean Dague2ef32ac2014-06-09 11:32:23 -0400226 # NOTE(sdague): log_format is defined inline here instead of using the oslo
227 # default because going through the config path recouples config to the
228 # stress tests too early, and depending on testr order will fail unit tests
229 log_format = ('%(asctime)s %(process)d %(levelname)-8s '
230 '[%(name)s] %(message)s')
231
Ryota MIBU60687e52015-12-09 18:37:39 +0900232 # Client manager class to use in this test case.
233 client_manager = clients.Manager
234
Sean Dague02620fd2016-03-02 15:52:51 -0500235 # A way to adjust slow test classes
236 TIMEOUT_SCALING_FACTOR = 1
237
Pavel Sedlák1053bd32013-04-16 16:47:40 +0200238 @classmethod
239 def setUpClass(cls):
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100240 # It should never be overridden by descendants
Pavel Sedlák1053bd32013-04-16 16:47:40 +0200241 if hasattr(super(BaseTestCase, cls), 'setUpClass'):
242 super(BaseTestCase, cls).setUpClass()
Attila Fazekasf86fa312013-07-30 19:56:39 +0200243 cls.setUpClassCalled = True
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100244 # Stack of (name, callable) to be invoked in reverse order at teardown
245 cls.teardowns = []
246 # All the configuration checks that may generate a skip
247 cls.skip_checks()
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100248 try:
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100249 # Allocation of all required credentials and client managers
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700250 cls.teardowns.append(('credentials', cls.clear_credentials))
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100251 cls.setup_credentials()
252 # Shortcuts to clients
253 cls.setup_clients()
254 # Additional class-wide test resources
255 cls.teardowns.append(('resources', cls.resource_cleanup))
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100256 cls.resource_setup()
257 except Exception:
258 etype, value, trace = sys.exc_info()
Matthew Treinished2ad4f2014-12-23 15:18:32 -0500259 LOG.info("%s raised in %s.setUpClass. Invoking tearDownClass." % (
260 etype, cls.__name__))
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100261 cls.tearDownClass()
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100262 try:
Matthew Treinish843227d2015-04-23 10:17:17 -0400263 six.reraise(etype, value, trace)
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100264 finally:
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100265 del trace # to avoid circular refs
Pavel Sedlák1053bd32013-04-16 16:47:40 +0200266
Attila Fazekasf86fa312013-07-30 19:56:39 +0200267 @classmethod
268 def tearDownClass(cls):
Attila Fazekas5d275302013-08-29 12:35:12 +0200269 at_exit_set.discard(cls)
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100270 # It should never be overridden by descendants
Attila Fazekasf86fa312013-07-30 19:56:39 +0200271 if hasattr(super(BaseTestCase, cls), 'tearDownClass'):
272 super(BaseTestCase, cls).tearDownClass()
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100273 # Save any existing exception, we always want to re-raise the original
274 # exception only
275 etype, value, trace = sys.exc_info()
276 # If there was no exception during setup we shall re-raise the first
277 # exception in teardown
278 re_raise = (etype is None)
279 while cls.teardowns:
280 name, teardown = cls.teardowns.pop()
281 # Catch any exception in tearDown so we can re-raise the original
282 # exception at the end
283 try:
284 teardown()
285 except Exception as te:
286 sys_exec_info = sys.exc_info()
287 tetype = sys_exec_info[0]
288 # TODO(andreaf): Till we have the ability to cleanup only
289 # resources that were successfully setup in resource_cleanup,
290 # log AttributeError as info instead of exception.
291 if tetype is AttributeError and name == 'resources':
292 LOG.info("tearDownClass of %s failed: %s" % (name, te))
293 else:
294 LOG.exception("teardown of %s failed: %s" % (name, te))
295 if not etype:
296 etype, value, trace = sys_exec_info
Joshua Whitebd769602016-02-02 09:30:11 -0800297 # If exceptions were raised during teardown, and not before, re-raise
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100298 # the first one
299 if re_raise and etype is not None:
300 try:
Matthew Treinish843227d2015-04-23 10:17:17 -0400301 six.reraise(etype, value, trace)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100302 finally:
303 del trace # to avoid circular refs
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100304
305 @classmethod
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100306 def skip_checks(cls):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000307 """Class level skip checks.
308
309 Subclasses verify in here all conditions that might prevent the
310 execution of the entire test class.
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100311 Checks implemented here may not make use API calls, and should rely on
312 configuration alone.
313 In general skip checks that require an API call are discouraged.
314 If one is really needed it may be implemented either in the
315 resource_setup or at test level.
316 """
Andrea Frittoli (andreaf)32d0de12015-10-09 14:43:53 +0100317 identity_version = cls.get_identity_version()
318 if 'admin' in cls.credentials and not credentials.is_admin_available(
319 identity_version=identity_version):
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000320 msg = "Missing Identity Admin API credentials in configuration."
321 raise cls.skipException(msg)
Andrea Frittoli (andreaf)32d0de12015-10-09 14:43:53 +0100322 if 'alt' in cls.credentials and not credentials.is_alt_available(
323 identity_version=identity_version):
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000324 msg = "Missing a 2nd set of API credentials in configuration."
325 raise cls.skipException(msg)
Andrea Frittoli (andreaf)41601412015-05-12 16:39:03 +0100326 if hasattr(cls, 'identity_version'):
327 if cls.identity_version == 'v2':
328 if not CONF.identity_feature_enabled.api_v2:
329 raise cls.skipException("Identity api v2 is not enabled")
330 elif cls.identity_version == 'v3':
331 if not CONF.identity_feature_enabled.api_v3:
332 raise cls.skipException("Identity api v3 is not enabled")
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100333
334 @classmethod
335 def setup_credentials(cls):
edannon6cc6fbc2016-05-03 11:56:12 +0300336 """Allocate credentials and create the client managers from them.
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000337
edannon6cc6fbc2016-05-03 11:56:12 +0300338 For every element of credentials param function creates tenant/user,
339 Then it creates client manager for that credential.
340
341 Network related tests must override this function with
342 set_network_resources() method, otherwise it will create
343 network resources(network resources are created in a later step).
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000344 """
345 for credentials_type in cls.credentials:
346 # This may raise an exception in case credentials are not available
347 # In that case we want to let the exception through and the test
348 # fail accordingly
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100349 if isinstance(credentials_type, six.string_types):
350 manager = cls.get_client_manager(
351 credential_type=credentials_type)
352 setattr(cls, 'os_%s' % credentials_type, manager)
353 # Setup some common aliases
354 # TODO(andreaf) The aliases below are a temporary hack
355 # to avoid changing too much code in one patch. They should
356 # be removed eventually
357 if credentials_type == 'primary':
358 cls.os = cls.manager = cls.os_primary
359 if credentials_type == 'admin':
360 cls.os_adm = cls.admin_manager = cls.os_admin
361 if credentials_type == 'alt':
362 cls.alt_manager = cls.os_alt
363 elif isinstance(credentials_type, list):
364 manager = cls.get_client_manager(roles=credentials_type[1:],
365 force_new=True)
366 setattr(cls, 'os_roles_%s' % credentials_type[0], manager)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100367
368 @classmethod
369 def setup_clients(cls):
370 """Create links to the clients into the test object."""
371 # TODO(andreaf) There is a fair amount of code that could me moved from
372 # base / test classes in here. Ideally tests should be able to only
373 # specify which client is `client` and nothing else.
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100374 pass
Attila Fazekasf86fa312013-07-30 19:56:39 +0200375
Emily Hugenbruch5bd4cbf2014-12-17 21:38:38 +0000376 @classmethod
377 def resource_setup(cls):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000378 """Class level resource setup for test cases."""
nithya-ganesan222efd72015-01-22 12:20:27 +0000379 if hasattr(cls, "os"):
380 cls.validation_resources = vresources.create_validation_resources(
381 cls.os, cls.validation_resources)
382 else:
zhangguoqing6c096642016-01-04 06:17:21 +0000383 LOG.warning("Client manager not found, validation resources not"
384 " created")
Emily Hugenbruch5bd4cbf2014-12-17 21:38:38 +0000385
386 @classmethod
387 def resource_cleanup(cls):
388 """Class level resource cleanup for test cases.
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000389
Emily Hugenbruch5bd4cbf2014-12-17 21:38:38 +0000390 Resource cleanup must be able to handle the case of partially setup
391 resources, in case a failure during `resource_setup` should happen.
392 """
nithya-ganesan222efd72015-01-22 12:20:27 +0000393 if cls.validation_resources:
394 if hasattr(cls, "os"):
395 vresources.clear_validation_resources(cls.os,
396 cls.validation_resources)
397 cls.validation_resources = {}
398 else:
zhangguoqing6c096642016-01-04 06:17:21 +0000399 LOG.warning("Client manager not found, validation resources "
400 "not deleted")
Emily Hugenbruch5bd4cbf2014-12-17 21:38:38 +0000401
Attila Fazekasf86fa312013-07-30 19:56:39 +0200402 def setUp(self):
403 super(BaseTestCase, self).setUp()
404 if not self.setUpClassCalled:
405 raise RuntimeError("setUpClass does not calls the super's"
406 "setUpClass in the "
407 + self.__class__.__name__)
408 at_exit_set.add(self.__class__)
Matthew Treinish78561ad2013-07-26 11:41:56 -0400409 test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0)
410 try:
Sean Dague02620fd2016-03-02 15:52:51 -0500411 test_timeout = int(test_timeout) * self.TIMEOUT_SCALING_FACTOR
Matthew Treinish78561ad2013-07-26 11:41:56 -0400412 except ValueError:
413 test_timeout = 0
414 if test_timeout > 0:
Attila Fazekasf86fa312013-07-30 19:56:39 +0200415 self.useFixture(fixtures.Timeout(test_timeout, gentle=True))
Matthew Treinish78561ad2013-07-26 11:41:56 -0400416
417 if (os.environ.get('OS_STDOUT_CAPTURE') == 'True' or
418 os.environ.get('OS_STDOUT_CAPTURE') == '1'):
Attila Fazekasf86fa312013-07-30 19:56:39 +0200419 stdout = self.useFixture(fixtures.StringStream('stdout')).stream
420 self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
Matthew Treinish78561ad2013-07-26 11:41:56 -0400421 if (os.environ.get('OS_STDERR_CAPTURE') == 'True' or
422 os.environ.get('OS_STDERR_CAPTURE') == '1'):
Attila Fazekasf86fa312013-07-30 19:56:39 +0200423 stderr = self.useFixture(fixtures.StringStream('stderr')).stream
424 self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
Attila Fazekas31388072013-08-15 08:58:07 +0200425 if (os.environ.get('OS_LOG_CAPTURE') != 'False' and
426 os.environ.get('OS_LOG_CAPTURE') != '0'):
Attila Fazekas31388072013-08-15 08:58:07 +0200427 self.useFixture(fixtures.LoggerFixture(nuke_handlers=False,
Sean Dague2ef32ac2014-06-09 11:32:23 -0400428 format=self.log_format,
Attila Fazekas90445be2013-10-24 16:46:03 +0200429 level=None))
Matthew Treinish78561ad2013-07-26 11:41:56 -0400430
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100431 @property
432 def credentials_provider(self):
433 return self._get_credentials_provider()
434
Jamie Lennox15350172015-08-17 10:54:25 +1000435 @property
436 def identity_utils(self):
437 """A client that abstracts v2 and v3 identity operations.
438
439 This can be used for creating and tearing down projects in tests. It
440 should not be used for testing identity features.
441 """
442 if CONF.identity.auth_version == 'v2':
443 client = self.os_admin.identity_client
Daniel Mellado7aea5342016-02-09 09:10:12 +0000444 users_client = self.os_admin.users_client
Daniel Melladob04da902015-11-20 17:43:12 +0100445 project_client = self.os_admin.tenants_client
Daniel Mellado6b16b922015-12-07 12:43:08 +0000446 roles_client = self.os_admin.roles_client
Daniel Mellado91a26b62016-02-11 11:13:04 +0000447 domains_client = None
Jamie Lennox15350172015-08-17 10:54:25 +1000448 else:
449 client = self.os_admin.identity_v3_client
Daniel Mellado7aea5342016-02-09 09:10:12 +0000450 users_client = self.os_admin.users_v3_client
Arx Cruz24bcb882016-02-10 15:20:16 +0100451 project_client = self.os_admin.projects_client
452 roles_client = self.os_admin.roles_v3_client
Daniel Mellado91a26b62016-02-11 11:13:04 +0000453 domains_client = self.os_admin.domains_client
Jamie Lennox15350172015-08-17 10:54:25 +1000454
455 try:
456 domain = client.auth_provider.credentials.project_domain_name
457 except AttributeError:
458 domain = 'Default'
459
Daniel Melladob04da902015-11-20 17:43:12 +0100460 return cred_client.get_creds_client(client, project_client,
Daniel Mellado82c83a52015-12-09 15:16:49 +0000461 users_client,
Daniel Mellado7aea5342016-02-09 09:10:12 +0000462 roles_client,
Daniel Mellado91a26b62016-02-11 11:13:04 +0000463 domains_client,
Daniel Melladob04da902015-11-20 17:43:12 +0100464 project_domain_name=domain)
Jamie Lennox15350172015-08-17 10:54:25 +1000465
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100466 @classmethod
Andrea Frittoli (andreaf)32d0de12015-10-09 14:43:53 +0100467 def get_identity_version(cls):
468 """Returns the identity version used by the test class"""
469 identity_version = getattr(cls, 'identity_version', None)
470 return identity_version or CONF.identity.auth_version
471
472 @classmethod
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100473 def _get_credentials_provider(cls):
474 """Returns a credentials provider
475
476 If no credential provider exists yet creates one.
477 It uses self.identity_version if defined, or the configuration value
478 """
479 if (not hasattr(cls, '_creds_provider') or not cls._creds_provider or
480 not cls._creds_provider.name == cls.__name__):
481 force_tenant_isolation = getattr(cls, 'force_tenant_isolation',
482 False)
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100483
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700484 cls._creds_provider = credentials.get_credentials_provider(
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100485 name=cls.__name__, network_resources=cls.network_resources,
486 force_tenant_isolation=force_tenant_isolation,
Andrea Frittoli (andreaf)32d0de12015-10-09 14:43:53 +0100487 identity_version=cls.get_identity_version())
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100488 return cls._creds_provider
489
Matthew Treinish3e046852013-07-23 16:00:24 -0400490 @classmethod
Andrea Frittoli (andreaf)41601412015-05-12 16:39:03 +0100491 def get_client_manager(cls, credential_type=None, roles=None,
492 force_new=None):
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100493 """Returns an OpenStack client manager
494
495 Returns an OpenStack client manager based on either credential_type
496 or a list of roles. If neither is specified, it defaults to
497 credential_type 'primary'
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100498 :param credential_type: string - primary, alt or admin
499 :param roles: list of roles
500
lei zhangdd552b22015-11-25 20:41:48 +0800501 :returns: the created client manager
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100502 :raises skipException: if the requested credentials are not available
Ryan Hsu6c4bb3d2013-10-21 21:22:50 -0700503 """
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100504 if all([roles, credential_type]):
505 msg = "Cannot get credentials by type and roles at the same time"
506 raise ValueError(msg)
507 if not any([roles, credential_type]):
508 credential_type = 'primary'
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100509 cred_provider = cls._get_credentials_provider()
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100510 if roles:
511 for role in roles:
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100512 if not cred_provider.is_role_available(role):
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100513 skip_msg = (
514 "%s skipped because the configured credential provider"
515 " is not able to provide credentials with the %s role "
516 "assigned." % (cls.__name__, role))
517 raise cls.skipException(skip_msg)
518 params = dict(roles=roles)
519 if force_new is not None:
520 params.update(force_new=force_new)
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100521 creds = cred_provider.get_creds_by_roles(**params)
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000522 else:
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100523 credentials_method = 'get_%s_creds' % credential_type
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100524 if hasattr(cred_provider, credentials_method):
525 creds = getattr(cred_provider, credentials_method)()
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100526 else:
Andrea Frittoli (andreaf)af4f7cf2016-06-13 15:12:26 +0100527 raise lib_exc.InvalidCredentials(
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100528 "Invalid credentials type %s" % credential_type)
Andrea Frittoli (andreaf)848c4a12016-06-09 11:09:02 +0100529 return cls.client_manager(credentials=creds.credentials,
530 service=cls._service)
Ryan Hsu6c4bb3d2013-10-21 21:22:50 -0700531
532 @classmethod
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700533 def clear_credentials(cls):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000534 """Clears creds if set"""
Attila Fazekas5b0d9262015-05-20 10:17:39 +0200535 if hasattr(cls, '_creds_provider'):
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700536 cls._creds_provider.clear_creds()
Ryan Hsu6c4bb3d2013-10-21 21:22:50 -0700537
538 @classmethod
nithya-ganesan222efd72015-01-22 12:20:27 +0000539 def set_validation_resources(cls, keypair=None, floating_ip=None,
540 security_group=None,
541 security_group_rules=None):
542 """Specify which ssh server validation resources should be created.
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000543
nithya-ganesan222efd72015-01-22 12:20:27 +0000544 Each of the argument must be set to either None, True or False, with
545 None - use default from config (security groups and security group
546 rules get created when set to None)
547 False - Do not create the validation resource
548 True - create the validation resource
549
550 @param keypair
551 @param security_group
552 @param security_group_rules
553 @param floating_ip
554 """
Matthew Treinishe5cca002015-05-11 15:36:50 -0400555 if not CONF.validation.run_validation:
556 return
nithya-ganesan222efd72015-01-22 12:20:27 +0000557 if keypair is None:
558 if CONF.validation.auth_method.lower() == "keypair":
559 keypair = True
560 else:
561 keypair = False
562 if floating_ip is None:
563 if CONF.validation.connect_method.lower() == "floating":
564 floating_ip = True
565 else:
566 floating_ip = False
567 if security_group is None:
Brandon Palmc6cc91d2015-08-19 13:20:21 -0500568 security_group = CONF.validation.security_group
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
Mark Maglana5885eb32014-02-28 10:57:34 -0800634 def assertEmpty(self, list, msg=None):
Béla Vancsics64862f72016-11-08 09:12:31 +0100635 self.assertEqual(0, len(list), msg)
Mark Maglana5885eb32014-02-28 10:57:34 -0800636
637 def assertNotEmpty(self, list, msg=None):
Béla Vancsics64862f72016-11-08 09:12:31 +0100638 self.assertGreater(len(list), 0, msg)
Mark Maglana5885eb32014-02-28 10:57:34 -0800639
Attila Fazekasdc216422013-01-29 15:12:14 +0100640
Jordan Pittier35a63752016-08-30 13:09:12 +0200641call_until_true = debtcollector.moves.moved_function(
642 test_utils.call_until_true, 'call_until_true', __name__,
643 version='Newton', removal_version='Ocata')