blob: 77877908cd93eef7c386c12552a8297367acf18c [file] [log] [blame]
Jay Pipes051075a2012-04-28 17:39:37 -04001# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2012 OpenStack, LLC
4# 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 Treinishf4a9b0f2013-07-26 16:58:26 -040029from tempest.openstack.common import log as logging
Jay Pipes051075a2012-04-28 17:39:37 -040030
31LOG = logging.getLogger(__name__)
32
Samuel Merritt0d499bc2013-06-19 12:08:23 -070033# All the successful HTTP status codes from RFC 2616
34HTTP_SUCCESS = (200, 201, 202, 203, 204, 205, 206)
35
Jay Pipes051075a2012-04-28 17:39:37 -040036
Chris Yeoh55530bb2013-02-08 16:04:27 +103037def attr(*args, **kwargs):
38 """A decorator which applies the nose and testtools attr decorator
39
40 This decorator applies the nose attr decorator as well as the
41 the testtools.testcase.attr if it is in the list of attributes
Attila Fazekasb2902af2013-02-16 16:22:44 +010042 to testtools we want to apply.
43 """
Chris Yeoh55530bb2013-02-08 16:04:27 +103044
45 def decorator(f):
Giulio Fidente4946a052013-05-14 12:23:51 +020046 if 'type' in kwargs and isinstance(kwargs['type'], str):
47 f = testtools.testcase.attr(kwargs['type'])(f)
Chris Yeohcf3fb7c2013-05-19 15:59:00 +093048 if kwargs['type'] == 'smoke':
49 f = testtools.testcase.attr('gate')(f)
Giulio Fidente4946a052013-05-14 12:23:51 +020050 elif 'type' in kwargs and isinstance(kwargs['type'], list):
51 for attr in kwargs['type']:
52 f = testtools.testcase.attr(attr)(f)
Chris Yeohcf3fb7c2013-05-19 15:59:00 +093053 if attr == 'smoke':
54 f = testtools.testcase.attr('gate')(f)
Giulio Fidente4946a052013-05-14 12:23:51 +020055 return nose.plugins.attrib.attr(*args, **kwargs)(f)
Chris Yeoh55530bb2013-02-08 16:04:27 +103056
57 return decorator
58
59
Ian Wienand98c35f32013-07-23 20:34:23 +100060# there is a mis-match between nose and testtools for older pythons.
61# testtools will set skipException to be either
62# unittest.case.SkipTest, unittest2.case.SkipTest or an internal skip
63# exception, depending on what it can find. Python <2.7 doesn't have
64# unittest.case.SkipTest; so if unittest2 is not installed it falls
65# back to the internal class.
66#
67# The current nose skip plugin will decide to raise either
68# unittest.case.SkipTest or its own internal exception; it does not
69# look for unittest2 or the internal unittest exception. Thus we must
70# monkey-patch testtools.TestCase.skipException to be the exception
71# the nose skip plugin expects.
72#
73# However, with the switch to testr nose may not be available, so we
74# require you to opt-in to this fix with an environment variable.
75#
76# This is temporary until upstream nose starts looking for unittest2
77# as testtools does; we can then remove this and ensure unittest2 is
78# available for older pythons; then nose and testtools will agree
79# unittest2.case.SkipTest is the one-true skip test exception.
80#
81# https://review.openstack.org/#/c/33056
82# https://github.com/nose-devs/nose/pull/699
83if 'TEMPEST_PY26_NOSE_COMPAT' in os.environ:
84 try:
85 import unittest.case.SkipTest
86 # convince pep8 we're using the import...
87 if unittest.case.SkipTest:
88 pass
89 raise RuntimeError("You have unittest.case.SkipTest; "
90 "no need to override")
91 except ImportError:
92 LOG.info("Overriding skipException to nose SkipTest")
93 testtools.TestCase.skipException = nose.plugins.skip.SkipTest
94
Attila Fazekasf86fa312013-07-30 19:56:39 +020095at_exit_set = set()
96
97
98def validate_tearDownClass():
99 if at_exit_set:
100 raise RuntimeError("tearDownClass does not calls the super's"
101 "tearDownClass in these classes: "
102 + str(at_exit_set))
103
104atexit.register(validate_tearDownClass)
105
Ian Wienand98c35f32013-07-23 20:34:23 +1000106
Attila Fazekasdc216422013-01-29 15:12:14 +0100107class BaseTestCase(testtools.TestCase,
108 testtools.testcase.WithAttributes,
109 testresources.ResourcedTestCase):
Attila Fazekasc43fec82013-04-09 23:17:52 +0200110
111 config = config.TempestConfig()
Attila Fazekasdc216422013-01-29 15:12:14 +0100112
Attila Fazekasf86fa312013-07-30 19:56:39 +0200113 setUpClassCalled = False
114
Pavel Sedlák1053bd32013-04-16 16:47:40 +0200115 @classmethod
116 def setUpClass(cls):
117 if hasattr(super(BaseTestCase, cls), 'setUpClass'):
118 super(BaseTestCase, cls).setUpClass()
Attila Fazekasf86fa312013-07-30 19:56:39 +0200119 cls.setUpClassCalled = True
Pavel Sedlák1053bd32013-04-16 16:47:40 +0200120
Attila Fazekasf86fa312013-07-30 19:56:39 +0200121 @classmethod
122 def tearDownClass(cls):
123 at_exit_set.remove(cls)
124 if hasattr(super(BaseTestCase, cls), 'tearDownClass'):
125 super(BaseTestCase, cls).tearDownClass()
126
127 def setUp(self):
128 super(BaseTestCase, self).setUp()
129 if not self.setUpClassCalled:
130 raise RuntimeError("setUpClass does not calls the super's"
131 "setUpClass in the "
132 + self.__class__.__name__)
133 at_exit_set.add(self.__class__)
Matthew Treinish78561ad2013-07-26 11:41:56 -0400134 test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0)
135 try:
136 test_timeout = int(test_timeout)
137 except ValueError:
138 test_timeout = 0
139 if test_timeout > 0:
Attila Fazekasf86fa312013-07-30 19:56:39 +0200140 self.useFixture(fixtures.Timeout(test_timeout, gentle=True))
Matthew Treinish78561ad2013-07-26 11:41:56 -0400141
142 if (os.environ.get('OS_STDOUT_CAPTURE') == 'True' or
143 os.environ.get('OS_STDOUT_CAPTURE') == '1'):
Attila Fazekasf86fa312013-07-30 19:56:39 +0200144 stdout = self.useFixture(fixtures.StringStream('stdout')).stream
145 self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
Matthew Treinish78561ad2013-07-26 11:41:56 -0400146 if (os.environ.get('OS_STDERR_CAPTURE') == 'True' or
147 os.environ.get('OS_STDERR_CAPTURE') == '1'):
Attila Fazekasf86fa312013-07-30 19:56:39 +0200148 stderr = self.useFixture(fixtures.StringStream('stderr')).stream
149 self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
Matthew Treinish78561ad2013-07-26 11:41:56 -0400150
Matthew Treinish3e046852013-07-23 16:00:24 -0400151 @classmethod
152 def _get_identity_admin_client(cls):
153 """
154 Returns an instance of the Identity Admin API client
155 """
156 os = clients.AdminManager(interface=cls._interface)
157 admin_client = os.identity_client
158 return admin_client
159
160 @classmethod
161 def _get_client_args(cls):
162
163 return (
164 cls.config,
165 cls.config.identity.admin_username,
166 cls.config.identity.admin_password,
167 cls.config.identity.uri
168 )
169
Attila Fazekasdc216422013-01-29 15:12:14 +0100170
Sean Dague35a7caf2013-05-10 10:38:22 -0400171def call_until_true(func, duration, sleep_for):
172 """
173 Call the given function until it returns True (and return True) or
174 until the specified duration (in seconds) elapses (and return
175 False).
176
177 :param func: A zero argument callable that returns True on success.
178 :param duration: The number of seconds for which to attempt a
179 successful call of the function.
180 :param sleep_for: The number of seconds to sleep after an unsuccessful
181 invocation of the function.
182 """
183 now = time.time()
184 timeout = now + duration
185 while now < timeout:
186 if func():
187 return True
188 LOG.debug("Sleeping for %d seconds", sleep_for)
189 time.sleep(sleep_for)
190 now = time.time()
191 return False