blob: b0038e0aade379967d6d3a4c24d2c98e6583500f [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
Pavel Sedlák1053bd32013-04-16 16:47:40 +020059 @classmethod
60 def setUpClass(cls):
61 if hasattr(super(BaseTestCase, cls), 'setUpClass'):
62 super(BaseTestCase, cls).setUpClass()
63
Attila Fazekasdc216422013-01-29 15:12:14 +010064
65class TestCase(BaseTestCase):
Pavel Sedláka2b757c2013-02-25 18:16:04 +010066 """Base test case class for all Tempest tests
Jay Pipes051075a2012-04-28 17:39:37 -040067
68 Contains basic setup and convenience methods
69 """
Pavel Sedláka2b757c2013-02-25 18:16:04 +010070
Jay Pipes051075a2012-04-28 17:39:37 -040071 manager_class = None
72
73 @classmethod
74 def setUpClass(cls):
75 cls.manager = cls.manager_class()
Maru Newbydec13ec2012-08-30 11:19:17 -070076 for attr_name in cls.manager.client_attr_names:
77 # Ensure that pre-existing class attributes won't be
78 # accidentally overriden.
79 assert not hasattr(cls, attr_name)
80 client = getattr(cls.manager, attr_name)
81 setattr(cls, attr_name, client)
Jay Pipes051075a2012-04-28 17:39:37 -040082 cls.resource_keys = {}
Attila Fazekasdc216422013-01-29 15:12:14 +010083 cls.os_resources = []
Jay Pipes051075a2012-04-28 17:39:37 -040084
85 def set_resource(self, key, thing):
86 LOG.debug("Adding %r to shared resources of %s" %
87 (thing, self.__class__.__name__))
88 self.resource_keys[key] = thing
Attila Fazekasdc216422013-01-29 15:12:14 +010089 self.os_resources.append(thing)
Jay Pipes051075a2012-04-28 17:39:37 -040090
91 def get_resource(self, key):
92 return self.resource_keys[key]
93
94 def remove_resource(self, key):
95 thing = self.resource_keys[key]
Attila Fazekasdc216422013-01-29 15:12:14 +010096 self.os_resources.remove(thing)
Jay Pipes051075a2012-04-28 17:39:37 -040097 del self.resource_keys[key]
98
99
Maru Newbyd3bf0aa2012-09-05 20:01:43 -0700100def call_until_true(func, duration, sleep_for):
101 """
102 Call the given function until it returns True (and return True) or
103 until the specified duration (in seconds) elapses (and return
104 False).
105
106 :param func: A zero argument callable that returns True on success.
107 :param duration: The number of seconds for which to attempt a successful
108 call of the function.
109 :param sleep_for: The number of seconds to sleep after an unsuccessful
110 invocation of the function.
111 """
112 now = time.time()
113 timeout = now + duration
114 while now < timeout:
115 if func():
116 return True
117 LOG.debug("Sleeping for %d seconds", sleep_for)
118 time.sleep(sleep_for)
119 now = time.time()
120 return False
121
122
Matthew Treinishfbf40fd2013-04-09 11:10:58 -0400123def status_timeout(things, thing_id, expected_status):
124 """
125 Given a thing and an expected status, do a loop, sleeping
126 for a configurable amount of time, checking for the
127 expected status to show. At any time, if the returned
128 status of the thing is ERROR, fail out.
129 """
130 def check_status():
131 # python-novaclient has resources available to its client
132 # that all implement a get() method taking an identifier
133 # for the singular resource to retrieve.
134 thing = things.get(thing_id)
135 new_status = thing.status
136 if new_status == 'ERROR':
137 self.fail("%s failed to get to expected status."
138 "In ERROR state."
139 % thing)
140 elif new_status == expected_status:
141 return True # All good.
142 LOG.debug("Waiting for %s to get to %s status. "
143 "Currently in %s status",
144 thing, expected_status, new_status)
145 conf = config.TempestConfig()
146 if not call_until_true(check_status,
147 conf.compute.build_timeout,
148 conf.compute.build_interval):
149 self.fail("Timed out waiting for thing %s to become %s"
150 % (thing_id, expected_status))
151
152
153class DefaultClientSmokeTest(TestCase):
Jay Pipes051075a2012-04-28 17:39:37 -0400154
155 """
Matthew Treinishfbf40fd2013-04-09 11:10:58 -0400156 Base smoke test case class that provides the default clients to
157 access the various OpenStack APIs.
158
159 Smoke tests are tests that have the following characteristics:
160
161 * Test basic operations of an API, typically in an order that
162 a regular user would perform those operations
163 * Test only the correct inputs and action paths -- no fuzz or
164 random input data is sent, only valid inputs.
165 * Use only the default client tool for calling an API
Jay Pipes051075a2012-04-28 17:39:37 -0400166 """
167
Maru Newbydec13ec2012-08-30 11:19:17 -0700168 manager_class = manager.DefaultClientManager
Jay Pipes051075a2012-04-28 17:39:37 -0400169
Matthew Treinishfbf40fd2013-04-09 11:10:58 -0400170 @classmethod
171 def tearDownClass(cls):
172 # NOTE(jaypipes): Because smoke tests are typically run in a specific
173 # order, and because test methods in smoke tests generally create
174 # resources in a particular order, we destroy resources in the reverse
175 # order in which resources are added to the smoke test class object
176 while cls.os_resources:
177 thing = cls.os_resources.pop()
178 LOG.debug("Deleting %r from shared resources of %s" %
179 (thing, cls.__name__))
180
181 try:
182 # OpenStack resources are assumed to have a delete()
183 # method which destroys the resource...
184 thing.delete()
185 except Exception as e:
186 # If the resource is already missing, mission accomplished.
187 if e.__class__.__name__ == 'NotFound':
188 continue
189 raise
190
191 def is_deletion_complete():
192 # Deletion testing is only required for objects whose
193 # existence cannot be checked via retrieval.
194 if isinstance(thing, dict):
195 return True
196 try:
197 thing.get()
198 except Exception as e:
199 # Clients are expected to return an exception
200 # called 'NotFound' if retrieval fails.
201 if e.__class__.__name__ == 'NotFound':
202 return True
203 raise
204 return False
205
206 # Block until resource deletion has completed or timed-out
207 call_until_true(is_deletion_complete, 10, 1)
Jay Pipes051075a2012-04-28 17:39:37 -0400208
209
210class ComputeFuzzClientTest(TestCase):
211
212 """
213 Base test case class for OpenStack Compute API (Nova)
214 that uses the Tempest REST fuzz client libs for calling the API.
215 """
216
217 manager_class = manager.ComputeFuzzClientManager