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