blob: 5f403b332600d6b2b179d398cf91b7df20c6779e [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
Jay Pipes051075a2012-04-28 17:39:37 -040018import time
19
Chris Yeoh55530bb2013-02-08 16:04:27 +103020import nose.plugins.attrib
Attila Fazekasdc216422013-01-29 15:12:14 +010021import testresources
ivan-zhu1feeb382013-01-24 10:14:39 +080022import testtools
Jay Pipes051075a2012-04-28 17:39:37 -040023
Mitsuhiko Yamazaki46818aa2013-04-18 17:49:17 +090024from tempest.common import log as logging
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):
Giulio Fidente4946a052013-05-14 12:23:51 +020040 if 'type' in kwargs and isinstance(kwargs['type'], str):
41 f = testtools.testcase.attr(kwargs['type'])(f)
Chris Yeohcf3fb7c2013-05-19 15:59:00 +093042 if kwargs['type'] == 'smoke':
43 f = testtools.testcase.attr('gate')(f)
Giulio Fidente4946a052013-05-14 12:23:51 +020044 elif 'type' in kwargs and isinstance(kwargs['type'], list):
45 for attr in kwargs['type']:
46 f = testtools.testcase.attr(attr)(f)
Chris Yeohcf3fb7c2013-05-19 15:59:00 +093047 if attr == 'smoke':
48 f = testtools.testcase.attr('gate')(f)
Giulio Fidente4946a052013-05-14 12:23:51 +020049 return nose.plugins.attrib.attr(*args, **kwargs)(f)
Chris Yeoh55530bb2013-02-08 16:04:27 +103050
51 return decorator
52
53
Attila Fazekasdc216422013-01-29 15:12:14 +010054class BaseTestCase(testtools.TestCase,
55 testtools.testcase.WithAttributes,
56 testresources.ResourcedTestCase):
Attila Fazekasc43fec82013-04-09 23:17:52 +020057
58 config = config.TempestConfig()
Attila Fazekasdc216422013-01-29 15:12:14 +010059
Pavel Sedlák1053bd32013-04-16 16:47:40 +020060 @classmethod
61 def setUpClass(cls):
62 if hasattr(super(BaseTestCase, cls), 'setUpClass'):
63 super(BaseTestCase, cls).setUpClass()
64
Attila Fazekasdc216422013-01-29 15:12:14 +010065
Sean Dague35a7caf2013-05-10 10:38:22 -040066def call_until_true(func, duration, sleep_for):
67 """
68 Call the given function until it returns True (and return True) or
69 until the specified duration (in seconds) elapses (and return
70 False).
71
72 :param func: A zero argument callable that returns True on success.
73 :param duration: The number of seconds for which to attempt a
74 successful call of the function.
75 :param sleep_for: The number of seconds to sleep after an unsuccessful
76 invocation of the function.
77 """
78 now = time.time()
79 timeout = now + duration
80 while now < timeout:
81 if func():
82 return True
83 LOG.debug("Sleeping for %d seconds", sleep_for)
84 time.sleep(sleep_for)
85 now = time.time()
86 return False
87
88
Attila Fazekasdc216422013-01-29 15:12:14 +010089class TestCase(BaseTestCase):
Pavel Sedláka2b757c2013-02-25 18:16:04 +010090 """Base test case class for all Tempest tests
Jay Pipes051075a2012-04-28 17:39:37 -040091
92 Contains basic setup and convenience methods
93 """
Pavel Sedláka2b757c2013-02-25 18:16:04 +010094
Jay Pipes051075a2012-04-28 17:39:37 -040095 manager_class = None
96
97 @classmethod
98 def setUpClass(cls):
99 cls.manager = cls.manager_class()
Maru Newbydec13ec2012-08-30 11:19:17 -0700100 for attr_name in cls.manager.client_attr_names:
101 # Ensure that pre-existing class attributes won't be
102 # accidentally overriden.
103 assert not hasattr(cls, attr_name)
104 client = getattr(cls.manager, attr_name)
105 setattr(cls, attr_name, client)
Jay Pipes051075a2012-04-28 17:39:37 -0400106 cls.resource_keys = {}
Attila Fazekasdc216422013-01-29 15:12:14 +0100107 cls.os_resources = []
Jay Pipes051075a2012-04-28 17:39:37 -0400108
109 def set_resource(self, key, thing):
110 LOG.debug("Adding %r to shared resources of %s" %
111 (thing, self.__class__.__name__))
112 self.resource_keys[key] = thing
Attila Fazekasdc216422013-01-29 15:12:14 +0100113 self.os_resources.append(thing)
Jay Pipes051075a2012-04-28 17:39:37 -0400114
115 def get_resource(self, key):
116 return self.resource_keys[key]
117
118 def remove_resource(self, key):
119 thing = self.resource_keys[key]
Attila Fazekasdc216422013-01-29 15:12:14 +0100120 self.os_resources.remove(thing)
Jay Pipes051075a2012-04-28 17:39:37 -0400121 del self.resource_keys[key]
122
Sean Dague35a7caf2013-05-10 10:38:22 -0400123 def status_timeout(self, 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."
Pavel Sedlák51ed3562013-04-26 12:36:08 +0200138 "In ERROR state."
139 % thing)
Sean Dague35a7caf2013-05-10 10:38:22 -0400140 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"
Pavel Sedlák51ed3562013-04-26 12:36:08 +0200150 % (thing_id, expected_status))
Matthew Treinishfbf40fd2013-04-09 11:10:58 -0400151
152
Jay Pipes051075a2012-04-28 17:39:37 -0400153class ComputeFuzzClientTest(TestCase):
154
155 """
156 Base test case class for OpenStack Compute API (Nova)
157 that uses the Tempest REST fuzz client libs for calling the API.
158 """
159
160 manager_class = manager.ComputeFuzzClientManager