blob: 8ce7af87a8945c890b6646710769be78959bcbb5 [file] [log] [blame]
Jay Pipes051075a2012-04-28 17:39:37 -04001# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
ZhiQiang Fan39f97222013-09-20 04:49:44 +08003# Copyright 2012 OpenStack Foundation
Jay Pipes051075a2012-04-28 17:39:37 -04004# All Rights Reserved.
5#
6# Licensed under the Apache License, Version 2.0 (the "License"); you may
7# not use this file except in compliance with the License. You may obtain
8# a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15# License for the specific language governing permissions and limitations
16# under the License.
17
Attila Fazekasf86fa312013-07-30 19:56:39 +020018import atexit
Masayuki Igawa80c1b9f2013-10-07 17:19:11 +090019import functools
Ian Wienand98c35f32013-07-23 20:34:23 +100020import os
Jay Pipes051075a2012-04-28 17:39:37 -040021import time
22
Matthew Treinish78561ad2013-07-26 11:41:56 -040023import fixtures
Chris Yeoh55530bb2013-02-08 16:04:27 +103024import nose.plugins.attrib
Attila Fazekasdc216422013-01-29 15:12:14 +010025import testresources
ivan-zhu1feeb382013-01-24 10:14:39 +080026import testtools
Jay Pipes051075a2012-04-28 17:39:37 -040027
Matthew Treinish3e046852013-07-23 16:00:24 -040028from tempest import clients
Attila Fazekasdc216422013-01-29 15:12:14 +010029from tempest import config
Matthew Treinish16c43792013-09-09 19:55:23 +000030from tempest import exceptions
Matthew Treinishf4a9b0f2013-07-26 16:58:26 -040031from tempest.openstack.common import log as logging
Jay Pipes051075a2012-04-28 17:39:37 -040032
33LOG = logging.getLogger(__name__)
34
Samuel Merritt0d499bc2013-06-19 12:08:23 -070035# All the successful HTTP status codes from RFC 2616
36HTTP_SUCCESS = (200, 201, 202, 203, 204, 205, 206)
37
Jay Pipes051075a2012-04-28 17:39:37 -040038
Chris Yeoh55530bb2013-02-08 16:04:27 +103039def attr(*args, **kwargs):
40 """A decorator which applies the nose and testtools attr decorator
41
42 This decorator applies the nose attr decorator as well as the
43 the testtools.testcase.attr if it is in the list of attributes
Attila Fazekasb2902af2013-02-16 16:22:44 +010044 to testtools we want to apply.
45 """
Chris Yeoh55530bb2013-02-08 16:04:27 +103046
47 def decorator(f):
Giulio Fidente4946a052013-05-14 12:23:51 +020048 if 'type' in kwargs and isinstance(kwargs['type'], str):
49 f = testtools.testcase.attr(kwargs['type'])(f)
Chris Yeohcf3fb7c2013-05-19 15:59:00 +093050 if kwargs['type'] == 'smoke':
51 f = testtools.testcase.attr('gate')(f)
Giulio Fidente4946a052013-05-14 12:23:51 +020052 elif 'type' in kwargs and isinstance(kwargs['type'], list):
53 for attr in kwargs['type']:
54 f = testtools.testcase.attr(attr)(f)
Chris Yeohcf3fb7c2013-05-19 15:59:00 +093055 if attr == 'smoke':
56 f = testtools.testcase.attr('gate')(f)
Giulio Fidente4946a052013-05-14 12:23:51 +020057 return nose.plugins.attrib.attr(*args, **kwargs)(f)
Chris Yeoh55530bb2013-02-08 16:04:27 +103058
59 return decorator
60
61
Matthew Treinish16c43792013-09-09 19:55:23 +000062def services(*args, **kwargs):
63 """A decorator used to set an attr for each service used in a test case
64
65 This decorator applies a testtools attr for each service that gets
66 exercised by a test case.
67 """
68 valid_service_list = ['compute', 'image', 'volume', 'orchestration',
69 'network', 'identity', 'object', 'dashboard']
70
71 def decorator(f):
72 for service in args:
73 if service not in valid_service_list:
74 raise exceptions.InvalidServiceTag('%s is not a valid service'
75 % service)
76 attr(type=list(args))(f)
77 return f
78 return decorator
79
80
Marc Koderer32221b8e2013-08-23 13:57:50 +020081def stresstest(*args, **kwargs):
82 """Add stress test decorator
83
84 For all functions with this decorator a attr stress will be
85 set automatically.
86
87 @param class_setup_per: allowed values are application, process, action
88 ``application``: once in the stress job lifetime
89 ``process``: once in the worker process lifetime
90 ``action``: on each action
Marc Kodererb0604412013-09-02 09:43:40 +020091 @param allow_inheritance: allows inheritance of this attribute
Marc Koderer32221b8e2013-08-23 13:57:50 +020092 """
93 def decorator(f):
94 if 'class_setup_per' in kwargs:
95 setattr(f, "st_class_setup_per", kwargs['class_setup_per'])
96 else:
97 setattr(f, "st_class_setup_per", 'process')
Marc Kodererb0604412013-09-02 09:43:40 +020098 if 'allow_inheritance' in kwargs:
99 setattr(f, "st_allow_inheritance", kwargs['allow_inheritance'])
100 else:
101 setattr(f, "st_allow_inheritance", False)
Marc Koderer32221b8e2013-08-23 13:57:50 +0200102 attr(type='stress')(f)
103 return f
104 return decorator
105
106
Giulio Fidente83181a92013-10-01 06:02:24 +0200107def skip_because(*args, **kwargs):
108 """A decorator useful to skip tests hitting known bugs
109
110 @param bug: bug number causing the test to skip
111 @param condition: optional condition to be True for the skip to have place
112 """
113 def decorator(f):
Masayuki Igawa80c1b9f2013-10-07 17:19:11 +0900114 @functools.wraps(f)
115 def wrapper(*func_args, **func_kwargs):
116 if "bug" in kwargs:
117 if "condition" not in kwargs or kwargs["condition"] is True:
118 msg = "Skipped until Bug: %s is resolved." % kwargs["bug"]
119 raise testtools.TestCase.skipException(msg)
120 return f(*func_args, **func_kwargs)
121 return wrapper
Giulio Fidente83181a92013-10-01 06:02:24 +0200122 return decorator
123
124
Ian Wienand98c35f32013-07-23 20:34:23 +1000125# there is a mis-match between nose and testtools for older pythons.
126# testtools will set skipException to be either
127# unittest.case.SkipTest, unittest2.case.SkipTest or an internal skip
128# exception, depending on what it can find. Python <2.7 doesn't have
129# unittest.case.SkipTest; so if unittest2 is not installed it falls
130# back to the internal class.
131#
132# The current nose skip plugin will decide to raise either
133# unittest.case.SkipTest or its own internal exception; it does not
134# look for unittest2 or the internal unittest exception. Thus we must
135# monkey-patch testtools.TestCase.skipException to be the exception
136# the nose skip plugin expects.
137#
138# However, with the switch to testr nose may not be available, so we
139# require you to opt-in to this fix with an environment variable.
140#
141# This is temporary until upstream nose starts looking for unittest2
142# as testtools does; we can then remove this and ensure unittest2 is
143# available for older pythons; then nose and testtools will agree
144# unittest2.case.SkipTest is the one-true skip test exception.
145#
146# https://review.openstack.org/#/c/33056
147# https://github.com/nose-devs/nose/pull/699
148if 'TEMPEST_PY26_NOSE_COMPAT' in os.environ:
149 try:
150 import unittest.case.SkipTest
151 # convince pep8 we're using the import...
152 if unittest.case.SkipTest:
153 pass
154 raise RuntimeError("You have unittest.case.SkipTest; "
155 "no need to override")
156 except ImportError:
157 LOG.info("Overriding skipException to nose SkipTest")
158 testtools.TestCase.skipException = nose.plugins.skip.SkipTest
159
Attila Fazekasf86fa312013-07-30 19:56:39 +0200160at_exit_set = set()
161
162
163def validate_tearDownClass():
164 if at_exit_set:
Alex Gaynor94560d42013-08-23 05:41:23 -0700165 raise RuntimeError("tearDownClass does not calls the super's "
Attila Fazekasf86fa312013-07-30 19:56:39 +0200166 "tearDownClass in these classes: "
167 + str(at_exit_set))
168
169atexit.register(validate_tearDownClass)
170
Ian Wienand98c35f32013-07-23 20:34:23 +1000171
Attila Fazekasdc216422013-01-29 15:12:14 +0100172class BaseTestCase(testtools.TestCase,
173 testtools.testcase.WithAttributes,
174 testresources.ResourcedTestCase):
Attila Fazekasc43fec82013-04-09 23:17:52 +0200175
176 config = config.TempestConfig()
Attila Fazekasdc216422013-01-29 15:12:14 +0100177
Attila Fazekasf86fa312013-07-30 19:56:39 +0200178 setUpClassCalled = False
179
Pavel Sedlák1053bd32013-04-16 16:47:40 +0200180 @classmethod
181 def setUpClass(cls):
182 if hasattr(super(BaseTestCase, cls), 'setUpClass'):
183 super(BaseTestCase, cls).setUpClass()
Attila Fazekasf86fa312013-07-30 19:56:39 +0200184 cls.setUpClassCalled = True
Pavel Sedlák1053bd32013-04-16 16:47:40 +0200185
Attila Fazekasf86fa312013-07-30 19:56:39 +0200186 @classmethod
187 def tearDownClass(cls):
Attila Fazekas5d275302013-08-29 12:35:12 +0200188 at_exit_set.discard(cls)
Attila Fazekasf86fa312013-07-30 19:56:39 +0200189 if hasattr(super(BaseTestCase, cls), 'tearDownClass'):
190 super(BaseTestCase, cls).tearDownClass()
191
192 def setUp(self):
193 super(BaseTestCase, self).setUp()
194 if not self.setUpClassCalled:
195 raise RuntimeError("setUpClass does not calls the super's"
196 "setUpClass in the "
197 + self.__class__.__name__)
198 at_exit_set.add(self.__class__)
Matthew Treinish78561ad2013-07-26 11:41:56 -0400199 test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0)
200 try:
201 test_timeout = int(test_timeout)
202 except ValueError:
203 test_timeout = 0
204 if test_timeout > 0:
Attila Fazekasf86fa312013-07-30 19:56:39 +0200205 self.useFixture(fixtures.Timeout(test_timeout, gentle=True))
Matthew Treinish78561ad2013-07-26 11:41:56 -0400206
207 if (os.environ.get('OS_STDOUT_CAPTURE') == 'True' or
208 os.environ.get('OS_STDOUT_CAPTURE') == '1'):
Attila Fazekasf86fa312013-07-30 19:56:39 +0200209 stdout = self.useFixture(fixtures.StringStream('stdout')).stream
210 self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
Matthew Treinish78561ad2013-07-26 11:41:56 -0400211 if (os.environ.get('OS_STDERR_CAPTURE') == 'True' or
212 os.environ.get('OS_STDERR_CAPTURE') == '1'):
Attila Fazekasf86fa312013-07-30 19:56:39 +0200213 stderr = self.useFixture(fixtures.StringStream('stderr')).stream
214 self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
Attila Fazekas31388072013-08-15 08:58:07 +0200215 if (os.environ.get('OS_LOG_CAPTURE') != 'False' and
216 os.environ.get('OS_LOG_CAPTURE') != '0'):
217 log_format = '%(asctime)-15s %(message)s'
218 self.useFixture(fixtures.LoggerFixture(nuke_handlers=False,
219 format=log_format))
Matthew Treinish78561ad2013-07-26 11:41:56 -0400220
Matthew Treinish3e046852013-07-23 16:00:24 -0400221 @classmethod
222 def _get_identity_admin_client(cls):
223 """
224 Returns an instance of the Identity Admin API client
225 """
226 os = clients.AdminManager(interface=cls._interface)
227 admin_client = os.identity_client
228 return admin_client
229
230 @classmethod
231 def _get_client_args(cls):
232
233 return (
234 cls.config,
235 cls.config.identity.admin_username,
236 cls.config.identity.admin_password,
237 cls.config.identity.uri
238 )
239
Attila Fazekasdc216422013-01-29 15:12:14 +0100240
Sean Dague35a7caf2013-05-10 10:38:22 -0400241def call_until_true(func, duration, sleep_for):
242 """
243 Call the given function until it returns True (and return True) or
244 until the specified duration (in seconds) elapses (and return
245 False).
246
247 :param func: A zero argument callable that returns True on success.
248 :param duration: The number of seconds for which to attempt a
249 successful call of the function.
250 :param sleep_for: The number of seconds to sleep after an unsuccessful
251 invocation of the function.
252 """
253 now = time.time()
254 timeout = now + duration
255 while now < timeout:
256 if func():
257 return True
258 LOG.debug("Sleeping for %d seconds", sleep_for)
259 time.sleep(sleep_for)
260 now = time.time()
261 return False