~allenap/maas/async-use-fixture

« back to all changes in this revision

Viewing changes to src/maastesting/testcase.py

  • Committer: Gavin Panella
  • Date: 2014-08-20 16:26:57 UTC
  • Revision ID: gavin.panella@canonical.com-20140820162657-427kqlwljzrzxvgr
Get useFixture working with async fixtures.

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
from nose.tools import nottest
30
30
import testresources
31
31
import testtools
 
32
from testtools.deferredruntest import extract_result
32
33
import testtools.matchers
 
34
from testtools.testcase import gather_details
 
35
from twisted.internet.defer import maybeDeferred
33
36
 
34
37
 
35
38
@nottest
168
171
            value = mock.MagicMock()
169
172
        super(MAASTestCase, self).patch(obj, attribute, value)
170
173
        return value
 
174
 
 
175
    def useFixture(self, fixture):
 
176
        """Use fixture in a test case.
 
177
 
 
178
        This behaves much like `testtools.TestCase.useFixture` except that it
 
179
        also handles fixtures that defer work, a la Twisted. If the fixture
 
180
        returns a :py:class:`~twisted.internet.defer.Deferred` from `setUp`,
 
181
        the usual set-up tasks will be chained onto it, and it will be
 
182
        returned. It it then the responsibility of the test to ensure that it
 
183
        completes. For example, assuming `inlineCallbacks`::
 
184
 
 
185
          fixture = yield self.useFixture(SomeTwistedFixture())
 
186
 
 
187
        :param fixture: The fixture to use.
 
188
        :return: The fixture, after setting it up and scheduling a cleanup for
 
189
           it *or* a Deferred firing with the fixture.
 
190
        """
 
191
        def gather_fixture_details():
 
192
            details_from = fixture.getDetails()
 
193
            details_to = self.getDetails()
 
194
            gather_details(details_from, details_to)
 
195
 
 
196
        d = maybeDeferred(fixture.setUp)
 
197
 
 
198
        # Callback to set-up things as usual.
 
199
        def cb_setUp(_):
 
200
            # fixture.cleanUp can also return a Deferred. If the test is using
 
201
            # AsynchronousDeferredRunTest this will be honoured.
 
202
            self.addCleanup(fixture.cleanUp)
 
203
            # First in, last out, so details are gathered before clean-up.
 
204
            self.addCleanup(gather_fixture_details)
 
205
            # Return the fixture to the caller.
 
206
            return fixture
 
207
 
 
208
        # Errback to gather details and propagate.
 
209
        def eb_setUp(failure):
 
210
            gather_fixture_details()
 
211
            return failure
 
212
 
 
213
        d.addCallbacks(cb_setUp, eb_setUp)
 
214
 
 
215
        if d.called:
 
216
            # This fixture was able to set up without time in the reactor. It
 
217
            # might have nothing to do with Twisted, for example, or just not
 
218
            # need to do IO, so we can process it presently.
 
219
            try:
 
220
                extract_result(d)
 
221
            except:
 
222
                gather_fixture_details()
 
223
                raise
 
224
            else:
 
225
                return fixture
 
226
        else:
 
227
            # This one needs reactor time.
 
228
            return d