blob: 6acb1c902d6ca71612e6e01dafb663068f0403a5 [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
Ian Wienand98c35f32013-07-23 20:34:23 +100019import os
Jay Pipes051075a2012-04-28 17:39:37 -040020import time
21
Matthew Treinish78561ad2013-07-26 11:41:56 -040022import fixtures
Chris Yeoh55530bb2013-02-08 16:04:27 +103023import nose.plugins.attrib
Attila Fazekasdc216422013-01-29 15:12:14 +010024import testresources
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
Attila Fazekasdc216422013-01-29 15:12:14 +010028from tempest import config
Matthew Treinish16c43792013-09-09 19:55:23 +000029from tempest import exceptions
Matthew Treinishf4a9b0f2013-07-26 16:58:26 -040030from tempest.openstack.common import log as logging
Jay Pipes051075a2012-04-28 17:39:37 -040031
32LOG = logging.getLogger(__name__)
33
Samuel Merritt0d499bc2013-06-19 12:08:23 -070034# All the successful HTTP status codes from RFC 2616
35HTTP_SUCCESS = (200, 201, 202, 203, 204, 205, 206)
36
Jay Pipes051075a2012-04-28 17:39:37 -040037
Chris Yeoh55530bb2013-02-08 16:04:27 +103038def attr(*args, **kwargs):
39 """A decorator which applies the nose and testtools attr decorator
40
41 This decorator applies the nose attr decorator as well as the
42 the testtools.testcase.attr if it is in the list of attributes
Attila Fazekasb2902af2013-02-16 16:22:44 +010043 to testtools we want to apply.
44 """
Chris Yeoh55530bb2013-02-08 16:04:27 +103045
46 def decorator(f):
Giulio Fidente4946a052013-05-14 12:23:51 +020047 if 'type' in kwargs and isinstance(kwargs['type'], str):
48 f = testtools.testcase.attr(kwargs['type'])(f)
Chris Yeohcf3fb7c2013-05-19 15:59:00 +093049 if kwargs['type'] == 'smoke':
50 f = testtools.testcase.attr('gate')(f)
Giulio Fidente4946a052013-05-14 12:23:51 +020051 elif 'type' in kwargs and isinstance(kwargs['type'], list):
52 for attr in kwargs['type']:
53 f = testtools.testcase.attr(attr)(f)
Chris Yeohcf3fb7c2013-05-19 15:59:00 +093054 if attr == 'smoke':
55 f = testtools.testcase.attr('gate')(f)
Giulio Fidente4946a052013-05-14 12:23:51 +020056 return nose.plugins.attrib.attr(*args, **kwargs)(f)
Chris Yeoh55530bb2013-02-08 16:04:27 +103057
58 return decorator
59
60
Matthew Treinish16c43792013-09-09 19:55:23 +000061def services(*args, **kwargs):
62 """A decorator used to set an attr for each service used in a test case
63
64 This decorator applies a testtools attr for each service that gets
65 exercised by a test case.
66 """
67 valid_service_list = ['compute', 'image', 'volume', 'orchestration',
68 'network', 'identity', 'object', 'dashboard']
69
70 def decorator(f):
71 for service in args:
72 if service not in valid_service_list:
73 raise exceptions.InvalidServiceTag('%s is not a valid service'
74 % service)
75 attr(type=list(args))(f)
76 return f
77 return decorator
78
79
Marc Koderer32221b8e2013-08-23 13:57:50 +020080def stresstest(*args, **kwargs):
81 """Add stress test decorator
82
83 For all functions with this decorator a attr stress will be
84 set automatically.
85
86 @param class_setup_per: allowed values are application, process, action
87 ``application``: once in the stress job lifetime
88 ``process``: once in the worker process lifetime
89 ``action``: on each action
Marc Kodererb0604412013-09-02 09:43:40 +020090 @param allow_inheritance: allows inheritance of this attribute
Marc Koderer32221b8e2013-08-23 13:57:50 +020091 """
92 def decorator(f):
93 if 'class_setup_per' in kwargs:
94 setattr(f, "st_class_setup_per", kwargs['class_setup_per'])
95 else:
96 setattr(f, "st_class_setup_per", 'process')
Marc Kodererb0604412013-09-02 09:43:40 +020097 if 'allow_inheritance' in kwargs:
98 setattr(f, "st_allow_inheritance", kwargs['allow_inheritance'])
99 else:
100 setattr(f, "st_allow_inheritance", False)
Marc Koderer32221b8e2013-08-23 13:57:50 +0200101 attr(type='stress')(f)
102 return f
103 return decorator
104
105
Ian Wienand98c35f32013-07-23 20:34:23 +1000106# there is a mis-match between nose and testtools for older pythons.
107# testtools will set skipException to be either
108# unittest.case.SkipTest, unittest2.case.SkipTest or an internal skip
109# exception, depending on what it can find. Python <2.7 doesn't have
110# unittest.case.SkipTest; so if unittest2 is not installed it falls
111# back to the internal class.
112#
113# The current nose skip plugin will decide to raise either
114# unittest.case.SkipTest or its own internal exception; it does not
115# look for unittest2 or the internal unittest exception. Thus we must
116# monkey-patch testtools.TestCase.skipException to be the exception
117# the nose skip plugin expects.
118#
119# However, with the switch to testr nose may not be available, so we
120# require you to opt-in to this fix with an environment variable.
121#
122# This is temporary until upstream nose starts looking for unittest2
123# as testtools does; we can then remove this and ensure unittest2 is
124# available for older pythons; then nose and testtools will agree
125# unittest2.case.SkipTest is the one-true skip test exception.
126#
127# https://review.openstack.org/#/c/33056
128# https://github.com/nose-devs/nose/pull/699
129if 'TEMPEST_PY26_NOSE_COMPAT' in os.environ:
130 try:
131 import unittest.case.SkipTest
132 # convince pep8 we're using the import...
133 if unittest.case.SkipTest:
134 pass
135 raise RuntimeError("You have unittest.case.SkipTest; "
136 "no need to override")
137 except ImportError:
138 LOG.info("Overriding skipException to nose SkipTest")
139 testtools.TestCase.skipException = nose.plugins.skip.SkipTest
140
Attila Fazekasf86fa312013-07-30 19:56:39 +0200141at_exit_set = set()
142
143
144def validate_tearDownClass():
145 if at_exit_set:
Alex Gaynor94560d42013-08-23 05:41:23 -0700146 raise RuntimeError("tearDownClass does not calls the super's "
Attila Fazekasf86fa312013-07-30 19:56:39 +0200147 "tearDownClass in these classes: "
148 + str(at_exit_set))
149
150atexit.register(validate_tearDownClass)
151
Ian Wienand98c35f32013-07-23 20:34:23 +1000152
Attila Fazekasdc216422013-01-29 15:12:14 +0100153class BaseTestCase(testtools.TestCase,
154 testtools.testcase.WithAttributes,
155 testresources.ResourcedTestCase):
Attila Fazekasc43fec82013-04-09 23:17:52 +0200156
157 config = config.TempestConfig()
Attila Fazekasdc216422013-01-29 15:12:14 +0100158
Attila Fazekasf86fa312013-07-30 19:56:39 +0200159 setUpClassCalled = False
160
Pavel Sedlák1053bd32013-04-16 16:47:40 +0200161 @classmethod
162 def setUpClass(cls):
163 if hasattr(super(BaseTestCase, cls), 'setUpClass'):
164 super(BaseTestCase, cls).setUpClass()
Attila Fazekasf86fa312013-07-30 19:56:39 +0200165 cls.setUpClassCalled = True
Pavel Sedlák1053bd32013-04-16 16:47:40 +0200166
Attila Fazekasf86fa312013-07-30 19:56:39 +0200167 @classmethod
168 def tearDownClass(cls):
Attila Fazekas5d275302013-08-29 12:35:12 +0200169 at_exit_set.discard(cls)
Attila Fazekasf86fa312013-07-30 19:56:39 +0200170 if hasattr(super(BaseTestCase, cls), 'tearDownClass'):
171 super(BaseTestCase, cls).tearDownClass()
172
173 def setUp(self):
174 super(BaseTestCase, self).setUp()
175 if not self.setUpClassCalled:
176 raise RuntimeError("setUpClass does not calls the super's"
177 "setUpClass in the "
178 + self.__class__.__name__)
179 at_exit_set.add(self.__class__)
Matthew Treinish78561ad2013-07-26 11:41:56 -0400180 test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0)
181 try:
182 test_timeout = int(test_timeout)
183 except ValueError:
184 test_timeout = 0
185 if test_timeout > 0:
Attila Fazekasf86fa312013-07-30 19:56:39 +0200186 self.useFixture(fixtures.Timeout(test_timeout, gentle=True))
Matthew Treinish78561ad2013-07-26 11:41:56 -0400187
188 if (os.environ.get('OS_STDOUT_CAPTURE') == 'True' or
189 os.environ.get('OS_STDOUT_CAPTURE') == '1'):
Attila Fazekasf86fa312013-07-30 19:56:39 +0200190 stdout = self.useFixture(fixtures.StringStream('stdout')).stream
191 self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
Matthew Treinish78561ad2013-07-26 11:41:56 -0400192 if (os.environ.get('OS_STDERR_CAPTURE') == 'True' or
193 os.environ.get('OS_STDERR_CAPTURE') == '1'):
Attila Fazekasf86fa312013-07-30 19:56:39 +0200194 stderr = self.useFixture(fixtures.StringStream('stderr')).stream
195 self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
Attila Fazekas31388072013-08-15 08:58:07 +0200196 if (os.environ.get('OS_LOG_CAPTURE') != 'False' and
197 os.environ.get('OS_LOG_CAPTURE') != '0'):
198 log_format = '%(asctime)-15s %(message)s'
199 self.useFixture(fixtures.LoggerFixture(nuke_handlers=False,
200 format=log_format))
Matthew Treinish78561ad2013-07-26 11:41:56 -0400201
Matthew Treinish3e046852013-07-23 16:00:24 -0400202 @classmethod
203 def _get_identity_admin_client(cls):
204 """
205 Returns an instance of the Identity Admin API client
206 """
207 os = clients.AdminManager(interface=cls._interface)
208 admin_client = os.identity_client
209 return admin_client
210
211 @classmethod
212 def _get_client_args(cls):
213
214 return (
215 cls.config,
216 cls.config.identity.admin_username,
217 cls.config.identity.admin_password,
218 cls.config.identity.uri
219 )
220
Attila Fazekasdc216422013-01-29 15:12:14 +0100221
Sean Dague35a7caf2013-05-10 10:38:22 -0400222def call_until_true(func, duration, sleep_for):
223 """
224 Call the given function until it returns True (and return True) or
225 until the specified duration (in seconds) elapses (and return
226 False).
227
228 :param func: A zero argument callable that returns True on success.
229 :param duration: The number of seconds for which to attempt a
230 successful call of the function.
231 :param sleep_for: The number of seconds to sleep after an unsuccessful
232 invocation of the function.
233 """
234 now = time.time()
235 timeout = now + duration
236 while now < timeout:
237 if func():
238 return True
239 LOG.debug("Sleeping for %d seconds", sleep_for)
240 time.sleep(sleep_for)
241 now = time.time()
242 return False