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 |