blob: e0639b640f03a20aad2a583f63b2cb5d3fa61bf5 [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
18import logging
19import time
20
Chris Yeoh55530bb2013-02-08 16:04:27 +103021import nose.plugins.attrib
Attila Fazekasdc216422013-01-29 15:12:14 +010022import testresources
ivan-zhu1feeb382013-01-24 10:14:39 +080023import testtools
Jay Pipes051075a2012-04-28 17:39:37 -040024
Attila Fazekasdc216422013-01-29 15:12:14 +010025from tempest import config
Jay Pipes051075a2012-04-28 17:39:37 -040026from tempest import manager
27
28LOG = logging.getLogger(__name__)
29
30
Chris Yeoh55530bb2013-02-08 16:04:27 +103031def attr(*args, **kwargs):
32 """A decorator which applies the nose and testtools attr decorator
33
34 This decorator applies the nose attr decorator as well as the
35 the testtools.testcase.attr if it is in the list of attributes
Attila Fazekasb2902af2013-02-16 16:22:44 +010036 to testtools we want to apply.
37 """
Chris Yeoh55530bb2013-02-08 16:04:27 +103038
39 def decorator(f):
40 testtool_attributes = ('smoke')
41
42 if 'type' in kwargs and kwargs['type'] in testtool_attributes:
43 return nose.plugins.attrib.attr(*args, **kwargs)(
44 testtools.testcase.attr(kwargs['type'])(f))
45 else:
46 return nose.plugins.attrib.attr(*args, **kwargs)(f)
47
48 return decorator
49
50
Attila Fazekasdc216422013-01-29 15:12:14 +010051class BaseTestCase(testtools.TestCase,
52 testtools.testcase.WithAttributes,
53 testresources.ResourcedTestCase):
54 def __init__(self, *args, **kwargs):
55 super(BaseTestCase, self).__init__(*args, **kwargs)
56 #NOTE(afazekas): inspection workaround
57 BaseTestCase.config = config.TempestConfig()
58
59
60class TestCase(BaseTestCase):
Pavel Sedláka2b757c2013-02-25 18:16:04 +010061 """Base test case class for all Tempest tests
Jay Pipes051075a2012-04-28 17:39:37 -040062
63 Contains basic setup and convenience methods
64 """
Pavel Sedláka2b757c2013-02-25 18:16:04 +010065
Jay Pipes051075a2012-04-28 17:39:37 -040066 manager_class = None
67
68 @classmethod
69 def setUpClass(cls):
70 cls.manager = cls.manager_class()
Maru Newbydec13ec2012-08-30 11:19:17 -070071 for attr_name in cls.manager.client_attr_names:
72 # Ensure that pre-existing class attributes won't be
73 # accidentally overriden.
74 assert not hasattr(cls, attr_name)
75 client = getattr(cls.manager, attr_name)
76 setattr(cls, attr_name, client)
Jay Pipes051075a2012-04-28 17:39:37 -040077 cls.resource_keys = {}
Attila Fazekasdc216422013-01-29 15:12:14 +010078 cls.os_resources = []
Jay Pipes051075a2012-04-28 17:39:37 -040079
80 def set_resource(self, key, thing):
81 LOG.debug("Adding %r to shared resources of %s" %
82 (thing, self.__class__.__name__))
83 self.resource_keys[key] = thing
Attila Fazekasdc216422013-01-29 15:12:14 +010084 self.os_resources.append(thing)
Jay Pipes051075a2012-04-28 17:39:37 -040085
86 def get_resource(self, key):
87 return self.resource_keys[key]
88
89 def remove_resource(self, key):
90 thing = self.resource_keys[key]
Attila Fazekasdc216422013-01-29 15:12:14 +010091 self.os_resources.remove(thing)
Jay Pipes051075a2012-04-28 17:39:37 -040092 del self.resource_keys[key]
93
94
Maru Newbyd3bf0aa2012-09-05 20:01:43 -070095def call_until_true(func, duration, sleep_for):
96 """
97 Call the given function until it returns True (and return True) or
98 until the specified duration (in seconds) elapses (and return
99 False).
100
101 :param func: A zero argument callable that returns True on success.
102 :param duration: The number of seconds for which to attempt a successful
103 call of the function.
104 :param sleep_for: The number of seconds to sleep after an unsuccessful
105 invocation of the function.
106 """
107 now = time.time()
108 timeout = now + duration
109 while now < timeout:
110 if func():
111 return True
112 LOG.debug("Sleeping for %d seconds", sleep_for)
113 time.sleep(sleep_for)
114 now = time.time()
115 return False
116
117
Maru Newbydec13ec2012-08-30 11:19:17 -0700118class DefaultClientTest(TestCase):
Jay Pipes051075a2012-04-28 17:39:37 -0400119
120 """
Maru Newbydec13ec2012-08-30 11:19:17 -0700121 Base test case class that provides the default clients to access
122 the various OpenStack APIs.
Jay Pipes051075a2012-04-28 17:39:37 -0400123 """
124
Maru Newbydec13ec2012-08-30 11:19:17 -0700125 manager_class = manager.DefaultClientManager
Jay Pipes051075a2012-04-28 17:39:37 -0400126
127 def status_timeout(self, things, thing_id, expected_status):
128 """
129 Given a thing and an expected status, do a loop, sleeping
130 for a configurable amount of time, checking for the
131 expected status to show. At any time, if the returned
132 status of the thing is ERROR, fail out.
133 """
Maru Newbyd3bf0aa2012-09-05 20:01:43 -0700134 def check_status():
Jay Pipes051075a2012-04-28 17:39:37 -0400135 # python-novaclient has resources available to its client
136 # that all implement a get() method taking an identifier
137 # for the singular resource to retrieve.
138 thing = things.get(thing_id)
139 new_status = thing.status
140 if new_status == 'ERROR':
141 self.fail("%s failed to get to expected status."
142 "In ERROR state."
143 % thing)
144 elif new_status == expected_status:
Maru Newbyd3bf0aa2012-09-05 20:01:43 -0700145 return True # All good.
Jay Pipes051075a2012-04-28 17:39:37 -0400146 LOG.debug("Waiting for %s to get to %s status. "
147 "Currently in %s status",
148 thing, expected_status, new_status)
Maru Newbyd3bf0aa2012-09-05 20:01:43 -0700149 if not call_until_true(check_status,
150 self.config.compute.build_timeout,
151 self.config.compute.build_interval):
152 self.fail("Timed out waiting for thing %s to become %s"
153 % (thing_id, expected_status))
Jay Pipes051075a2012-04-28 17:39:37 -0400154
155
156class ComputeFuzzClientTest(TestCase):
157
158 """
159 Base test case class for OpenStack Compute API (Nova)
160 that uses the Tempest REST fuzz client libs for calling the API.
161 """
162
163 manager_class = manager.ComputeFuzzClientManager
164
165 def status_timeout(self, client_get_method, thing_id, expected_status):
166 """
167 Given a method to get a resource and an expected status, do a loop,
168 sleeping for a configurable amount of time, checking for the
169 expected status to show. At any time, if the returned
170 status of the thing is ERROR, fail out.
171
172 :param client_get_method: The callable that will retrieve the thing
173 with ID :param:thing_id
174 :param thing_id: The ID of the thing to get
175 :param expected_status: String value of the expected status of the
176 thing that we are looking for.
177
178 :code ..
179
180 Usage:
181
182 def test_some_server_action(self):
183 client = self.servers_client
184 resp, server = client.create_server('random_server')
185 self.status_timeout(client.get_server, server['id'], 'ACTIVE')
186 """
Maru Newbyd3bf0aa2012-09-05 20:01:43 -0700187 def check_status():
Jay Pipes051075a2012-04-28 17:39:37 -0400188 # Tempest REST client has resources available to its client
189 # that all implement a various get_$resource() methods taking
190 # an identifier for the singular resource to retrieve.
191 thing = client_get_method(thing_id)
192 new_status = thing['status']
193 if new_status == 'ERROR':
194 self.fail("%s failed to get to expected status."
195 "In ERROR state."
196 % thing)
197 elif new_status == expected_status:
Maru Newbyd3bf0aa2012-09-05 20:01:43 -0700198 return True # All good.
Jay Pipes051075a2012-04-28 17:39:37 -0400199 LOG.debug("Waiting for %s to get to %s status. "
200 "Currently in %s status",
201 thing, expected_status, new_status)
Maru Newbyd3bf0aa2012-09-05 20:01:43 -0700202 if not call_until_true(check_status,
203 self.config.compute.build_timeout,
204 self.config.compute.build_interval):
205 self.fail("Timed out waiting for thing %s to become %s"
206 % (thing_id, expected_status))