1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
# Copyright [2010] [Anso Labs, LLC]
4
# Licensed under the Apache License, Version 2.0 (the "License");
5
# you may not use this file except in compliance with the License.
6
# You may obtain a copy of the License at
8
# http://www.apache.org/licenses/LICENSE-2.0
10
# Unless required by applicable law or agreed to in writing, software
11
# distributed under the License is distributed on an "AS IS" BASIS,
12
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
# See the License for the specific language governing permissions and
14
# limitations under the License.
17
Base classes for our unit tests.
18
Allows overriding of flags for use of fakes,
19
and some black magic for inline callbacks.
26
from nova import vendor
28
from tornado import ioloop
29
from twisted.internet import defer
30
from twisted.python import failure
31
from twisted.trial import unittest as trial_unittest
34
from nova import datastore
35
from nova import fakerabbit
36
from nova import flags
40
flags.DEFINE_bool('fake_tests', True,
41
'should we use everything for testing')
45
def _skipper(*args, **kw):
47
raise trial_unittest.SkipTest('Test cannot be run in fake mode')
51
_skipper.func_name = f.func_name
55
class TrialTestCase(trial_unittest.TestCase):
57
super(TrialTestCase, self).setUp()
59
# emulate some of the mox stuff, we can't use the metaclass
60
# because it screws with our generators
62
self.stubs = stubout.StubOutForTesting()
63
self.flag_overrides = {}
66
super(TrialTestCase, self).tearDown()
70
self.stubs.SmartUnsetAll()
74
fakerabbit.reset_all()
76
# attempt to wipe all keepers
77
#keeper = datastore.Keeper()
80
def flags(self, **kw):
81
for k, v in kw.iteritems():
82
if k in self.flag_overrides:
85
'trying to override already overriden flag: %s' % k)
86
self.flag_overrides[k] = getattr(FLAGS, k)
89
def reset_flags(self):
90
for k, v in self.flag_overrides.iteritems():
95
class BaseTestCase(TrialTestCase):
97
super(BaseTestCase, self).setUp()
98
# TODO(termie): we could possibly keep a more global registry of
99
# the injected listeners... this is fine for now though
101
self.ioloop = ioloop.IOLoop.instance()
104
self._doneWaiting = False
105
self._timedOut = False
115
super(BaseTestCase, self).tearDown()
116
for x in self.injected:
118
if FLAGS.fake_rabbit:
119
fakerabbit.reset_all()
122
def _waitForTest(self, timeout=60):
123
""" Push the ioloop along to wait for our test to complete. """
124
self._waiting = self.ioloop.add_timeout(time.time() + timeout,
128
self.fail('test timed out')
130
if self._doneWaiting:
133
# we can use add_callback here but this uses less cpu when testing
134
self.ioloop.add_timeout(time.time() + 0.01, _wait)
136
self.ioloop.add_callback(_wait)
142
self.ioloop.remove_timeout(self._waiting)
146
self._doneWaiting = True
148
def _maybeInlineCallbacks(self, f):
149
""" If we're doing async calls in our tests, wait on them.
151
This is probably the most complicated hunk of code we have so far.
153
First up, if the function is normal (not async) we just act normal
156
Async tests will use the "Inline Callbacks" pattern, which means
157
you yield Deferreds at every "waiting" step of your code instead
158
of making epic callback chains.
160
Example (callback chain, ugly):
162
d = self.node.terminate_instance(instance_id) # a Deferred instance
164
d_desc = self.node.describe_instances() # another Deferred instance
166
def _checkDescribe(rv):
167
self.assertEqual(rv, [])
168
d.addCallback(_describe)
169
d.addCallback(_checkDescribe)
170
d.addCallback(lambda x: self._done())
173
Example (inline callbacks! yay!):
175
yield self.node.terminate_instance(instance_id)
176
rv = yield self.node.describe_instances()
177
self.assertEqual(rv, [])
179
If the test fits the Inline Callbacks pattern we will automatically
180
handle calling wait and done.
182
# TODO(termie): this can be a wrapper function instead and
183
# and we can make a metaclass so that we don't
184
# have to copy all that "run" code below.
186
if not hasattr(g, 'send'):
188
return defer.succeed(g)
190
inlined = defer.inlineCallbacks(f)
194
def _catchExceptions(self, result, failure):
195
exc = (failure.type, failure.value, failure.getTracebackObject())
196
if isinstance(failure.value, self.failureException):
197
result.addFailure(self, exc)
198
elif isinstance(failure.value, KeyboardInterrupt):
201
result.addError(self, exc)
206
self._waiting = False
207
self._timedOut = True
209
def run(self, result=None):
210
if result is None: result = self.defaultTestResult()
212
result.startTest(self)
213
testMethod = getattr(self, self._testMethodName)
217
except KeyboardInterrupt:
220
result.addError(self, self._exc_info())
225
d = self._maybeInlineCallbacks(testMethod)
226
d.addErrback(lambda x: self._catchExceptions(result, x))
227
d.addBoth(lambda x: self._done() and x)
230
except self.failureException:
231
result.addFailure(self, self._exc_info())
232
except KeyboardInterrupt:
235
result.addError(self, self._exc_info())
239
except KeyboardInterrupt:
242
result.addError(self, self._exc_info())
244
if ok: result.addSuccess(self)
246
result.stopTest(self)