| OLD | NEW |
| (Empty) |
| 1 | |
| 2 # Copyright (c) 2001-2007 Twisted Matrix Laboratories. | |
| 3 # See LICENSE for details. | |
| 4 | |
| 5 | |
| 6 """ | |
| 7 Test cases for defer module. | |
| 8 """ | |
| 9 | |
| 10 import gc | |
| 11 | |
| 12 from twisted.trial import unittest, util | |
| 13 from twisted.internet import reactor, defer | |
| 14 from twisted.python import failure, log | |
| 15 | |
| 16 from twisted.internet.task import Clock | |
| 17 | |
| 18 class GenericError(Exception): | |
| 19 pass | |
| 20 | |
| 21 | |
| 22 _setTimeoutSuppression = util.suppress( | |
| 23 message="Deferred.setTimeout is deprecated. Look for timeout " | |
| 24 "support specific to the API you are using instead.", | |
| 25 category=DeprecationWarning) | |
| 26 | |
| 27 _firstErrorSuppression = util.suppress( | |
| 28 message="FirstError.__getitem__ is deprecated. Use attributes instead.", | |
| 29 category=DeprecationWarning) | |
| 30 | |
| 31 | |
| 32 class DeferredTestCase(unittest.TestCase): | |
| 33 | |
| 34 def setUp(self): | |
| 35 self.callback_results = None | |
| 36 self.errback_results = None | |
| 37 self.callback2_results = None | |
| 38 | |
| 39 def _callback(self, *args, **kw): | |
| 40 self.callback_results = args, kw | |
| 41 return args[0] | |
| 42 | |
| 43 def _callback2(self, *args, **kw): | |
| 44 self.callback2_results = args, kw | |
| 45 | |
| 46 def _errback(self, *args, **kw): | |
| 47 self.errback_results = args, kw | |
| 48 | |
| 49 def testCallbackWithoutArgs(self): | |
| 50 deferred = defer.Deferred() | |
| 51 deferred.addCallback(self._callback) | |
| 52 deferred.callback("hello") | |
| 53 self.failUnlessEqual(self.errback_results, None) | |
| 54 self.failUnlessEqual(self.callback_results, (('hello',), {})) | |
| 55 | |
| 56 def testCallbackWithArgs(self): | |
| 57 deferred = defer.Deferred() | |
| 58 deferred.addCallback(self._callback, "world") | |
| 59 deferred.callback("hello") | |
| 60 self.failUnlessEqual(self.errback_results, None) | |
| 61 self.failUnlessEqual(self.callback_results, (('hello', 'world'), {})) | |
| 62 | |
| 63 def testCallbackWithKwArgs(self): | |
| 64 deferred = defer.Deferred() | |
| 65 deferred.addCallback(self._callback, world="world") | |
| 66 deferred.callback("hello") | |
| 67 self.failUnlessEqual(self.errback_results, None) | |
| 68 self.failUnlessEqual(self.callback_results, | |
| 69 (('hello',), {'world': 'world'})) | |
| 70 | |
| 71 def testTwoCallbacks(self): | |
| 72 deferred = defer.Deferred() | |
| 73 deferred.addCallback(self._callback) | |
| 74 deferred.addCallback(self._callback2) | |
| 75 deferred.callback("hello") | |
| 76 self.failUnlessEqual(self.errback_results, None) | |
| 77 self.failUnlessEqual(self.callback_results, | |
| 78 (('hello',), {})) | |
| 79 self.failUnlessEqual(self.callback2_results, | |
| 80 (('hello',), {})) | |
| 81 | |
| 82 def testDeferredList(self): | |
| 83 defr1 = defer.Deferred() | |
| 84 defr2 = defer.Deferred() | |
| 85 defr3 = defer.Deferred() | |
| 86 dl = defer.DeferredList([defr1, defr2, defr3]) | |
| 87 result = [] | |
| 88 def cb(resultList, result=result): | |
| 89 result.extend(resultList) | |
| 90 def catch(err): | |
| 91 return None | |
| 92 dl.addCallbacks(cb, cb) | |
| 93 defr1.callback("1") | |
| 94 defr2.addErrback(catch) | |
| 95 # "catch" is added to eat the GenericError that will be passed on by | |
| 96 # the DeferredList's callback on defr2. If left unhandled, the | |
| 97 # Failure object would cause a log.err() warning about "Unhandled | |
| 98 # error in Deferred". Twisted's pyunit watches for log.err calls and | |
| 99 # treats them as failures. So "catch" must eat the error to prevent | |
| 100 # it from flunking the test. | |
| 101 defr2.errback(GenericError("2")) | |
| 102 defr3.callback("3") | |
| 103 self.failUnlessEqual([result[0], | |
| 104 #result[1][1] is now a Failure instead of an Exception | |
| 105 (result[1][0], str(result[1][1].value)), | |
| 106 result[2]], | |
| 107 | |
| 108 [(defer.SUCCESS, "1"), | |
| 109 (defer.FAILURE, "2"), | |
| 110 (defer.SUCCESS, "3")]) | |
| 111 | |
| 112 def testEmptyDeferredList(self): | |
| 113 result = [] | |
| 114 def cb(resultList, result=result): | |
| 115 result.append(resultList) | |
| 116 | |
| 117 dl = defer.DeferredList([]) | |
| 118 dl.addCallbacks(cb) | |
| 119 self.failUnlessEqual(result, [[]]) | |
| 120 | |
| 121 result[:] = [] | |
| 122 dl = defer.DeferredList([], fireOnOneCallback=1) | |
| 123 dl.addCallbacks(cb) | |
| 124 self.failUnlessEqual(result, []) | |
| 125 | |
| 126 def testDeferredListFireOnOneError(self): | |
| 127 defr1 = defer.Deferred() | |
| 128 defr2 = defer.Deferred() | |
| 129 defr3 = defer.Deferred() | |
| 130 dl = defer.DeferredList([defr1, defr2, defr3], fireOnOneErrback=1) | |
| 131 result = [] | |
| 132 dl.addErrback(result.append) | |
| 133 | |
| 134 # consume errors after they pass through the DeferredList (to avoid | |
| 135 # 'Unhandled error in Deferred'. | |
| 136 def catch(err): | |
| 137 return None | |
| 138 defr2.addErrback(catch) | |
| 139 | |
| 140 # fire one Deferred's callback, no result yet | |
| 141 defr1.callback("1") | |
| 142 self.failUnlessEqual(result, []) | |
| 143 | |
| 144 # fire one Deferred's errback -- now we have a result | |
| 145 defr2.errback(GenericError("from def2")) | |
| 146 self.failUnlessEqual(len(result), 1) | |
| 147 | |
| 148 # extract the result from the list | |
| 149 failure = result[0] | |
| 150 | |
| 151 # the type of the failure is a FirstError | |
| 152 self.failUnless(issubclass(failure.type, defer.FirstError), | |
| 153 'issubclass(failure.type, defer.FirstError) failed: ' | |
| 154 'failure.type is %r' % (failure.type,) | |
| 155 ) | |
| 156 | |
| 157 firstError = failure.value | |
| 158 | |
| 159 # check that the GenericError("2") from the deferred at index 1 | |
| 160 # (defr2) is intact inside failure.value | |
| 161 self.failUnlessEqual(firstError.subFailure.type, GenericError) | |
| 162 self.failUnlessEqual(firstError.subFailure.value.args, ("from def2",)) | |
| 163 self.failUnlessEqual(firstError.index, 1) | |
| 164 | |
| 165 | |
| 166 def test_indexingFirstError(self): | |
| 167 """ | |
| 168 L{FirstError} behaves a little like a tuple, for backwards | |
| 169 compatibility. Test that it can actually be indexed to retrieve | |
| 170 information about the failure. | |
| 171 """ | |
| 172 subFailure = object() | |
| 173 index = object() | |
| 174 firstError = defer.FirstError(subFailure, index) | |
| 175 self.assertIdentical(firstError[0], firstError.subFailure) | |
| 176 self.assertIdentical(firstError[1], firstError.index) | |
| 177 test_indexingFirstError.suppress = [_firstErrorSuppression] | |
| 178 | |
| 179 | |
| 180 def testDeferredListDontConsumeErrors(self): | |
| 181 d1 = defer.Deferred() | |
| 182 dl = defer.DeferredList([d1]) | |
| 183 | |
| 184 errorTrap = [] | |
| 185 d1.addErrback(errorTrap.append) | |
| 186 | |
| 187 result = [] | |
| 188 dl.addCallback(result.append) | |
| 189 | |
| 190 d1.errback(GenericError('Bang')) | |
| 191 self.failUnlessEqual('Bang', errorTrap[0].value.args[0]) | |
| 192 self.failUnlessEqual(1, len(result)) | |
| 193 self.failUnlessEqual('Bang', result[0][0][1].value.args[0]) | |
| 194 | |
| 195 def testDeferredListConsumeErrors(self): | |
| 196 d1 = defer.Deferred() | |
| 197 dl = defer.DeferredList([d1], consumeErrors=True) | |
| 198 | |
| 199 errorTrap = [] | |
| 200 d1.addErrback(errorTrap.append) | |
| 201 | |
| 202 result = [] | |
| 203 dl.addCallback(result.append) | |
| 204 | |
| 205 d1.errback(GenericError('Bang')) | |
| 206 self.failUnlessEqual([], errorTrap) | |
| 207 self.failUnlessEqual(1, len(result)) | |
| 208 self.failUnlessEqual('Bang', result[0][0][1].value.args[0]) | |
| 209 | |
| 210 def testDeferredListFireOnOneErrorWithAlreadyFiredDeferreds(self): | |
| 211 # Create some deferreds, and errback one | |
| 212 d1 = defer.Deferred() | |
| 213 d2 = defer.Deferred() | |
| 214 d1.errback(GenericError('Bang')) | |
| 215 | |
| 216 # *Then* build the DeferredList, with fireOnOneErrback=True | |
| 217 dl = defer.DeferredList([d1, d2], fireOnOneErrback=True) | |
| 218 result = [] | |
| 219 dl.addErrback(result.append) | |
| 220 self.failUnlessEqual(1, len(result)) | |
| 221 | |
| 222 d1.addErrback(lambda e: None) # Swallow error | |
| 223 | |
| 224 def testDeferredListWithAlreadyFiredDeferreds(self): | |
| 225 # Create some deferreds, and err one, call the other | |
| 226 d1 = defer.Deferred() | |
| 227 d2 = defer.Deferred() | |
| 228 d1.errback(GenericError('Bang')) | |
| 229 d2.callback(2) | |
| 230 | |
| 231 # *Then* build the DeferredList | |
| 232 dl = defer.DeferredList([d1, d2]) | |
| 233 | |
| 234 result = [] | |
| 235 dl.addCallback(result.append) | |
| 236 | |
| 237 self.failUnlessEqual(1, len(result)) | |
| 238 | |
| 239 d1.addErrback(lambda e: None) # Swallow error | |
| 240 | |
| 241 def testTimeOut(self): | |
| 242 """ | |
| 243 Test that a Deferred which has setTimeout called on it and never has | |
| 244 C{callback} or C{errback} called on it eventually fails with a | |
| 245 L{error.TimeoutError}. | |
| 246 """ | |
| 247 L = [] | |
| 248 d = defer.Deferred() | |
| 249 d.setTimeout(0.01) | |
| 250 self.assertFailure(d, defer.TimeoutError) | |
| 251 d.addCallback(L.append) | |
| 252 self.failIf(L, "Deferred failed too soon.") | |
| 253 return d | |
| 254 testTimeOut.suppress = [_setTimeoutSuppression] | |
| 255 | |
| 256 | |
| 257 def testImmediateSuccess(self): | |
| 258 l = [] | |
| 259 d = defer.succeed("success") | |
| 260 d.addCallback(l.append) | |
| 261 self.assertEquals(l, ["success"]) | |
| 262 | |
| 263 | |
| 264 def test_immediateSuccessBeforeTimeout(self): | |
| 265 """ | |
| 266 Test that a synchronously successful Deferred is not affected by a | |
| 267 C{setTimeout} call. | |
| 268 """ | |
| 269 l = [] | |
| 270 d = defer.succeed("success") | |
| 271 d.setTimeout(1.0) | |
| 272 d.addCallback(l.append) | |
| 273 self.assertEquals(l, ["success"]) | |
| 274 test_immediateSuccessBeforeTimeout.suppress = [_setTimeoutSuppression] | |
| 275 | |
| 276 | |
| 277 def testImmediateFailure(self): | |
| 278 l = [] | |
| 279 d = defer.fail(GenericError("fail")) | |
| 280 d.addErrback(l.append) | |
| 281 self.assertEquals(str(l[0].value), "fail") | |
| 282 | |
| 283 def testPausedFailure(self): | |
| 284 l = [] | |
| 285 d = defer.fail(GenericError("fail")) | |
| 286 d.pause() | |
| 287 d.addErrback(l.append) | |
| 288 self.assertEquals(l, []) | |
| 289 d.unpause() | |
| 290 self.assertEquals(str(l[0].value), "fail") | |
| 291 | |
| 292 def testCallbackErrors(self): | |
| 293 l = [] | |
| 294 d = defer.Deferred().addCallback(lambda _: 1/0).addErrback(l.append) | |
| 295 d.callback(1) | |
| 296 self.assert_(isinstance(l[0].value, ZeroDivisionError)) | |
| 297 l = [] | |
| 298 d = defer.Deferred().addCallback( | |
| 299 lambda _: failure.Failure(ZeroDivisionError())).addErrback(l.append) | |
| 300 d.callback(1) | |
| 301 self.assert_(isinstance(l[0].value, ZeroDivisionError)) | |
| 302 | |
| 303 def testUnpauseBeforeCallback(self): | |
| 304 d = defer.Deferred() | |
| 305 d.pause() | |
| 306 d.addCallback(self._callback) | |
| 307 d.unpause() | |
| 308 | |
| 309 def testReturnDeferred(self): | |
| 310 d = defer.Deferred() | |
| 311 d2 = defer.Deferred() | |
| 312 d2.pause() | |
| 313 d.addCallback(lambda r, d2=d2: d2) | |
| 314 d.addCallback(self._callback) | |
| 315 d.callback(1) | |
| 316 assert self.callback_results is None, "Should not have been called yet." | |
| 317 d2.callback(2) | |
| 318 assert self.callback_results is None, "Still should not have been called
yet." | |
| 319 d2.unpause() | |
| 320 assert self.callback_results[0][0] == 2, "Result should have been from s
econd deferred:%s"% (self.callback_results,) | |
| 321 | |
| 322 def testGatherResults(self): | |
| 323 # test successful list of deferreds | |
| 324 l = [] | |
| 325 defer.gatherResults([defer.succeed(1), defer.succeed(2)]).addCallback(l.
append) | |
| 326 self.assertEquals(l, [[1, 2]]) | |
| 327 # test failing list of deferreds | |
| 328 l = [] | |
| 329 dl = [defer.succeed(1), defer.fail(ValueError)] | |
| 330 defer.gatherResults(dl).addErrback(l.append) | |
| 331 self.assertEquals(len(l), 1) | |
| 332 self.assert_(isinstance(l[0], failure.Failure)) | |
| 333 # get rid of error | |
| 334 dl[1].addErrback(lambda e: 1) | |
| 335 | |
| 336 | |
| 337 def test_maybeDeferredSync(self): | |
| 338 """ | |
| 339 L{defer.maybeDeferred} should retrieve the result of a synchronous | |
| 340 function and pass it to its resulting L{defer.Deferred}. | |
| 341 """ | |
| 342 S, E = [], [] | |
| 343 d = defer.maybeDeferred((lambda x: x + 5), 10) | |
| 344 d.addCallbacks(S.append, E.append) | |
| 345 self.assertEquals(E, []) | |
| 346 self.assertEquals(S, [15]) | |
| 347 return d | |
| 348 | |
| 349 | |
| 350 def test_maybeDeferredSyncError(self): | |
| 351 """ | |
| 352 L{defer.maybeDeferred} should catch exception raised by a synchronous | |
| 353 function and errback its resulting L{defer.Deferred} with it. | |
| 354 """ | |
| 355 S, E = [], [] | |
| 356 try: | |
| 357 '10' + 5 | |
| 358 except TypeError, e: | |
| 359 expected = str(e) | |
| 360 d = defer.maybeDeferred((lambda x: x + 5), '10') | |
| 361 d.addCallbacks(S.append, E.append) | |
| 362 self.assertEquals(S, []) | |
| 363 self.assertEquals(len(E), 1) | |
| 364 self.assertEquals(str(E[0].value), expected) | |
| 365 return d | |
| 366 | |
| 367 | |
| 368 def test_maybeDeferredAsync(self): | |
| 369 """ | |
| 370 L{defer.maybeDeferred} should let L{defer.Deferred} instance pass by | |
| 371 so that original result is the same. | |
| 372 """ | |
| 373 d = defer.Deferred() | |
| 374 d2 = defer.maybeDeferred(lambda: d) | |
| 375 d.callback('Success') | |
| 376 return d2.addCallback(self.assertEquals, 'Success') | |
| 377 | |
| 378 | |
| 379 def test_maybeDeferredAsyncError(self): | |
| 380 """ | |
| 381 L{defer.maybeDeferred} should let L{defer.Deferred} instance pass by | |
| 382 so that L{failure.Failure} returned by the original instance is the | |
| 383 same. | |
| 384 """ | |
| 385 d = defer.Deferred() | |
| 386 d2 = defer.maybeDeferred(lambda: d) | |
| 387 d.errback(failure.Failure(RuntimeError())) | |
| 388 return self.assertFailure(d2, RuntimeError) | |
| 389 | |
| 390 | |
| 391 def test_reentrantRunCallbacks(self): | |
| 392 """ | |
| 393 A callback added to a L{Deferred} by a callback on that L{Deferred} | |
| 394 should be added to the end of the callback chain. | |
| 395 """ | |
| 396 deferred = defer.Deferred() | |
| 397 called = [] | |
| 398 def callback3(result): | |
| 399 called.append(3) | |
| 400 def callback2(result): | |
| 401 called.append(2) | |
| 402 def callback1(result): | |
| 403 called.append(1) | |
| 404 deferred.addCallback(callback3) | |
| 405 deferred.addCallback(callback1) | |
| 406 deferred.addCallback(callback2) | |
| 407 deferred.callback(None) | |
| 408 self.assertEqual(called, [1, 2, 3]) | |
| 409 | |
| 410 | |
| 411 def test_nonReentrantCallbacks(self): | |
| 412 """ | |
| 413 A callback added to a L{Deferred} by a callback on that L{Deferred} | |
| 414 should not be executed until the running callback returns. | |
| 415 """ | |
| 416 deferred = defer.Deferred() | |
| 417 called = [] | |
| 418 def callback2(result): | |
| 419 called.append(2) | |
| 420 def callback1(result): | |
| 421 called.append(1) | |
| 422 deferred.addCallback(callback2) | |
| 423 self.assertEquals(called, [1]) | |
| 424 deferred.addCallback(callback1) | |
| 425 deferred.callback(None) | |
| 426 self.assertEqual(called, [1, 2]) | |
| 427 | |
| 428 | |
| 429 def test_reentrantRunCallbacksWithFailure(self): | |
| 430 """ | |
| 431 After an exception is raised by a callback which was added to a | |
| 432 L{Deferred} by a callback on that L{Deferred}, the L{Deferred} should | |
| 433 call the first errback with a L{Failure} wrapping that exception. | |
| 434 """ | |
| 435 exceptionMessage = "callback raised exception" | |
| 436 deferred = defer.Deferred() | |
| 437 def callback2(result): | |
| 438 raise Exception(exceptionMessage) | |
| 439 def callback1(result): | |
| 440 deferred.addCallback(callback2) | |
| 441 deferred.addCallback(callback1) | |
| 442 deferred.callback(None) | |
| 443 self.assertFailure(deferred, Exception) | |
| 444 def cbFailed(exception): | |
| 445 self.assertEqual(exception.args, (exceptionMessage,)) | |
| 446 deferred.addCallback(cbFailed) | |
| 447 return deferred | |
| 448 | |
| 449 | |
| 450 | |
| 451 class AlreadyCalledTestCase(unittest.TestCase): | |
| 452 def setUp(self): | |
| 453 self._deferredWasDebugging = defer.getDebugging() | |
| 454 defer.setDebugging(True) | |
| 455 | |
| 456 def tearDown(self): | |
| 457 defer.setDebugging(self._deferredWasDebugging) | |
| 458 | |
| 459 def _callback(self, *args, **kw): | |
| 460 pass | |
| 461 def _errback(self, *args, **kw): | |
| 462 pass | |
| 463 | |
| 464 def _call_1(self, d): | |
| 465 d.callback("hello") | |
| 466 def _call_2(self, d): | |
| 467 d.callback("twice") | |
| 468 def _err_1(self, d): | |
| 469 d.errback(failure.Failure(RuntimeError())) | |
| 470 def _err_2(self, d): | |
| 471 d.errback(failure.Failure(RuntimeError())) | |
| 472 | |
| 473 def testAlreadyCalled_CC(self): | |
| 474 d = defer.Deferred() | |
| 475 d.addCallbacks(self._callback, self._errback) | |
| 476 self._call_1(d) | |
| 477 self.failUnlessRaises(defer.AlreadyCalledError, self._call_2, d) | |
| 478 | |
| 479 def testAlreadyCalled_CE(self): | |
| 480 d = defer.Deferred() | |
| 481 d.addCallbacks(self._callback, self._errback) | |
| 482 self._call_1(d) | |
| 483 self.failUnlessRaises(defer.AlreadyCalledError, self._err_2, d) | |
| 484 | |
| 485 def testAlreadyCalled_EE(self): | |
| 486 d = defer.Deferred() | |
| 487 d.addCallbacks(self._callback, self._errback) | |
| 488 self._err_1(d) | |
| 489 self.failUnlessRaises(defer.AlreadyCalledError, self._err_2, d) | |
| 490 | |
| 491 def testAlreadyCalled_EC(self): | |
| 492 d = defer.Deferred() | |
| 493 d.addCallbacks(self._callback, self._errback) | |
| 494 self._err_1(d) | |
| 495 self.failUnlessRaises(defer.AlreadyCalledError, self._call_2, d) | |
| 496 | |
| 497 | |
| 498 def _count(self, linetype, func, lines, expected): | |
| 499 count = 0 | |
| 500 for line in lines: | |
| 501 if (line.startswith(' %s:' % linetype) and | |
| 502 line.endswith(' %s' % func)): | |
| 503 count += 1 | |
| 504 self.failUnless(count == expected) | |
| 505 | |
| 506 def _check(self, e, caller, invoker1, invoker2): | |
| 507 # make sure the debugging information is vaguely correct | |
| 508 lines = e.args[0].split("\n") | |
| 509 # the creator should list the creator (testAlreadyCalledDebug) but not | |
| 510 # _call_1 or _call_2 or other invokers | |
| 511 self._count('C', caller, lines, 1) | |
| 512 self._count('C', '_call_1', lines, 0) | |
| 513 self._count('C', '_call_2', lines, 0) | |
| 514 self._count('C', '_err_1', lines, 0) | |
| 515 self._count('C', '_err_2', lines, 0) | |
| 516 # invoker should list the first invoker but not the second | |
| 517 self._count('I', invoker1, lines, 1) | |
| 518 self._count('I', invoker2, lines, 0) | |
| 519 | |
| 520 def testAlreadyCalledDebug_CC(self): | |
| 521 d = defer.Deferred() | |
| 522 d.addCallbacks(self._callback, self._errback) | |
| 523 self._call_1(d) | |
| 524 try: | |
| 525 self._call_2(d) | |
| 526 except defer.AlreadyCalledError, e: | |
| 527 self._check(e, "testAlreadyCalledDebug_CC", "_call_1", "_call_2") | |
| 528 else: | |
| 529 self.fail("second callback failed to raise AlreadyCalledError") | |
| 530 | |
| 531 def testAlreadyCalledDebug_CE(self): | |
| 532 d = defer.Deferred() | |
| 533 d.addCallbacks(self._callback, self._errback) | |
| 534 self._call_1(d) | |
| 535 try: | |
| 536 self._err_2(d) | |
| 537 except defer.AlreadyCalledError, e: | |
| 538 self._check(e, "testAlreadyCalledDebug_CE", "_call_1", "_err_2") | |
| 539 else: | |
| 540 self.fail("second errback failed to raise AlreadyCalledError") | |
| 541 | |
| 542 def testAlreadyCalledDebug_EC(self): | |
| 543 d = defer.Deferred() | |
| 544 d.addCallbacks(self._callback, self._errback) | |
| 545 self._err_1(d) | |
| 546 try: | |
| 547 self._call_2(d) | |
| 548 except defer.AlreadyCalledError, e: | |
| 549 self._check(e, "testAlreadyCalledDebug_EC", "_err_1", "_call_2") | |
| 550 else: | |
| 551 self.fail("second callback failed to raise AlreadyCalledError") | |
| 552 | |
| 553 def testAlreadyCalledDebug_EE(self): | |
| 554 d = defer.Deferred() | |
| 555 d.addCallbacks(self._callback, self._errback) | |
| 556 self._err_1(d) | |
| 557 try: | |
| 558 self._err_2(d) | |
| 559 except defer.AlreadyCalledError, e: | |
| 560 self._check(e, "testAlreadyCalledDebug_EE", "_err_1", "_err_2") | |
| 561 else: | |
| 562 self.fail("second errback failed to raise AlreadyCalledError") | |
| 563 | |
| 564 def testNoDebugging(self): | |
| 565 defer.setDebugging(False) | |
| 566 d = defer.Deferred() | |
| 567 d.addCallbacks(self._callback, self._errback) | |
| 568 self._call_1(d) | |
| 569 try: | |
| 570 self._call_2(d) | |
| 571 except defer.AlreadyCalledError, e: | |
| 572 self.failIf(e.args) | |
| 573 else: | |
| 574 self.fail("second callback failed to raise AlreadyCalledError") | |
| 575 | |
| 576 | |
| 577 def testSwitchDebugging(self): | |
| 578 # Make sure Deferreds can deal with debug state flipping | |
| 579 # around randomly. This is covering a particular fixed bug. | |
| 580 defer.setDebugging(False) | |
| 581 d = defer.Deferred() | |
| 582 d.addBoth(lambda ign: None) | |
| 583 defer.setDebugging(True) | |
| 584 d.callback(None) | |
| 585 | |
| 586 defer.setDebugging(False) | |
| 587 d = defer.Deferred() | |
| 588 d.callback(None) | |
| 589 defer.setDebugging(True) | |
| 590 d.addBoth(lambda ign: None) | |
| 591 | |
| 592 | |
| 593 | |
| 594 class LogTestCase(unittest.TestCase): | |
| 595 """ | |
| 596 Test logging of unhandled errors. | |
| 597 """ | |
| 598 | |
| 599 def setUp(self): | |
| 600 """ | |
| 601 Add a custom observer to observer logging. | |
| 602 """ | |
| 603 self.c = [] | |
| 604 log.addObserver(self.c.append) | |
| 605 | |
| 606 def tearDown(self): | |
| 607 """ | |
| 608 Remove the observer. | |
| 609 """ | |
| 610 log.removeObserver(self.c.append) | |
| 611 | |
| 612 def _check(self): | |
| 613 """ | |
| 614 Check the output of the log observer to see if the error is present. | |
| 615 """ | |
| 616 c2 = [e for e in self.c if e["isError"]] | |
| 617 self.assertEquals(len(c2), 2) | |
| 618 c2[1]["failure"].trap(ZeroDivisionError) | |
| 619 self.flushLoggedErrors(ZeroDivisionError) | |
| 620 | |
| 621 def test_errorLog(self): | |
| 622 """ | |
| 623 Verify that when a Deferred with no references to it is fired, and its | |
| 624 final result (the one not handled by any callback) is an exception, | |
| 625 that exception will be logged immediately. | |
| 626 """ | |
| 627 defer.Deferred().addCallback(lambda x: 1/0).callback(1) | |
| 628 self._check() | |
| 629 | |
| 630 def test_errorLogWithInnerFrameRef(self): | |
| 631 """ | |
| 632 Same as L{test_errorLog}, but with an inner frame. | |
| 633 """ | |
| 634 def _subErrorLogWithInnerFrameRef(): | |
| 635 d = defer.Deferred() | |
| 636 d.addCallback(lambda x: 1/0) | |
| 637 d.callback(1) | |
| 638 | |
| 639 _subErrorLogWithInnerFrameRef() | |
| 640 gc.collect() | |
| 641 self._check() | |
| 642 | |
| 643 def test_errorLogWithInnerFrameCycle(self): | |
| 644 """ | |
| 645 Same as L{test_errorLogWithInnerFrameRef}, plus create a cycle. | |
| 646 """ | |
| 647 def _subErrorLogWithInnerFrameCycle(): | |
| 648 d = defer.Deferred() | |
| 649 d.addCallback(lambda x, d=d: 1/0) | |
| 650 d._d = d | |
| 651 d.callback(1) | |
| 652 | |
| 653 _subErrorLogWithInnerFrameCycle() | |
| 654 gc.collect() | |
| 655 self._check() | |
| 656 | |
| 657 | |
| 658 class DeferredTestCaseII(unittest.TestCase): | |
| 659 def setUp(self): | |
| 660 self.callbackRan = 0 | |
| 661 | |
| 662 def testDeferredListEmpty(self): | |
| 663 """Testing empty DeferredList.""" | |
| 664 dl = defer.DeferredList([]) | |
| 665 dl.addCallback(self.cb_empty) | |
| 666 | |
| 667 def cb_empty(self, res): | |
| 668 self.callbackRan = 1 | |
| 669 self.failUnlessEqual([], res) | |
| 670 | |
| 671 def tearDown(self): | |
| 672 self.failUnless(self.callbackRan, "Callback was never run.") | |
| 673 | |
| 674 class OtherPrimitives(unittest.TestCase): | |
| 675 def _incr(self, result): | |
| 676 self.counter += 1 | |
| 677 | |
| 678 def setUp(self): | |
| 679 self.counter = 0 | |
| 680 | |
| 681 def testLock(self): | |
| 682 lock = defer.DeferredLock() | |
| 683 lock.acquire().addCallback(self._incr) | |
| 684 self.failUnless(lock.locked) | |
| 685 self.assertEquals(self.counter, 1) | |
| 686 | |
| 687 lock.acquire().addCallback(self._incr) | |
| 688 self.failUnless(lock.locked) | |
| 689 self.assertEquals(self.counter, 1) | |
| 690 | |
| 691 lock.release() | |
| 692 self.failUnless(lock.locked) | |
| 693 self.assertEquals(self.counter, 2) | |
| 694 | |
| 695 lock.release() | |
| 696 self.failIf(lock.locked) | |
| 697 self.assertEquals(self.counter, 2) | |
| 698 | |
| 699 self.assertRaises(TypeError, lock.run) | |
| 700 | |
| 701 firstUnique = object() | |
| 702 secondUnique = object() | |
| 703 | |
| 704 controlDeferred = defer.Deferred() | |
| 705 def helper(self, b): | |
| 706 self.b = b | |
| 707 return controlDeferred | |
| 708 | |
| 709 resultDeferred = lock.run(helper, self=self, b=firstUnique) | |
| 710 self.failUnless(lock.locked) | |
| 711 self.assertEquals(self.b, firstUnique) | |
| 712 | |
| 713 resultDeferred.addCallback(lambda x: setattr(self, 'result', x)) | |
| 714 | |
| 715 lock.acquire().addCallback(self._incr) | |
| 716 self.failUnless(lock.locked) | |
| 717 self.assertEquals(self.counter, 2) | |
| 718 | |
| 719 controlDeferred.callback(secondUnique) | |
| 720 self.assertEquals(self.result, secondUnique) | |
| 721 self.failUnless(lock.locked) | |
| 722 self.assertEquals(self.counter, 3) | |
| 723 | |
| 724 lock.release() | |
| 725 self.failIf(lock.locked) | |
| 726 | |
| 727 def testSemaphore(self): | |
| 728 N = 13 | |
| 729 sem = defer.DeferredSemaphore(N) | |
| 730 | |
| 731 controlDeferred = defer.Deferred() | |
| 732 def helper(self, arg): | |
| 733 self.arg = arg | |
| 734 return controlDeferred | |
| 735 | |
| 736 results = [] | |
| 737 uniqueObject = object() | |
| 738 resultDeferred = sem.run(helper, self=self, arg=uniqueObject) | |
| 739 resultDeferred.addCallback(results.append) | |
| 740 resultDeferred.addCallback(self._incr) | |
| 741 self.assertEquals(results, []) | |
| 742 self.assertEquals(self.arg, uniqueObject) | |
| 743 controlDeferred.callback(None) | |
| 744 self.assertEquals(results.pop(), None) | |
| 745 self.assertEquals(self.counter, 1) | |
| 746 | |
| 747 self.counter = 0 | |
| 748 for i in range(1, 1 + N): | |
| 749 sem.acquire().addCallback(self._incr) | |
| 750 self.assertEquals(self.counter, i) | |
| 751 | |
| 752 sem.acquire().addCallback(self._incr) | |
| 753 self.assertEquals(self.counter, N) | |
| 754 | |
| 755 sem.release() | |
| 756 self.assertEquals(self.counter, N + 1) | |
| 757 | |
| 758 for i in range(1, 1 + N): | |
| 759 sem.release() | |
| 760 self.assertEquals(self.counter, N + 1) | |
| 761 | |
| 762 def testQueue(self): | |
| 763 N, M = 2, 2 | |
| 764 queue = defer.DeferredQueue(N, M) | |
| 765 | |
| 766 gotten = [] | |
| 767 | |
| 768 for i in range(M): | |
| 769 queue.get().addCallback(gotten.append) | |
| 770 self.assertRaises(defer.QueueUnderflow, queue.get) | |
| 771 | |
| 772 for i in range(M): | |
| 773 queue.put(i) | |
| 774 self.assertEquals(gotten, range(i + 1)) | |
| 775 for i in range(N): | |
| 776 queue.put(N + i) | |
| 777 self.assertEquals(gotten, range(M)) | |
| 778 self.assertRaises(defer.QueueOverflow, queue.put, None) | |
| 779 | |
| 780 gotten = [] | |
| 781 for i in range(N): | |
| 782 queue.get().addCallback(gotten.append) | |
| 783 self.assertEquals(gotten, range(N, N + i + 1)) | |
| 784 | |
| 785 queue = defer.DeferredQueue() | |
| 786 gotten = [] | |
| 787 for i in range(N): | |
| 788 queue.get().addCallback(gotten.append) | |
| 789 for i in range(N): | |
| 790 queue.put(i) | |
| 791 self.assertEquals(gotten, range(N)) | |
| 792 | |
| 793 queue = defer.DeferredQueue(size=0) | |
| 794 self.assertRaises(defer.QueueOverflow, queue.put, None) | |
| 795 | |
| 796 queue = defer.DeferredQueue(backlog=0) | |
| 797 self.assertRaises(defer.QueueUnderflow, queue.get) | |
| 798 | |
| 799 | |
| 800 | |
| 801 class DeferredFilesystemLockTestCase(unittest.TestCase): | |
| 802 """ | |
| 803 Test the behavior of L{DeferredFilesystemLock} | |
| 804 """ | |
| 805 def setUp(self): | |
| 806 self.clock = Clock() | |
| 807 self.lock = defer.DeferredFilesystemLock(self.mktemp(), | |
| 808 scheduler=self.clock) | |
| 809 | |
| 810 | |
| 811 def test_waitUntilLockedWithNoLock(self): | |
| 812 """ | |
| 813 Test that the lock can be acquired when no lock is held | |
| 814 """ | |
| 815 d = self.lock.deferUntilLocked(timeout=1) | |
| 816 | |
| 817 return d | |
| 818 | |
| 819 | |
| 820 def test_waitUntilLockedWithTimeoutLocked(self): | |
| 821 """ | |
| 822 Test that the lock can not be acquired when the lock is held | |
| 823 for longer than the timeout. | |
| 824 """ | |
| 825 self.failUnless(self.lock.lock()) | |
| 826 | |
| 827 d = self.lock.deferUntilLocked(timeout=5.5) | |
| 828 self.assertFailure(d, defer.TimeoutError) | |
| 829 | |
| 830 self.clock.pump([1]*10) | |
| 831 | |
| 832 return d | |
| 833 | |
| 834 | |
| 835 def test_waitUntilLockedWithTimeoutUnlocked(self): | |
| 836 """ | |
| 837 Test that a lock can be acquired while a lock is held | |
| 838 but the lock is unlocked before our timeout. | |
| 839 """ | |
| 840 def onTimeout(f): | |
| 841 f.trap(defer.TimeoutError) | |
| 842 self.fail("Should not have timed out") | |
| 843 | |
| 844 self.failUnless(self.lock.lock()) | |
| 845 | |
| 846 self.clock.callLater(1, self.lock.unlock) | |
| 847 d = self.lock.deferUntilLocked(timeout=10) | |
| 848 d.addErrback(onTimeout) | |
| 849 | |
| 850 self.clock.pump([1]*10) | |
| 851 | |
| 852 return d | |
| 853 | |
| 854 | |
| 855 def test_defaultScheduler(self): | |
| 856 """ | |
| 857 Test that the default scheduler is set up properly. | |
| 858 """ | |
| 859 lock = defer.DeferredFilesystemLock(self.mktemp()) | |
| 860 | |
| 861 self.assertEquals(lock._scheduler, reactor) | |
| 862 | |
| 863 | |
| 864 def test_concurrentUsage(self): | |
| 865 """ | |
| 866 Test that an appropriate exception is raised when attempting | |
| 867 to use deferUntilLocked concurrently. | |
| 868 """ | |
| 869 self.lock.lock() | |
| 870 self.clock.callLater(1, self.lock.unlock) | |
| 871 | |
| 872 d = self.lock.deferUntilLocked() | |
| 873 d2 = self.lock.deferUntilLocked() | |
| 874 | |
| 875 self.assertFailure(d2, defer.AlreadyTryingToLockError) | |
| 876 | |
| 877 self.clock.advance(1) | |
| 878 | |
| 879 return d | |
| 880 | |
| 881 | |
| 882 def test_multipleUsages(self): | |
| 883 """ | |
| 884 Test that a DeferredFilesystemLock can be used multiple times | |
| 885 """ | |
| 886 def lockAquired(ign): | |
| 887 self.lock.unlock() | |
| 888 d = self.lock.deferUntilLocked() | |
| 889 return d | |
| 890 | |
| 891 self.lock.lock() | |
| 892 self.clock.callLater(1, self.lock.unlock) | |
| 893 | |
| 894 d = self.lock.deferUntilLocked() | |
| 895 d.addCallback(lockAquired) | |
| 896 | |
| 897 self.clock.advance(1) | |
| 898 | |
| 899 return d | |
| OLD | NEW |