diff options
Diffstat (limited to 'lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/test/test_defer.py')
-rwxr-xr-x | lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/test/test_defer.py | 2002 |
1 files changed, 0 insertions, 2002 deletions
diff --git a/lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/test/test_defer.py b/lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/test/test_defer.py deleted file mode 100755 index 1b113462..00000000 --- a/lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/test/test_defer.py +++ /dev/null @@ -1,2002 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test cases for defer module. -""" - -import gc, traceback - -from twisted.trial import unittest -from twisted.internet import reactor, defer -from twisted.internet.task import Clock -from twisted.python import failure, log -from twisted.python.util import unsignedID - -class GenericError(Exception): - pass - - - -class DeferredTestCase(unittest.TestCase): - - def setUp(self): - self.callbackResults = None - self.errbackResults = None - self.callback2Results = None - # Restore the debug flag to its original state when done. - self.addCleanup(defer.setDebugging, defer.getDebugging()) - - def _callback(self, *args, **kw): - self.callbackResults = args, kw - return args[0] - - def _callback2(self, *args, **kw): - self.callback2Results = args, kw - - def _errback(self, *args, **kw): - self.errbackResults = args, kw - - def testCallbackWithoutArgs(self): - deferred = defer.Deferred() - deferred.addCallback(self._callback) - deferred.callback("hello") - self.assertEqual(self.errbackResults, None) - self.assertEqual(self.callbackResults, (('hello',), {})) - - def testCallbackWithArgs(self): - deferred = defer.Deferred() - deferred.addCallback(self._callback, "world") - deferred.callback("hello") - self.assertEqual(self.errbackResults, None) - self.assertEqual(self.callbackResults, (('hello', 'world'), {})) - - def testCallbackWithKwArgs(self): - deferred = defer.Deferred() - deferred.addCallback(self._callback, world="world") - deferred.callback("hello") - self.assertEqual(self.errbackResults, None) - self.assertEqual(self.callbackResults, - (('hello',), {'world': 'world'})) - - def testTwoCallbacks(self): - deferred = defer.Deferred() - deferred.addCallback(self._callback) - deferred.addCallback(self._callback2) - deferred.callback("hello") - self.assertEqual(self.errbackResults, None) - self.assertEqual(self.callbackResults, - (('hello',), {})) - self.assertEqual(self.callback2Results, - (('hello',), {})) - - def testDeferredList(self): - defr1 = defer.Deferred() - defr2 = defer.Deferred() - defr3 = defer.Deferred() - dl = defer.DeferredList([defr1, defr2, defr3]) - result = [] - def cb(resultList, result=result): - result.extend(resultList) - def catch(err): - return None - dl.addCallbacks(cb, cb) - defr1.callback("1") - defr2.addErrback(catch) - # "catch" is added to eat the GenericError that will be passed on by - # the DeferredList's callback on defr2. If left unhandled, the - # Failure object would cause a log.err() warning about "Unhandled - # error in Deferred". Twisted's pyunit watches for log.err calls and - # treats them as failures. So "catch" must eat the error to prevent - # it from flunking the test. - defr2.errback(GenericError("2")) - defr3.callback("3") - self.assertEqual([result[0], - #result[1][1] is now a Failure instead of an Exception - (result[1][0], str(result[1][1].value)), - result[2]], - - [(defer.SUCCESS, "1"), - (defer.FAILURE, "2"), - (defer.SUCCESS, "3")]) - - def testEmptyDeferredList(self): - result = [] - def cb(resultList, result=result): - result.append(resultList) - - dl = defer.DeferredList([]) - dl.addCallbacks(cb) - self.assertEqual(result, [[]]) - - result[:] = [] - dl = defer.DeferredList([], fireOnOneCallback=1) - dl.addCallbacks(cb) - self.assertEqual(result, []) - - def testDeferredListFireOnOneError(self): - defr1 = defer.Deferred() - defr2 = defer.Deferred() - defr3 = defer.Deferred() - dl = defer.DeferredList([defr1, defr2, defr3], fireOnOneErrback=1) - result = [] - dl.addErrback(result.append) - - # consume errors after they pass through the DeferredList (to avoid - # 'Unhandled error in Deferred'. - def catch(err): - return None - defr2.addErrback(catch) - - # fire one Deferred's callback, no result yet - defr1.callback("1") - self.assertEqual(result, []) - - # fire one Deferred's errback -- now we have a result - defr2.errback(GenericError("from def2")) - self.assertEqual(len(result), 1) - - # extract the result from the list - aFailure = result[0] - - # the type of the failure is a FirstError - self.failUnless(issubclass(aFailure.type, defer.FirstError), - 'issubclass(aFailure.type, defer.FirstError) failed: ' - "failure's type is %r" % (aFailure.type,) - ) - - firstError = aFailure.value - - # check that the GenericError("2") from the deferred at index 1 - # (defr2) is intact inside failure.value - self.assertEqual(firstError.subFailure.type, GenericError) - self.assertEqual(firstError.subFailure.value.args, ("from def2",)) - self.assertEqual(firstError.index, 1) - - - def testDeferredListDontConsumeErrors(self): - d1 = defer.Deferred() - dl = defer.DeferredList([d1]) - - errorTrap = [] - d1.addErrback(errorTrap.append) - - result = [] - dl.addCallback(result.append) - - d1.errback(GenericError('Bang')) - self.assertEqual('Bang', errorTrap[0].value.args[0]) - self.assertEqual(1, len(result)) - self.assertEqual('Bang', result[0][0][1].value.args[0]) - - def testDeferredListConsumeErrors(self): - d1 = defer.Deferred() - dl = defer.DeferredList([d1], consumeErrors=True) - - errorTrap = [] - d1.addErrback(errorTrap.append) - - result = [] - dl.addCallback(result.append) - - d1.errback(GenericError('Bang')) - self.assertEqual([], errorTrap) - self.assertEqual(1, len(result)) - self.assertEqual('Bang', result[0][0][1].value.args[0]) - - def testDeferredListFireOnOneErrorWithAlreadyFiredDeferreds(self): - # Create some deferreds, and errback one - d1 = defer.Deferred() - d2 = defer.Deferred() - d1.errback(GenericError('Bang')) - - # *Then* build the DeferredList, with fireOnOneErrback=True - dl = defer.DeferredList([d1, d2], fireOnOneErrback=True) - result = [] - dl.addErrback(result.append) - self.assertEqual(1, len(result)) - - d1.addErrback(lambda e: None) # Swallow error - - def testDeferredListWithAlreadyFiredDeferreds(self): - # Create some deferreds, and err one, call the other - d1 = defer.Deferred() - d2 = defer.Deferred() - d1.errback(GenericError('Bang')) - d2.callback(2) - - # *Then* build the DeferredList - dl = defer.DeferredList([d1, d2]) - - result = [] - dl.addCallback(result.append) - - self.assertEqual(1, len(result)) - - d1.addErrback(lambda e: None) # Swallow error - - - def testImmediateSuccess(self): - l = [] - d = defer.succeed("success") - d.addCallback(l.append) - self.assertEqual(l, ["success"]) - - - def testImmediateFailure(self): - l = [] - d = defer.fail(GenericError("fail")) - d.addErrback(l.append) - self.assertEqual(str(l[0].value), "fail") - - def testPausedFailure(self): - l = [] - d = defer.fail(GenericError("fail")) - d.pause() - d.addErrback(l.append) - self.assertEqual(l, []) - d.unpause() - self.assertEqual(str(l[0].value), "fail") - - def testCallbackErrors(self): - l = [] - d = defer.Deferred().addCallback(lambda _: 1 // 0).addErrback(l.append) - d.callback(1) - self.assert_(isinstance(l[0].value, ZeroDivisionError)) - l = [] - d = defer.Deferred().addCallback( - lambda _: failure.Failure(ZeroDivisionError())).addErrback(l.append) - d.callback(1) - self.assert_(isinstance(l[0].value, ZeroDivisionError)) - - def testUnpauseBeforeCallback(self): - d = defer.Deferred() - d.pause() - d.addCallback(self._callback) - d.unpause() - - def testReturnDeferred(self): - d = defer.Deferred() - d2 = defer.Deferred() - d2.pause() - d.addCallback(lambda r, d2=d2: d2) - d.addCallback(self._callback) - d.callback(1) - assert self.callbackResults is None, "Should not have been called yet." - d2.callback(2) - assert self.callbackResults is None, "Still should not have been called yet." - d2.unpause() - assert self.callbackResults[0][0] == 2, "Result should have been from second deferred:%s" % (self.callbackResults,) - - - def test_chainedPausedDeferredWithResult(self): - """ - When a paused Deferred with a result is returned from a callback on - another Deferred, the other Deferred is chained to the first and waits - for it to be unpaused. - """ - expected = object() - paused = defer.Deferred() - paused.callback(expected) - paused.pause() - chained = defer.Deferred() - chained.addCallback(lambda ignored: paused) - chained.callback(None) - - result = [] - chained.addCallback(result.append) - self.assertEqual(result, []) - paused.unpause() - self.assertEqual(result, [expected]) - - - def test_pausedDeferredChained(self): - """ - A paused Deferred encountered while pushing a result forward through a - chain does not prevent earlier Deferreds from continuing to execute - their callbacks. - """ - first = defer.Deferred() - second = defer.Deferred() - first.addCallback(lambda ignored: second) - first.callback(None) - first.pause() - second.callback(None) - result = [] - second.addCallback(result.append) - self.assertEqual(result, [None]) - - - def test_gatherResults(self): - # test successful list of deferreds - l = [] - defer.gatherResults([defer.succeed(1), defer.succeed(2)]).addCallback(l.append) - self.assertEqual(l, [[1, 2]]) - # test failing list of deferreds - l = [] - dl = [defer.succeed(1), defer.fail(ValueError)] - defer.gatherResults(dl).addErrback(l.append) - self.assertEqual(len(l), 1) - self.assert_(isinstance(l[0], failure.Failure)) - # get rid of error - dl[1].addErrback(lambda e: 1) - - - def test_gatherResultsWithConsumeErrors(self): - """ - If a L{Deferred} in the list passed to L{gatherResults} fires with a - failure and C{consumerErrors} is C{True}, the failure is converted to a - C{None} result on that L{Deferred}. - """ - # test successful list of deferreds - dgood = defer.succeed(1) - dbad = defer.fail(RuntimeError("oh noes")) - d = defer.gatherResults([dgood, dbad], consumeErrors=True) - unconsumedErrors = [] - dbad.addErrback(unconsumedErrors.append) - gatheredErrors = [] - d.addErrback(gatheredErrors.append) - - self.assertEqual((len(unconsumedErrors), len(gatheredErrors)), - (0, 1)) - self.assertIsInstance(gatheredErrors[0].value, defer.FirstError) - firstError = gatheredErrors[0].value.subFailure - self.assertIsInstance(firstError.value, RuntimeError) - - - def test_maybeDeferredSync(self): - """ - L{defer.maybeDeferred} should retrieve the result of a synchronous - function and pass it to its resulting L{defer.Deferred}. - """ - S, E = [], [] - d = defer.maybeDeferred((lambda x: x + 5), 10) - d.addCallbacks(S.append, E.append) - self.assertEqual(E, []) - self.assertEqual(S, [15]) - return d - - - def test_maybeDeferredSyncError(self): - """ - L{defer.maybeDeferred} should catch exception raised by a synchronous - function and errback its resulting L{defer.Deferred} with it. - """ - S, E = [], [] - try: - '10' + 5 - except TypeError, e: - expected = str(e) - d = defer.maybeDeferred((lambda x: x + 5), '10') - d.addCallbacks(S.append, E.append) - self.assertEqual(S, []) - self.assertEqual(len(E), 1) - self.assertEqual(str(E[0].value), expected) - return d - - - def test_maybeDeferredAsync(self): - """ - L{defer.maybeDeferred} should let L{defer.Deferred} instance pass by - so that original result is the same. - """ - d = defer.Deferred() - d2 = defer.maybeDeferred(lambda: d) - d.callback('Success') - return d2.addCallback(self.assertEqual, 'Success') - - - def test_maybeDeferredAsyncError(self): - """ - L{defer.maybeDeferred} should let L{defer.Deferred} instance pass by - so that L{failure.Failure} returned by the original instance is the - same. - """ - d = defer.Deferred() - d2 = defer.maybeDeferred(lambda: d) - d.errback(failure.Failure(RuntimeError())) - return self.assertFailure(d2, RuntimeError) - - - def test_innerCallbacksPreserved(self): - """ - When a L{Deferred} encounters a result which is another L{Deferred} - which is waiting on a third L{Deferred}, the middle L{Deferred}'s - callbacks are executed after the third L{Deferred} fires and before the - first receives a result. - """ - results = [] - failures = [] - inner = defer.Deferred() - def cb(result): - results.append(('start-of-cb', result)) - d = defer.succeed('inner') - def firstCallback(result): - results.append(('firstCallback', 'inner')) - return inner - def secondCallback(result): - results.append(('secondCallback', result)) - return result * 2 - d.addCallback(firstCallback).addCallback(secondCallback) - d.addErrback(failures.append) - return d - outer = defer.succeed('outer') - outer.addCallback(cb) - inner.callback('orange') - outer.addCallback(results.append) - inner.addErrback(failures.append) - outer.addErrback(failures.append) - self.assertEqual([], failures) - self.assertEqual( - results, - [('start-of-cb', 'outer'), - ('firstCallback', 'inner'), - ('secondCallback', 'orange'), - 'orangeorange']) - - - def test_continueCallbackNotFirst(self): - """ - The continue callback of a L{Deferred} waiting for another L{Deferred} - is not necessarily the first one. This is somewhat a whitebox test - checking that we search for that callback among the whole list of - callbacks. - """ - results = [] - failures = [] - a = defer.Deferred() - - def cb(result): - results.append(('cb', result)) - d = defer.Deferred() - - def firstCallback(ignored): - results.append(('firstCallback', ignored)) - return defer.gatherResults([a]) - - def secondCallback(result): - results.append(('secondCallback', result)) - - d.addCallback(firstCallback) - d.addCallback(secondCallback) - d.addErrback(failures.append) - d.callback(None) - return d - - outer = defer.succeed('outer') - outer.addCallback(cb) - outer.addErrback(failures.append) - self.assertEqual([('cb', 'outer'), ('firstCallback', None)], results) - a.callback('withers') - self.assertEqual([], failures) - self.assertEqual( - results, - [('cb', 'outer'), - ('firstCallback', None), - ('secondCallback', ['withers'])]) - - - def test_callbackOrderPreserved(self): - """ - A callback added to a L{Deferred} after a previous callback attached - another L{Deferred} as a result is run after the callbacks of the other - L{Deferred} are run. - """ - results = [] - failures = [] - a = defer.Deferred() - - def cb(result): - results.append(('cb', result)) - d = defer.Deferred() - - def firstCallback(ignored): - results.append(('firstCallback', ignored)) - return defer.gatherResults([a]) - - def secondCallback(result): - results.append(('secondCallback', result)) - - d.addCallback(firstCallback) - d.addCallback(secondCallback) - d.addErrback(failures.append) - d.callback(None) - return d - - outer = defer.Deferred() - outer.addCallback(cb) - outer.addCallback(lambda x: results.append('final')) - outer.addErrback(failures.append) - outer.callback('outer') - self.assertEqual([('cb', 'outer'), ('firstCallback', None)], results) - a.callback('withers') - self.assertEqual([], failures) - self.assertEqual( - results, - [('cb', 'outer'), - ('firstCallback', None), - ('secondCallback', ['withers']), 'final']) - - - def test_reentrantRunCallbacks(self): - """ - A callback added to a L{Deferred} by a callback on that L{Deferred} - should be added to the end of the callback chain. - """ - deferred = defer.Deferred() - called = [] - def callback3(result): - called.append(3) - def callback2(result): - called.append(2) - def callback1(result): - called.append(1) - deferred.addCallback(callback3) - deferred.addCallback(callback1) - deferred.addCallback(callback2) - deferred.callback(None) - self.assertEqual(called, [1, 2, 3]) - - - def test_nonReentrantCallbacks(self): - """ - A callback added to a L{Deferred} by a callback on that L{Deferred} - should not be executed until the running callback returns. - """ - deferred = defer.Deferred() - called = [] - def callback2(result): - called.append(2) - def callback1(result): - called.append(1) - deferred.addCallback(callback2) - self.assertEqual(called, [1]) - deferred.addCallback(callback1) - deferred.callback(None) - self.assertEqual(called, [1, 2]) - - - def test_reentrantRunCallbacksWithFailure(self): - """ - After an exception is raised by a callback which was added to a - L{Deferred} by a callback on that L{Deferred}, the L{Deferred} should - call the first errback with a L{Failure} wrapping that exception. - """ - exceptionMessage = "callback raised exception" - deferred = defer.Deferred() - def callback2(result): - raise Exception(exceptionMessage) - def callback1(result): - deferred.addCallback(callback2) - deferred.addCallback(callback1) - deferred.callback(None) - self.assertFailure(deferred, Exception) - def cbFailed(exception): - self.assertEqual(exception.args, (exceptionMessage,)) - deferred.addCallback(cbFailed) - return deferred - - - def test_synchronousImplicitChain(self): - """ - If a first L{Deferred} with a result is returned from a callback on a - second L{Deferred}, the result of the second L{Deferred} becomes the - result of the first L{Deferred} and the result of the first L{Deferred} - becomes C{None}. - """ - result = object() - first = defer.succeed(result) - second = defer.Deferred() - second.addCallback(lambda ign: first) - second.callback(None) - - results = [] - first.addCallback(results.append) - self.assertIdentical(results[0], None) - second.addCallback(results.append) - self.assertIdentical(results[1], result) - - - def test_asynchronousImplicitChain(self): - """ - If a first L{Deferred} without a result is returned from a callback on - a second L{Deferred}, the result of the second L{Deferred} becomes the - result of the first L{Deferred} as soon as the first L{Deferred} has - one and the result of the first L{Deferred} becomes C{None}. - """ - first = defer.Deferred() - second = defer.Deferred() - second.addCallback(lambda ign: first) - second.callback(None) - - firstResult = [] - first.addCallback(firstResult.append) - secondResult = [] - second.addCallback(secondResult.append) - - self.assertEqual(firstResult, []) - self.assertEqual(secondResult, []) - - result = object() - first.callback(result) - - self.assertEqual(firstResult, [None]) - self.assertEqual(secondResult, [result]) - - - def test_synchronousImplicitErrorChain(self): - """ - If a first L{Deferred} with a L{Failure} result is returned from a - callback on a second L{Deferred}, the first L{Deferred}'s result is - converted to L{None} and no unhandled error is logged when it is - garbage collected. - """ - first = defer.fail(RuntimeError("First Deferred's Failure")) - second = defer.Deferred() - second.addCallback(lambda ign, first=first: first) - self.assertFailure(second, RuntimeError) - second.callback(None) - firstResult = [] - first.addCallback(firstResult.append) - self.assertIdentical(firstResult[0], None) - return second - - - def test_asynchronousImplicitErrorChain(self): - """ - Let C{a} and C{b} be two L{Deferred}s. - - If C{a} has no result and is returned from a callback on C{b} then when - C{a} fails, C{b}'s result becomes the L{Failure} that was C{a}'s result, - the result of C{a} becomes C{None} so that no unhandled error is logged - when it is garbage collected. - """ - first = defer.Deferred() - second = defer.Deferred() - second.addCallback(lambda ign: first) - second.callback(None) - self.assertFailure(second, RuntimeError) - - firstResult = [] - first.addCallback(firstResult.append) - secondResult = [] - second.addCallback(secondResult.append) - - self.assertEqual(firstResult, []) - self.assertEqual(secondResult, []) - - first.errback(RuntimeError("First Deferred's Failure")) - - self.assertEqual(firstResult, [None]) - self.assertEqual(len(secondResult), 1) - - - def test_doubleAsynchronousImplicitChaining(self): - """ - L{Deferred} chaining is transitive. - - In other words, let A, B, and C be Deferreds. If C is returned from a - callback on B and B is returned from a callback on A then when C fires, - A fires. - """ - first = defer.Deferred() - second = defer.Deferred() - second.addCallback(lambda ign: first) - third = defer.Deferred() - third.addCallback(lambda ign: second) - - thirdResult = [] - third.addCallback(thirdResult.append) - - result = object() - # After this, second is waiting for first to tell it to continue. - second.callback(None) - # And after this, third is waiting for second to tell it to continue. - third.callback(None) - - # Still waiting - self.assertEqual(thirdResult, []) - - # This will tell second to continue which will tell third to continue. - first.callback(result) - - self.assertEqual(thirdResult, [result]) - - - def test_nestedAsynchronousChainedDeferreds(self): - """ - L{Deferred}s can have callbacks that themselves return L{Deferred}s. - When these "inner" L{Deferred}s fire (even asynchronously), the - callback chain continues. - """ - results = [] - failures = [] - - # A Deferred returned in the inner callback. - inner = defer.Deferred() - - def cb(result): - results.append(('start-of-cb', result)) - d = defer.succeed('inner') - - def firstCallback(result): - results.append(('firstCallback', 'inner')) - # Return a Deferred that definitely has not fired yet, so we - # can fire the Deferreds out of order. - return inner - - def secondCallback(result): - results.append(('secondCallback', result)) - return result * 2 - - d.addCallback(firstCallback).addCallback(secondCallback) - d.addErrback(failures.append) - return d - - # Create a synchronous Deferred that has a callback 'cb' that returns - # a Deferred 'd' that has fired but is now waiting on an unfired - # Deferred 'inner'. - outer = defer.succeed('outer') - outer.addCallback(cb) - outer.addCallback(results.append) - # At this point, the callback 'cb' has been entered, and the first - # callback of 'd' has been called. - self.assertEqual( - results, [('start-of-cb', 'outer'), ('firstCallback', 'inner')]) - - # Once the inner Deferred is fired, processing of the outer Deferred's - # callback chain continues. - inner.callback('orange') - - # Make sure there are no errors. - inner.addErrback(failures.append) - outer.addErrback(failures.append) - self.assertEqual( - [], failures, "Got errbacks but wasn't expecting any.") - - self.assertEqual( - results, - [('start-of-cb', 'outer'), - ('firstCallback', 'inner'), - ('secondCallback', 'orange'), - 'orangeorange']) - - - def test_nestedAsynchronousChainedDeferredsWithExtraCallbacks(self): - """ - L{Deferred}s can have callbacks that themselves return L{Deferred}s. - These L{Deferred}s can have other callbacks added before they are - returned, which subtly changes the callback chain. When these "inner" - L{Deferred}s fire (even asynchronously), the outer callback chain - continues. - """ - results = [] - failures = [] - - # A Deferred returned in the inner callback after a callback is - # added explicitly and directly to it. - inner = defer.Deferred() - - def cb(result): - results.append(('start-of-cb', result)) - d = defer.succeed('inner') - - def firstCallback(ignored): - results.append(('firstCallback', ignored)) - # Return a Deferred that definitely has not fired yet with a - # result-transforming callback so we can fire the Deferreds - # out of order and see how the callback affects the ultimate - # results. - return inner.addCallback(lambda x: [x]) - - def secondCallback(result): - results.append(('secondCallback', result)) - return result * 2 - - d.addCallback(firstCallback) - d.addCallback(secondCallback) - d.addErrback(failures.append) - return d - - # Create a synchronous Deferred that has a callback 'cb' that returns - # a Deferred 'd' that has fired but is now waiting on an unfired - # Deferred 'inner'. - outer = defer.succeed('outer') - outer.addCallback(cb) - outer.addCallback(results.append) - # At this point, the callback 'cb' has been entered, and the first - # callback of 'd' has been called. - self.assertEqual( - results, [('start-of-cb', 'outer'), ('firstCallback', 'inner')]) - - # Once the inner Deferred is fired, processing of the outer Deferred's - # callback chain continues. - inner.callback('withers') - - # Make sure there are no errors. - outer.addErrback(failures.append) - inner.addErrback(failures.append) - self.assertEqual( - [], failures, "Got errbacks but wasn't expecting any.") - - self.assertEqual( - results, - [('start-of-cb', 'outer'), - ('firstCallback', 'inner'), - ('secondCallback', ['withers']), - ['withers', 'withers']]) - - - def test_chainDeferredRecordsExplicitChain(self): - """ - When we chain a L{Deferred}, that chaining is recorded explicitly. - """ - a = defer.Deferred() - b = defer.Deferred() - b.chainDeferred(a) - self.assertIdentical(a._chainedTo, b) - - - def test_explicitChainClearedWhenResolved(self): - """ - Any recorded chaining is cleared once the chaining is resolved, since - it no longer exists. - - In other words, if one L{Deferred} is recorded as depending on the - result of another, and I{that} L{Deferred} has fired, then the - dependency is resolved and we no longer benefit from recording it. - """ - a = defer.Deferred() - b = defer.Deferred() - b.chainDeferred(a) - b.callback(None) - self.assertIdentical(a._chainedTo, None) - - - def test_chainDeferredRecordsImplicitChain(self): - """ - We can chain L{Deferred}s implicitly by adding callbacks that return - L{Deferred}s. When this chaining happens, we record it explicitly as - soon as we can find out about it. - """ - a = defer.Deferred() - b = defer.Deferred() - a.addCallback(lambda ignored: b) - a.callback(None) - self.assertIdentical(a._chainedTo, b) - - - def test_repr(self): - """ - The C{repr()} of a L{Deferred} contains the class name and a - representation of the internal Python ID. - """ - d = defer.Deferred() - address = hex(unsignedID(d)) - self.assertEqual( - repr(d), '<Deferred at %s>' % (address,)) - - - def test_reprWithResult(self): - """ - If a L{Deferred} has been fired, then its C{repr()} contains its - result. - """ - d = defer.Deferred() - d.callback('orange') - self.assertEqual( - repr(d), "<Deferred at %s current result: 'orange'>" % ( - hex(unsignedID(d)))) - - - def test_reprWithChaining(self): - """ - If a L{Deferred} C{a} has been fired, but is waiting on another - L{Deferred} C{b} that appears in its callback chain, then C{repr(a)} - says that it is waiting on C{b}. - """ - a = defer.Deferred() - b = defer.Deferred() - b.chainDeferred(a) - self.assertEqual( - repr(a), "<Deferred at %s waiting on Deferred at %s>" % ( - hex(unsignedID(a)), hex(unsignedID(b)))) - - - def test_boundedStackDepth(self): - """ - The depth of the call stack does not grow as more L{Deferred} instances - are chained together. - """ - def chainDeferreds(howMany): - stack = [] - def recordStackDepth(ignored): - stack.append(len(traceback.extract_stack())) - - top = defer.Deferred() - innerDeferreds = [defer.Deferred() for ignored in range(howMany)] - originalInners = innerDeferreds[:] - last = defer.Deferred() - - inner = innerDeferreds.pop() - top.addCallback(lambda ign, inner=inner: inner) - top.addCallback(recordStackDepth) - - while innerDeferreds: - newInner = innerDeferreds.pop() - inner.addCallback(lambda ign, inner=newInner: inner) - inner = newInner - inner.addCallback(lambda ign: last) - - top.callback(None) - for inner in originalInners: - inner.callback(None) - - # Sanity check - the record callback is not intended to have - # fired yet. - self.assertEqual(stack, []) - - # Now fire the last thing and return the stack depth at which the - # callback was invoked. - last.callback(None) - return stack[0] - - # Callbacks should be invoked at the same stack depth regardless of - # how many Deferreds are chained. - self.assertEqual(chainDeferreds(1), chainDeferreds(2)) - - - def test_resultOfDeferredResultOfDeferredOfFiredDeferredCalled(self): - """ - Given three Deferreds, one chained to the next chained to the next, - callbacks on the middle Deferred which are added after the chain is - created are called once the last Deferred fires. - - This is more of a regression-style test. It doesn't exercise any - particular code path through the current implementation of Deferred, but - it does exercise a broken codepath through one of the variations of the - implementation proposed as a resolution to ticket #411. - """ - first = defer.Deferred() - second = defer.Deferred() - third = defer.Deferred() - first.addCallback(lambda ignored: second) - second.addCallback(lambda ignored: third) - second.callback(None) - first.callback(None) - third.callback(None) - L = [] - second.addCallback(L.append) - self.assertEqual(L, [None]) - - - def test_errbackWithNoArgsNoDebug(self): - """ - C{Deferred.errback()} creates a failure from the current Python - exception. When Deferred.debug is not set no globals or locals are - captured in that failure. - """ - defer.setDebugging(False) - d = defer.Deferred() - l = [] - exc = GenericError("Bang") - try: - raise exc - except: - d.errback() - d.addErrback(l.append) - fail = l[0] - self.assertEqual(fail.value, exc) - localz, globalz = fail.frames[0][-2:] - self.assertEqual([], localz) - self.assertEqual([], globalz) - - - def test_errbackWithNoArgs(self): - """ - C{Deferred.errback()} creates a failure from the current Python - exception. When Deferred.debug is set globals and locals are captured - in that failure. - """ - defer.setDebugging(True) - d = defer.Deferred() - l = [] - exc = GenericError("Bang") - try: - raise exc - except: - d.errback() - d.addErrback(l.append) - fail = l[0] - self.assertEqual(fail.value, exc) - localz, globalz = fail.frames[0][-2:] - self.assertNotEquals([], localz) - self.assertNotEquals([], globalz) - - - def test_errorInCallbackDoesNotCaptureVars(self): - """ - An error raised by a callback creates a Failure. The Failure captures - locals and globals if and only if C{Deferred.debug} is set. - """ - d = defer.Deferred() - d.callback(None) - defer.setDebugging(False) - def raiseError(ignored): - raise GenericError("Bang") - d.addCallback(raiseError) - l = [] - d.addErrback(l.append) - fail = l[0] - localz, globalz = fail.frames[0][-2:] - self.assertEqual([], localz) - self.assertEqual([], globalz) - - - def test_errorInCallbackCapturesVarsWhenDebugging(self): - """ - An error raised by a callback creates a Failure. The Failure captures - locals and globals if and only if C{Deferred.debug} is set. - """ - d = defer.Deferred() - d.callback(None) - defer.setDebugging(True) - def raiseError(ignored): - raise GenericError("Bang") - d.addCallback(raiseError) - l = [] - d.addErrback(l.append) - fail = l[0] - localz, globalz = fail.frames[0][-2:] - self.assertNotEquals([], localz) - self.assertNotEquals([], globalz) - - - -class FirstErrorTests(unittest.TestCase): - """ - Tests for L{FirstError}. - """ - def test_repr(self): - """ - The repr of a L{FirstError} instance includes the repr of the value of - the sub-failure and the index which corresponds to the L{FirstError}. - """ - exc = ValueError("some text") - try: - raise exc - except: - f = failure.Failure() - - error = defer.FirstError(f, 3) - self.assertEqual( - repr(error), - "FirstError[#3, %s]" % (repr(exc),)) - - - def test_str(self): - """ - The str of a L{FirstError} instance includes the str of the - sub-failure and the index which corresponds to the L{FirstError}. - """ - exc = ValueError("some text") - try: - raise exc - except: - f = failure.Failure() - - error = defer.FirstError(f, 5) - self.assertEqual( - str(error), - "FirstError[#5, %s]" % (str(f),)) - - - def test_comparison(self): - """ - L{FirstError} instances compare equal to each other if and only if - their failure and index compare equal. L{FirstError} instances do not - compare equal to instances of other types. - """ - try: - 1 // 0 - except: - firstFailure = failure.Failure() - - one = defer.FirstError(firstFailure, 13) - anotherOne = defer.FirstError(firstFailure, 13) - - try: - raise ValueError("bar") - except: - secondFailure = failure.Failure() - - another = defer.FirstError(secondFailure, 9) - - self.assertTrue(one == anotherOne) - self.assertFalse(one == another) - self.assertTrue(one != another) - self.assertFalse(one != anotherOne) - - self.assertFalse(one == 10) - - - -class AlreadyCalledTestCase(unittest.TestCase): - def setUp(self): - self._deferredWasDebugging = defer.getDebugging() - defer.setDebugging(True) - - def tearDown(self): - defer.setDebugging(self._deferredWasDebugging) - - def _callback(self, *args, **kw): - pass - def _errback(self, *args, **kw): - pass - - def _call_1(self, d): - d.callback("hello") - def _call_2(self, d): - d.callback("twice") - def _err_1(self, d): - d.errback(failure.Failure(RuntimeError())) - def _err_2(self, d): - d.errback(failure.Failure(RuntimeError())) - - def testAlreadyCalled_CC(self): - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - self._call_1(d) - self.failUnlessRaises(defer.AlreadyCalledError, self._call_2, d) - - def testAlreadyCalled_CE(self): - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - self._call_1(d) - self.failUnlessRaises(defer.AlreadyCalledError, self._err_2, d) - - def testAlreadyCalled_EE(self): - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - self._err_1(d) - self.failUnlessRaises(defer.AlreadyCalledError, self._err_2, d) - - def testAlreadyCalled_EC(self): - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - self._err_1(d) - self.failUnlessRaises(defer.AlreadyCalledError, self._call_2, d) - - - def _count(self, linetype, func, lines, expected): - count = 0 - for line in lines: - if (line.startswith(' %s:' % linetype) and - line.endswith(' %s' % func)): - count += 1 - self.failUnless(count == expected) - - def _check(self, e, caller, invoker1, invoker2): - # make sure the debugging information is vaguely correct - lines = e.args[0].split("\n") - # the creator should list the creator (testAlreadyCalledDebug) but not - # _call_1 or _call_2 or other invokers - self._count('C', caller, lines, 1) - self._count('C', '_call_1', lines, 0) - self._count('C', '_call_2', lines, 0) - self._count('C', '_err_1', lines, 0) - self._count('C', '_err_2', lines, 0) - # invoker should list the first invoker but not the second - self._count('I', invoker1, lines, 1) - self._count('I', invoker2, lines, 0) - - def testAlreadyCalledDebug_CC(self): - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - self._call_1(d) - try: - self._call_2(d) - except defer.AlreadyCalledError, e: - self._check(e, "testAlreadyCalledDebug_CC", "_call_1", "_call_2") - else: - self.fail("second callback failed to raise AlreadyCalledError") - - def testAlreadyCalledDebug_CE(self): - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - self._call_1(d) - try: - self._err_2(d) - except defer.AlreadyCalledError, e: - self._check(e, "testAlreadyCalledDebug_CE", "_call_1", "_err_2") - else: - self.fail("second errback failed to raise AlreadyCalledError") - - def testAlreadyCalledDebug_EC(self): - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - self._err_1(d) - try: - self._call_2(d) - except defer.AlreadyCalledError, e: - self._check(e, "testAlreadyCalledDebug_EC", "_err_1", "_call_2") - else: - self.fail("second callback failed to raise AlreadyCalledError") - - def testAlreadyCalledDebug_EE(self): - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - self._err_1(d) - try: - self._err_2(d) - except defer.AlreadyCalledError, e: - self._check(e, "testAlreadyCalledDebug_EE", "_err_1", "_err_2") - else: - self.fail("second errback failed to raise AlreadyCalledError") - - def testNoDebugging(self): - defer.setDebugging(False) - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - self._call_1(d) - try: - self._call_2(d) - except defer.AlreadyCalledError, e: - self.failIf(e.args) - else: - self.fail("second callback failed to raise AlreadyCalledError") - - - def testSwitchDebugging(self): - # Make sure Deferreds can deal with debug state flipping - # around randomly. This is covering a particular fixed bug. - defer.setDebugging(False) - d = defer.Deferred() - d.addBoth(lambda ign: None) - defer.setDebugging(True) - d.callback(None) - - defer.setDebugging(False) - d = defer.Deferred() - d.callback(None) - defer.setDebugging(True) - d.addBoth(lambda ign: None) - - - -class DeferredCancellerTest(unittest.TestCase): - def setUp(self): - self.callbackResults = None - self.errbackResults = None - self.callback2Results = None - self.cancellerCallCount = 0 - - - def tearDown(self): - # Sanity check that the canceller was called at most once. - self.assertTrue(self.cancellerCallCount in (0, 1)) - - - def _callback(self, data): - self.callbackResults = data - return data - - - def _callback2(self, data): - self.callback2Results = data - - - def _errback(self, data): - self.errbackResults = data - - - def test_noCanceller(self): - """ - A L{defer.Deferred} without a canceller must errback with a - L{defer.CancelledError} and not callback. - """ - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - d.cancel() - self.assertEqual(self.errbackResults.type, defer.CancelledError) - self.assertEqual(self.callbackResults, None) - - - def test_raisesAfterCancelAndCallback(self): - """ - A L{defer.Deferred} without a canceller, when cancelled must allow - a single extra call to callback, and raise - L{defer.AlreadyCalledError} if callbacked or errbacked thereafter. - """ - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - d.cancel() - - # A single extra callback should be swallowed. - d.callback(None) - - # But a second call to callback or errback is not. - self.assertRaises(defer.AlreadyCalledError, d.callback, None) - self.assertRaises(defer.AlreadyCalledError, d.errback, Exception()) - - - def test_raisesAfterCancelAndErrback(self): - """ - A L{defer.Deferred} without a canceller, when cancelled must allow - a single extra call to errback, and raise - L{defer.AlreadyCalledError} if callbacked or errbacked thereafter. - """ - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - d.cancel() - - # A single extra errback should be swallowed. - d.errback(Exception()) - - # But a second call to callback or errback is not. - self.assertRaises(defer.AlreadyCalledError, d.callback, None) - self.assertRaises(defer.AlreadyCalledError, d.errback, Exception()) - - - def test_noCancellerMultipleCancelsAfterCancelAndCallback(self): - """ - A L{Deferred} without a canceller, when cancelled and then - callbacked, ignores multiple cancels thereafter. - """ - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - d.cancel() - currentFailure = self.errbackResults - # One callback will be ignored - d.callback(None) - # Cancel should have no effect. - d.cancel() - self.assertIdentical(currentFailure, self.errbackResults) - - - def test_noCancellerMultipleCancelsAfterCancelAndErrback(self): - """ - A L{defer.Deferred} without a canceller, when cancelled and then - errbacked, ignores multiple cancels thereafter. - """ - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - d.cancel() - self.assertEqual(self.errbackResults.type, defer.CancelledError) - currentFailure = self.errbackResults - # One errback will be ignored - d.errback(GenericError()) - # I.e., we should still have a CancelledError. - self.assertEqual(self.errbackResults.type, defer.CancelledError) - d.cancel() - self.assertIdentical(currentFailure, self.errbackResults) - - - def test_noCancellerMultipleCancel(self): - """ - Calling cancel multiple times on a deferred with no canceller - results in a L{defer.CancelledError}. Subsequent calls to cancel - do not cause an error. - """ - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - d.cancel() - self.assertEqual(self.errbackResults.type, defer.CancelledError) - currentFailure = self.errbackResults - d.cancel() - self.assertIdentical(currentFailure, self.errbackResults) - - - def test_cancellerMultipleCancel(self): - """ - Verify that calling cancel multiple times on a deferred with a - canceller that does not errback results in a - L{defer.CancelledError} and that subsequent calls to cancel do not - cause an error and that after all that, the canceller was only - called once. - """ - def cancel(d): - self.cancellerCallCount += 1 - - d = defer.Deferred(canceller=cancel) - d.addCallbacks(self._callback, self._errback) - d.cancel() - self.assertEqual(self.errbackResults.type, defer.CancelledError) - currentFailure = self.errbackResults - d.cancel() - self.assertIdentical(currentFailure, self.errbackResults) - self.assertEqual(self.cancellerCallCount, 1) - - - def test_simpleCanceller(self): - """ - Verify that a L{defer.Deferred} calls its specified canceller when - it is cancelled, and that further call/errbacks raise - L{defer.AlreadyCalledError}. - """ - def cancel(d): - self.cancellerCallCount += 1 - - d = defer.Deferred(canceller=cancel) - d.addCallbacks(self._callback, self._errback) - d.cancel() - self.assertEqual(self.cancellerCallCount, 1) - self.assertEqual(self.errbackResults.type, defer.CancelledError) - - # Test that further call/errbacks are *not* swallowed - self.assertRaises(defer.AlreadyCalledError, d.callback, None) - self.assertRaises(defer.AlreadyCalledError, d.errback, Exception()) - - - def test_cancellerArg(self): - """ - Verify that a canceller is given the correct deferred argument. - """ - def cancel(d1): - self.assertIdentical(d1, d) - d = defer.Deferred(canceller=cancel) - d.addCallbacks(self._callback, self._errback) - d.cancel() - - - def test_cancelAfterCallback(self): - """ - Test that cancelling a deferred after it has been callbacked does - not cause an error. - """ - def cancel(d): - self.cancellerCallCount += 1 - d.errback(GenericError()) - d = defer.Deferred(canceller=cancel) - d.addCallbacks(self._callback, self._errback) - d.callback('biff!') - d.cancel() - self.assertEqual(self.cancellerCallCount, 0) - self.assertEqual(self.errbackResults, None) - self.assertEqual(self.callbackResults, 'biff!') - - - def test_cancelAfterErrback(self): - """ - Test that cancelling a L{Deferred} after it has been errbacked does - not result in a L{defer.CancelledError}. - """ - def cancel(d): - self.cancellerCallCount += 1 - d.errback(GenericError()) - d = defer.Deferred(canceller=cancel) - d.addCallbacks(self._callback, self._errback) - d.errback(GenericError()) - d.cancel() - self.assertEqual(self.cancellerCallCount, 0) - self.assertEqual(self.errbackResults.type, GenericError) - self.assertEqual(self.callbackResults, None) - - - def test_cancellerThatErrbacks(self): - """ - Test a canceller which errbacks its deferred. - """ - def cancel(d): - self.cancellerCallCount += 1 - d.errback(GenericError()) - d = defer.Deferred(canceller=cancel) - d.addCallbacks(self._callback, self._errback) - d.cancel() - self.assertEqual(self.cancellerCallCount, 1) - self.assertEqual(self.errbackResults.type, GenericError) - - - def test_cancellerThatCallbacks(self): - """ - Test a canceller which calls its deferred. - """ - def cancel(d): - self.cancellerCallCount += 1 - d.callback('hello!') - d = defer.Deferred(canceller=cancel) - d.addCallbacks(self._callback, self._errback) - d.cancel() - self.assertEqual(self.cancellerCallCount, 1) - self.assertEqual(self.callbackResults, 'hello!') - self.assertEqual(self.errbackResults, None) - - - def test_cancelNestedDeferred(self): - """ - Verify that a Deferred, a, which is waiting on another Deferred, b, - returned from one of its callbacks, will propagate - L{defer.CancelledError} when a is cancelled. - """ - def innerCancel(d): - self.cancellerCallCount += 1 - def cancel(d): - self.assert_(False) - - b = defer.Deferred(canceller=innerCancel) - a = defer.Deferred(canceller=cancel) - a.callback(None) - a.addCallback(lambda data: b) - a.cancel() - a.addCallbacks(self._callback, self._errback) - # The cancel count should be one (the cancellation done by B) - self.assertEqual(self.cancellerCallCount, 1) - # B's canceller didn't errback, so defer.py will have called errback - # with a CancelledError. - self.assertEqual(self.errbackResults.type, defer.CancelledError) - - - -class LogTestCase(unittest.TestCase): - """ - Test logging of unhandled errors. - """ - - def setUp(self): - """ - Add a custom observer to observer logging. - """ - self.c = [] - log.addObserver(self.c.append) - - def tearDown(self): - """ - Remove the observer. - """ - log.removeObserver(self.c.append) - - - def _loggedErrors(self): - return [e for e in self.c if e["isError"]] - - - def _check(self): - """ - Check the output of the log observer to see if the error is present. - """ - c2 = self._loggedErrors() - self.assertEqual(len(c2), 2) - c2[1]["failure"].trap(ZeroDivisionError) - self.flushLoggedErrors(ZeroDivisionError) - - def test_errorLog(self): - """ - Verify that when a L{Deferred} with no references to it is fired, - and its final result (the one not handled by any callback) is an - exception, that exception will be logged immediately. - """ - defer.Deferred().addCallback(lambda x: 1 // 0).callback(1) - gc.collect() - self._check() - - def test_errorLogWithInnerFrameRef(self): - """ - Same as L{test_errorLog}, but with an inner frame. - """ - def _subErrorLogWithInnerFrameRef(): - d = defer.Deferred() - d.addCallback(lambda x: 1 // 0) - d.callback(1) - - _subErrorLogWithInnerFrameRef() - gc.collect() - self._check() - - def test_errorLogWithInnerFrameCycle(self): - """ - Same as L{test_errorLogWithInnerFrameRef}, plus create a cycle. - """ - def _subErrorLogWithInnerFrameCycle(): - d = defer.Deferred() - d.addCallback(lambda x, d=d: 1 // 0) - d._d = d - d.callback(1) - - _subErrorLogWithInnerFrameCycle() - gc.collect() - self._check() - - - def test_chainedErrorCleanup(self): - """ - If one Deferred with an error result is returned from a callback on - another Deferred, when the first Deferred is garbage collected it does - not log its error. - """ - d = defer.Deferred() - d.addCallback(lambda ign: defer.fail(RuntimeError("zoop"))) - d.callback(None) - - # Sanity check - this isn't too interesting, but we do want the original - # Deferred to have gotten the failure. - results = [] - errors = [] - d.addCallbacks(results.append, errors.append) - self.assertEqual(results, []) - self.assertEqual(len(errors), 1) - errors[0].trap(Exception) - - # Get rid of any references we might have to the inner Deferred (none of - # these should really refer to it, but we're just being safe). - del results, errors, d - # Force a collection cycle so that there's a chance for an error to be - # logged, if it's going to be logged. - gc.collect() - # And make sure it is not. - self.assertEqual(self._loggedErrors(), []) - - - def test_errorClearedByChaining(self): - """ - If a Deferred with a failure result has an errback which chains it to - another Deferred, the initial failure is cleared by the errback so it is - not logged. - """ - # Start off with a Deferred with a failure for a result - bad = defer.fail(Exception("oh no")) - good = defer.Deferred() - # Give it a callback that chains it to another Deferred - bad.addErrback(lambda ignored: good) - # That's all, clean it up. No Deferred here still has a failure result, - # so nothing should be logged. - good = bad = None - gc.collect() - self.assertEqual(self._loggedErrors(), []) - - - -class DeferredTestCaseII(unittest.TestCase): - def setUp(self): - self.callbackRan = 0 - - def testDeferredListEmpty(self): - """Testing empty DeferredList.""" - dl = defer.DeferredList([]) - dl.addCallback(self.cb_empty) - - def cb_empty(self, res): - self.callbackRan = 1 - self.assertEqual([], res) - - def tearDown(self): - self.failUnless(self.callbackRan, "Callback was never run.") - -class OtherPrimitives(unittest.TestCase): - def _incr(self, result): - self.counter += 1 - - def setUp(self): - self.counter = 0 - - def testLock(self): - lock = defer.DeferredLock() - lock.acquire().addCallback(self._incr) - self.failUnless(lock.locked) - self.assertEqual(self.counter, 1) - - lock.acquire().addCallback(self._incr) - self.failUnless(lock.locked) - self.assertEqual(self.counter, 1) - - lock.release() - self.failUnless(lock.locked) - self.assertEqual(self.counter, 2) - - lock.release() - self.failIf(lock.locked) - self.assertEqual(self.counter, 2) - - self.assertRaises(TypeError, lock.run) - - firstUnique = object() - secondUnique = object() - - controlDeferred = defer.Deferred() - def helper(self, b): - self.b = b - return controlDeferred - - resultDeferred = lock.run(helper, self=self, b=firstUnique) - self.failUnless(lock.locked) - self.assertEqual(self.b, firstUnique) - - resultDeferred.addCallback(lambda x: setattr(self, 'result', x)) - - lock.acquire().addCallback(self._incr) - self.failUnless(lock.locked) - self.assertEqual(self.counter, 2) - - controlDeferred.callback(secondUnique) - self.assertEqual(self.result, secondUnique) - self.failUnless(lock.locked) - self.assertEqual(self.counter, 3) - - d = lock.acquire().addBoth(lambda x: setattr(self, 'result', x)) - d.cancel() - self.assertEqual(self.result.type, defer.CancelledError) - - lock.release() - self.failIf(lock.locked) - - - def test_cancelLockAfterAcquired(self): - """ - When canceling a L{Deferred} from a L{DeferredLock} that already - has the lock, the cancel should have no effect. - """ - def _failOnErrback(_): - self.fail("Unexpected errback call!") - lock = defer.DeferredLock() - d = lock.acquire() - d.addErrback(_failOnErrback) - d.cancel() - - - def test_cancelLockBeforeAcquired(self): - """ - When canceling a L{Deferred} from a L{DeferredLock} that does not - yet have the lock (i.e., the L{Deferred} has not fired), the cancel - should cause a L{defer.CancelledError} failure. - """ - lock = defer.DeferredLock() - lock.acquire() - d = lock.acquire() - self.assertFailure(d, defer.CancelledError) - d.cancel() - - - def testSemaphore(self): - N = 13 - sem = defer.DeferredSemaphore(N) - - controlDeferred = defer.Deferred() - def helper(self, arg): - self.arg = arg - return controlDeferred - - results = [] - uniqueObject = object() - resultDeferred = sem.run(helper, self=self, arg=uniqueObject) - resultDeferred.addCallback(results.append) - resultDeferred.addCallback(self._incr) - self.assertEqual(results, []) - self.assertEqual(self.arg, uniqueObject) - controlDeferred.callback(None) - self.assertEqual(results.pop(), None) - self.assertEqual(self.counter, 1) - - self.counter = 0 - for i in range(1, 1 + N): - sem.acquire().addCallback(self._incr) - self.assertEqual(self.counter, i) - - - success = [] - def fail(r): - success.append(False) - def succeed(r): - success.append(True) - d = sem.acquire().addCallbacks(fail, succeed) - d.cancel() - self.assertEqual(success, [True]) - - sem.acquire().addCallback(self._incr) - self.assertEqual(self.counter, N) - - sem.release() - self.assertEqual(self.counter, N + 1) - - for i in range(1, 1 + N): - sem.release() - self.assertEqual(self.counter, N + 1) - - - def test_semaphoreInvalidTokens(self): - """ - If the token count passed to L{DeferredSemaphore} is less than one - then L{ValueError} is raised. - """ - self.assertRaises(ValueError, defer.DeferredSemaphore, 0) - self.assertRaises(ValueError, defer.DeferredSemaphore, -1) - - - def test_cancelSemaphoreAfterAcquired(self): - """ - When canceling a L{Deferred} from a L{DeferredSemaphore} that - already has the semaphore, the cancel should have no effect. - """ - def _failOnErrback(_): - self.fail("Unexpected errback call!") - - sem = defer.DeferredSemaphore(1) - d = sem.acquire() - d.addErrback(_failOnErrback) - d.cancel() - - - def test_cancelSemaphoreBeforeAcquired(self): - """ - When canceling a L{Deferred} from a L{DeferredSemaphore} that does - not yet have the semaphore (i.e., the L{Deferred} has not fired), - the cancel should cause a L{defer.CancelledError} failure. - """ - sem = defer.DeferredSemaphore(1) - sem.acquire() - d = sem.acquire() - self.assertFailure(d, defer.CancelledError) - d.cancel() - return d - - - def testQueue(self): - N, M = 2, 2 - queue = defer.DeferredQueue(N, M) - - gotten = [] - - for i in range(M): - queue.get().addCallback(gotten.append) - self.assertRaises(defer.QueueUnderflow, queue.get) - - for i in range(M): - queue.put(i) - self.assertEqual(gotten, range(i + 1)) - for i in range(N): - queue.put(N + i) - self.assertEqual(gotten, range(M)) - self.assertRaises(defer.QueueOverflow, queue.put, None) - - gotten = [] - for i in range(N): - queue.get().addCallback(gotten.append) - self.assertEqual(gotten, range(N, N + i + 1)) - - queue = defer.DeferredQueue() - gotten = [] - for i in range(N): - queue.get().addCallback(gotten.append) - for i in range(N): - queue.put(i) - self.assertEqual(gotten, range(N)) - - queue = defer.DeferredQueue(size=0) - self.assertRaises(defer.QueueOverflow, queue.put, None) - - queue = defer.DeferredQueue(backlog=0) - self.assertRaises(defer.QueueUnderflow, queue.get) - - - def test_cancelQueueAfterSynchronousGet(self): - """ - When canceling a L{Deferred} from a L{DeferredQueue} that already has - a result, the cancel should have no effect. - """ - def _failOnErrback(_): - self.fail("Unexpected errback call!") - - queue = defer.DeferredQueue() - d = queue.get() - d.addErrback(_failOnErrback) - queue.put(None) - d.cancel() - - - def test_cancelQueueAfterGet(self): - """ - When canceling a L{Deferred} from a L{DeferredQueue} that does not - have a result (i.e., the L{Deferred} has not fired), the cancel - causes a L{defer.CancelledError} failure. If the queue has a result - later on, it doesn't try to fire the deferred. - """ - queue = defer.DeferredQueue() - d = queue.get() - self.assertFailure(d, defer.CancelledError) - d.cancel() - def cb(ignore): - # If the deferred is still linked with the deferred queue, it will - # fail with an AlreadyCalledError - queue.put(None) - return queue.get().addCallback(self.assertIdentical, None) - return d.addCallback(cb) - - - -class DeferredFilesystemLockTestCase(unittest.TestCase): - """ - Test the behavior of L{DeferredFilesystemLock} - """ - def setUp(self): - self.clock = Clock() - self.lock = defer.DeferredFilesystemLock(self.mktemp(), - scheduler=self.clock) - - - def test_waitUntilLockedWithNoLock(self): - """ - Test that the lock can be acquired when no lock is held - """ - d = self.lock.deferUntilLocked(timeout=1) - - return d - - - def test_waitUntilLockedWithTimeoutLocked(self): - """ - Test that the lock can not be acquired when the lock is held - for longer than the timeout. - """ - self.failUnless(self.lock.lock()) - - d = self.lock.deferUntilLocked(timeout=5.5) - self.assertFailure(d, defer.TimeoutError) - - self.clock.pump([1] * 10) - - return d - - - def test_waitUntilLockedWithTimeoutUnlocked(self): - """ - Test that a lock can be acquired while a lock is held - but the lock is unlocked before our timeout. - """ - def onTimeout(f): - f.trap(defer.TimeoutError) - self.fail("Should not have timed out") - - self.failUnless(self.lock.lock()) - - self.clock.callLater(1, self.lock.unlock) - d = self.lock.deferUntilLocked(timeout=10) - d.addErrback(onTimeout) - - self.clock.pump([1] * 10) - - return d - - - def test_defaultScheduler(self): - """ - Test that the default scheduler is set up properly. - """ - lock = defer.DeferredFilesystemLock(self.mktemp()) - - self.assertEqual(lock._scheduler, reactor) - - - def test_concurrentUsage(self): - """ - Test that an appropriate exception is raised when attempting - to use deferUntilLocked concurrently. - """ - self.lock.lock() - self.clock.callLater(1, self.lock.unlock) - - d = self.lock.deferUntilLocked() - d2 = self.lock.deferUntilLocked() - - self.assertFailure(d2, defer.AlreadyTryingToLockError) - - self.clock.advance(1) - - return d - - - def test_multipleUsages(self): - """ - Test that a DeferredFilesystemLock can be used multiple times - """ - def lockAquired(ign): - self.lock.unlock() - d = self.lock.deferUntilLocked() - return d - - self.lock.lock() - self.clock.callLater(1, self.lock.unlock) - - d = self.lock.deferUntilLocked() - d.addCallback(lockAquired) - - self.clock.advance(1) - - return d |