Ticket #990: ddiff

File ddiff, 25.7 KB (added by terrycojones, 4 years ago)

cancelation-changes-from-pycon-2010

Line 
1=== modified file 'twisted/internet/defer.py'
2--- twisted/internet/defer.py   2010-02-21 23:19:24 +0000
3+++ twisted/internet/defer.py   2010-02-22 20:23:28 +0000
4@@ -180,8 +180,8 @@
5     For more information about Deferreds, see doc/howto/defer.html or
6     U{http://twistedmatrix.com/projects/core/documentation/howto/defer.html}
7 
8-    When creating a Deferred, you should provide a canceller function, which
9-    will be called by d.cancel() to let you do any cleanup necessary if the
10+    When creating a Deferred, you may provide a canceller function, which
11+    will be called by d.cancel() to let you do any clean-up necessary if the
12     user decides not to wait for the deferred to complete.
13     """
14 
15@@ -204,20 +204,25 @@
16         """
17         Initialize a L{Deferred}.
18 
19-        @param canceller: an object to call in order to stop the pending
20-            operation scheduled by this L{Deferred} when L{Deferred.cancel} is
21-            invoked.  If this callable does not invoke its argument's
22-            C{callback} or C{errback} method when it is called,
23-            L{Deferred.cancel} will invoke L{Deferred.errback} on its behalf.
24-            Note that if this is not supplied, C{callback} or C{errback} may
25-            still be invoked once, even if the default behavior of C{cancel}
26-            invokes C{errback} on your behalf.  This is to allow the clients of
27-            code which returns a Deferred to to cancel it without the
28-            instantiator providing any specific implementation support for
29-            cancellation.  New in 10.0.
30-
31-        @type canceller: a 1-argument callable which takes a L{Deferred} and
32-            returns C{None}
33+        @param canceller: a callable used to stop the pending operation
34+            scheduled by this L{Deferred} when L{Deferred.cancel} is
35+            invoked. The canceller will be passed the deferred whose
36+            cancelation is requested (i.e., self).
37+           
38+            If a canceller is not given, or does not invoke its argument's
39+            C{callback} or C{errback} method, L{Deferred.cancel} will
40+            invoke L{Deferred.errback} with a L{CancelledError}.
41+
42+            Note that if a canceller is not given, C{callback} or
43+            C{errback} may still be invoked exactly once, even though
44+            defer.py will have already invoked C{errback}, as described
45+            above.  This allows clients of code which returns a L{Deferred}
46+            to cancel it without requiring the L{Deferred} instantiator to
47+            provide any specific implementation support for cancellation.
48+            New in 10.0.
49+
50+        @type canceller: a 1-argument callable which takes a L{Deferred}. The
51+            return result is ignored.
52         """
53         self.callbacks = []
54         self._canceller = canceller
55@@ -360,38 +365,29 @@
56         """
57         Cancel this L{Deferred}.
58 
59-        If this L{Deferred} is waiting on another L{Deferred}, forward the
60-        cancellation to the other L{Deferred}.
61-
62         If the L{Deferred} has not yet had its C{errback} or C{callback} method
63         invoked, call the canceller function provided to the constructor. If
64         that function does not invoke C{callback} or C{errback}, or if no
65         canceller function was provided, errback with L{CancelledError}.
66 
67-        @raise AlreadyCalledError: if the L{Deferred} has previously had its
68-            C{callback} or C{errback} method invoked.
69+        If this L{Deferred} is waiting on another L{Deferred}, forward the
70+        cancellation to the other L{Deferred}.
71         """
72-        canceller = self._canceller
73         if not self.called:
74+            canceller = self._canceller
75             if canceller:
76                 canceller(self)
77             else:
78-                # Eat the callback that will eventually be fired
79+                # Arrange to eat the callback that will eventually be fired
80                 # since there was no real canceller.
81                 self._suppressAlreadyCalled = 1
82-
83             if not self.called:
84-                # The canceller didn't do an errback of its own
85-                try:
86-                    raise CancelledError()
87-                except:
88-                    self.errback(failure.Failure())
89+                # There was no canceller, or the canceller didn't call
90+                # callback or errback.
91+                self.errback(failure.Failure(CancelledError()))
92         elif isinstance(self.result, Deferred):
93-            # Waiting for another deferred -- cancel it instead
94+            # Waiting for another deferred -- cancel it instead.
95             self.result.cancel()
96-        else:
97-            # Called and not waiting for another deferred
98-            raise AlreadyCalledError()
99 
100 
101     def _continue(self, result):
102@@ -400,9 +396,6 @@
103 
104 
105     def _startRunCallbacks(self, result):
106-        # Canceller is no longer relevant
107-        self.canceller = None
108-
109         if self.called:
110             if self._suppressAlreadyCalled:
111                 self._suppressAlreadyCalled = 0
112@@ -1078,6 +1071,17 @@
113 
114 
115     def _cancelAcquire(self, d):
116+        """
117+        Remove a deferred d from our waiting list, as the deferred has been
118+        canceled.
119+       
120+        Note: We do not need to wrap this in a try/except to catch d not
121+        being in self.waiting because this canceller will not be called if
122+        d has fired. release() pops a deferred out of self.waiting and
123+        calls it, so the canceller will no longer be called.
124+
125+        @param d: The deferred that has been canceled.
126+        """
127         self.waiting.remove(d)
128 
129 
130@@ -1130,6 +1134,17 @@
131 
132 
133     def _cancelAcquire(self, d):
134+        """
135+        Remove a deferred d from our waiting list, as the deferred has been
136+        canceled.
137+       
138+        Note: We do not need to wrap this in a try/except to catch d not
139+        being in self.waiting because this canceller will not be called if
140+        d has fired. release() pops a deferred out of self.waiting and
141+        calls it, so the canceller will no longer be called.
142+
143+        @param d: The deferred that has been canceled.
144+        """
145         self.waiting.remove(d)
146 
147 
148@@ -1202,6 +1217,17 @@
149 
150 
151     def _cancelGet(self, d):
152+        """
153+        Remove a deferred d from our waiting list, as the deferred has been
154+        canceled.
155+       
156+        Note: We do not need to wrap this in a try/except to catch d not
157+        being in self.waiting because this canceller will not be called if
158+        d has fired. put() pops a deferred out of self.waiting and calls
159+        it, so the canceller will no longer be called.
160+
161+        @param d: The deferred that has been canceled.
162+        """
163         self.waiting.remove(d)
164 
165 
166
167=== modified file 'twisted/test/test_defer.py'
168--- twisted/test/test_defer.py  2010-02-21 21:13:51 +0000
169+++ twisted/test/test_defer.py  2010-02-22 20:28:00 +0000
170@@ -28,40 +28,40 @@
171 class DeferredTestCase(unittest.TestCase):
172 
173     def setUp(self):
174-        self.callback_results = None
175-        self.errback_results = None
176-        self.callback2_results = None
177+        self.callbackResults = None
178+        self.errbackResults = None
179+        self.callback2Results = None
180 
181     def _callback(self, *args, **kw):
182-        self.callback_results = args, kw
183+        self.callbackResults = args, kw
184         return args[0]
185 
186     def _callback2(self, *args, **kw):
187-        self.callback2_results = args, kw
188+        self.callback2Results = args, kw
189 
190     def _errback(self, *args, **kw):
191-        self.errback_results = args, kw
192+        self.errbackResults = args, kw
193 
194     def testCallbackWithoutArgs(self):
195         deferred = defer.Deferred()
196         deferred.addCallback(self._callback)
197         deferred.callback("hello")
198-        self.failUnlessEqual(self.errback_results, None)
199-        self.failUnlessEqual(self.callback_results, (('hello',), {}))
200+        self.failUnlessEqual(self.errbackResults, None)
201+        self.failUnlessEqual(self.callbackResults, (('hello',), {}))
202 
203     def testCallbackWithArgs(self):
204         deferred = defer.Deferred()
205         deferred.addCallback(self._callback, "world")
206         deferred.callback("hello")
207-        self.failUnlessEqual(self.errback_results, None)
208-        self.failUnlessEqual(self.callback_results, (('hello', 'world'), {}))
209+        self.failUnlessEqual(self.errbackResults, None)
210+        self.failUnlessEqual(self.callbackResults, (('hello', 'world'), {}))
211 
212     def testCallbackWithKwArgs(self):
213         deferred = defer.Deferred()
214         deferred.addCallback(self._callback, world="world")
215         deferred.callback("hello")
216-        self.failUnlessEqual(self.errback_results, None)
217-        self.failUnlessEqual(self.callback_results,
218+        self.failUnlessEqual(self.errbackResults, None)
219+        self.failUnlessEqual(self.callbackResults,
220                              (('hello',), {'world': 'world'}))
221 
222     def testTwoCallbacks(self):
223@@ -69,10 +69,10 @@
224         deferred.addCallback(self._callback)
225         deferred.addCallback(self._callback2)
226         deferred.callback("hello")
227-        self.failUnlessEqual(self.errback_results, None)
228-        self.failUnlessEqual(self.callback_results,
229+        self.failUnlessEqual(self.errbackResults, None)
230+        self.failUnlessEqual(self.callbackResults,
231                              (('hello',), {}))
232-        self.failUnlessEqual(self.callback2_results,
233+        self.failUnlessEqual(self.callback2Results,
234                              (('hello',), {}))
235 
236     def testDeferredList(self):
237@@ -295,11 +295,11 @@
238         d.addCallback(lambda r, d2=d2: d2)
239         d.addCallback(self._callback)
240         d.callback(1)
241-        assert self.callback_results is None, "Should not have been called yet."
242+        assert self.callbackResults is None, "Should not have been called yet."
243         d2.callback(2)
244-        assert self.callback_results is None, "Still should not have been called yet."
245+        assert self.callbackResults is None, "Still should not have been called yet."
246         d2.unpause()
247-        assert self.callback_results[0][0] == 2, "Result should have been from second deferred:%s"% (self.callback_results,)
248+        assert self.callbackResults[0][0] == 2, "Result should have been from second deferred:%s"% (self.callbackResults,)
249 
250     def testGatherResults(self):
251         # test successful list of deferreds
252@@ -640,98 +640,253 @@
253         d.addBoth(lambda ign: None)
254 
255 
256-class FooError(Exception):
257-    pass
258 
259 class DeferredCancellerTest(unittest.TestCase):
260     def setUp(self):
261-        self.callback_results = None
262-        self.errback_results = None
263-        self.callback2_results = None
264-        self.cancellerCalled = False
265+        self.callbackResults = None
266+        self.errbackResults = None
267+        self.callback2Results = None
268+        self.cancellerCallCount = 0
269+
270+
271+    def tearDown(self):
272+        # Sanity check that the canceller was called at most once.
273+        self.assertTrue(self.cancellerCallCount in (0, 1))
274+
275 
276     def _callback(self, data):
277-        self.callback_results = data
278+        self.callbackResults = data
279         return data
280 
281+
282     def _callback2(self, data):
283-        self.callback2_results = data
284+        self.callback2Results = data
285+
286 
287     def _errback(self, data):
288-        self.errback_results = data
289+        self.errbackResults = data
290 
291 
292     def test_noCanceller(self):
293         """
294-        Verify that a Deferred without a canceller errbacks with defer.CancelledError.
295-        """
296-        d = defer.Deferred()
297-        d.addCallbacks(self._callback, self._errback)
298-        d.cancel()
299-        self.assertEquals(self.errback_results.type, defer.CancelledError)
300-
301-        # Test that further callbacks *are* swallowed
302-        d.callback(None)
303-
304-        # But that a second is not
305-        self.assertRaises(defer.AlreadyCalledError, d.callback, None)
306-
307-
308-    def test_canceller(self):
309-        """
310-        Verify that a Deferred calls its specified canceller when it is
311-        cancelled.
312-        """
313-        def cancel(d):
314-            self.cancellerCalled=True
315-
316-        d = defer.Deferred(canceller=cancel)
317-        d.addCallbacks(self._callback, self._errback)
318-        d.cancel()
319-        self.assertEquals(self.cancellerCalled, True)
320-        self.assertEquals(self.errback_results.type, defer.CancelledError)
321-
322-        # Test that further callbacks are *not* swallowed
323-        self.assertRaises(defer.AlreadyCalledError, d.callback, None)
324-
325-
326-    def test_cancellerWithCallback(self):
327-        """
328-        Verify that a canceller which invokes a (non-errback) callback will not
329-        get errbacked with L{CancelledError}
330-        """
331-        def cancel(d):
332-            self.cancellerCalled=True
333-            d.errback(FooError())
334-        d = defer.Deferred(canceller=cancel)
335-        d.addCallbacks(self._callback, self._errback)
336-        d.cancel()
337-        self.assertEquals(self.cancellerCalled, True)
338-        self.assertEquals(self.errback_results.type, FooError)
339-
340-
341-    def test_cancelAlreadyCalled(self):
342-        """
343-        Verify that cancelling a L{Deferred} twice will result in an
344-        L{AlreadyCalledError}.
345-        """
346-        def cancel(d):
347-            self.cancellerCalled=True
348-        d = defer.Deferred(canceller=cancel)
349-        d.callback(None)
350-        self.assertRaises(defer.AlreadyCalledError, d.cancel)
351-        self.assertEquals(self.cancellerCalled, False)
352+        A L{defer.Deferred} without a canceller must errback with a
353+        L{defer.CancelledError} and not callback.
354+        """
355+        d = defer.Deferred()
356+        d.addCallbacks(self._callback, self._errback)
357+        d.cancel()
358+        self.assertEquals(self.errbackResults.type, defer.CancelledError)
359+        self.assertEquals(self.callbackResults, None)
360+
361+
362+    def test_raisesAfterCancelAndCallback(self):
363+        """
364+        A L{defer.Deferred} without a canceller, when cancelled must allow
365+        a single extra call to callback, and raise
366+        L{defer.AlreadyCalledError} if callbacked or errbacked thereafter.
367+        """
368+        d = defer.Deferred()
369+        d.addCallbacks(self._callback, self._errback)
370+        d.cancel()
371+
372+        # A single extra callback should be swallowed.
373+        d.callback(None)
374+
375+        # But a second call to callback or errback is not.
376+        self.assertRaises(defer.AlreadyCalledError, d.callback, None)
377+        self.assertRaises(defer.AlreadyCalledError, d.errback, Exception())
378+
379+
380+    def test_raisesAfterCancelAndErrback(self):
381+        """
382+        A L{defer.Deferred} without a canceller, when cancelled must allow
383+        a single extra call to errback, and raise
384+        L{defer.AlreadyCalledError} if callbacked or errbacked thereafter.
385+        """
386+        d = defer.Deferred()
387+        d.addCallbacks(self._callback, self._errback)
388+        d.cancel()
389+
390+        # A single extra errback should be swallowed.
391+        d.errback(Exception())
392+
393+        # But a second call to callback or errback is not.
394+        self.assertRaises(defer.AlreadyCalledError, d.callback, None)
395+        self.assertRaises(defer.AlreadyCalledError, d.errback, Exception())
396+
397+
398+    def test_noCancellerMultipleCancelsAfterCancelAndCallback(self):
399+        """
400+        A L{Deferred} without a canceller, when cancelled and then
401+        callbacked, ignores multiple cancels thereafter.
402+        """
403+        d = defer.Deferred()
404+        d.addCallbacks(self._callback, self._errback)
405+        d.cancel()
406+        currentFailure = self.errbackResults
407+        # One callback will be ignored
408+        d.callback(None)
409+        # Cancel should have no effect.
410+        d.cancel()
411+        self.assertIdentical(currentFailure, self.errbackResults)
412+
413+
414+    def test_noCancellerMultipleCancelsAfterCancelAndErrback(self):
415+        """
416+        A L{defer.Deferred} without a canceller, when cancelled and then
417+        errbacked, ignores multiple cancels thereafter.
418+        """
419+        d = defer.Deferred()
420+        d.addCallbacks(self._callback, self._errback)
421+        d.cancel()
422+        self.assertEquals(self.errbackResults.type, defer.CancelledError)
423+        currentFailure = self.errbackResults
424+        # One errback will be ignored
425+        d.errback(GenericError())
426+        # I.e., we should still have a CancelledError.
427+        self.assertEquals(self.errbackResults.type, defer.CancelledError)
428+        d.cancel()
429+        self.assertIdentical(currentFailure, self.errbackResults)
430+
431+
432+    def test_noCancellerMultipleCancel(self):
433+        """
434+        Calling cancel multiple times on a deferred with no canceller
435+        results in a L{defer.CancelledError}. Subsequent calls to cancel
436+        do not cause an error.
437+        """
438+        d = defer.Deferred()
439+        d.addCallbacks(self._callback, self._errback)
440+        d.cancel()
441+        self.assertEquals(self.errbackResults.type, defer.CancelledError)
442+        currentFailure = self.errbackResults
443+        d.cancel()
444+        self.assertIdentical(currentFailure, self.errbackResults)
445+
446+
447+    def test_cancellerMultipleCancel(self):
448+        """
449+        Verify that calling cancel multiple times on a deferred with a
450+        canceller that does not errback results in a
451+        L{defer.CancelledError} and that subsequent calls to cancel do not
452+        cause an error and that after all that, the canceller was only
453+        called once.
454+        """
455+        def cancel(d):
456+            self.cancellerCallCount += 1
457+           
458+        d = defer.Deferred(canceller=cancel)
459+        d.addCallbacks(self._callback, self._errback)
460+        d.cancel()
461+        self.assertEquals(self.errbackResults.type, defer.CancelledError)
462+        currentFailure = self.errbackResults
463+        d.cancel()
464+        self.assertIdentical(currentFailure, self.errbackResults)
465+        self.assertEquals(self.cancellerCallCount, 1)
466+
467+
468+    def test_simpleCanceller(self):
469+        """
470+        Verify that a L{defer.Deferred} calls its specified canceller when
471+        it is cancelled, and that further call/errbacks raise
472+        L{defer.AlreadyCalledError}.
473+        """
474+        def cancel(d):
475+            self.cancellerCallCount += 1
476+
477+        d = defer.Deferred(canceller=cancel)
478+        d.addCallbacks(self._callback, self._errback)
479+        d.cancel()
480+        self.assertEquals(self.cancellerCallCount, 1)
481+        self.assertEquals(self.errbackResults.type, defer.CancelledError)
482+
483+        # Test that further call/errbacks are *not* swallowed
484+        self.assertRaises(defer.AlreadyCalledError, d.callback, None)
485+        self.assertRaises(defer.AlreadyCalledError, d.errback, Exception())
486+
487+
488+    def test_cancellerArg(self):
489+        """
490+        Verify that a canceller is given the correct deferred argument.
491+        """
492+        def cancel(d1):
493+            self.assertIdentical(d1, d)
494+        d = defer.Deferred(canceller=cancel)
495+        d.addCallbacks(self._callback, self._errback)
496+        d.cancel()
497+
498+
499+    def test_cancelAfterCallback(self):
500+        """
501+        Test that cancelling a deferred after it has been callbacked does
502+        not cause an error.
503+        """
504+        def cancel(d):
505+            self.cancellerCallCount += 1
506+            d.errback(GenericError())
507+        d = defer.Deferred(canceller=cancel)
508+        d.addCallbacks(self._callback, self._errback)
509+        d.callback('biff!')
510+        d.cancel()
511+        self.assertEquals(self.cancellerCallCount, 0)
512+        self.assertEquals(self.errbackResults, None)
513+        self.assertEquals(self.callbackResults, 'biff!')
514+
515+
516+    def test_cancelAfterErrback(self):
517+        """
518+        Test that cancelling a L{Deferred} after it has been errbacked does
519+        not result in a L{defer.CancelledError}.
520+        """
521+        def cancel(d):
522+            self.cancellerCallCount += 1
523+            d.errback(GenericError())
524+        d = defer.Deferred(canceller=cancel)
525+        d.addCallbacks(self._callback, self._errback)
526+        d.errback(GenericError())
527+        d.cancel()
528+        self.assertEquals(self.cancellerCallCount, 0)
529+        self.assertEquals(self.errbackResults.type, GenericError)
530+        self.assertEquals(self.callbackResults, None)
531+
532+
533+    def test_cancellerThatErrbacks(self):
534+        """
535+        Test a canceller which errbacks its deferred.
536+        """
537+        def cancel(d):
538+            self.cancellerCallCount += 1
539+            d.errback(GenericError())
540+        d = defer.Deferred(canceller=cancel)
541+        d.addCallbacks(self._callback, self._errback)
542+        d.cancel()
543+        self.assertEquals(self.cancellerCallCount, 1)
544+        self.assertEquals(self.errbackResults.type, GenericError)
545+
546+
547+    def test_cancellerThatCallbacks(self):
548+        """
549+        Test a canceller which calls its deferred.
550+        """
551+        def cancel(d):
552+            self.cancellerCallCount += 1
553+            d.callback('hello!')
554+        d = defer.Deferred(canceller=cancel)
555+        d.addCallbacks(self._callback, self._errback)
556+        d.cancel()
557+        self.assertEquals(self.cancellerCallCount, 1)
558+        self.assertEquals(self.callbackResults, 'hello!')
559+        self.assertEquals(self.errbackResults, None)
560 
561 
562     def test_cancelNestedDeferred(self):
563         """
564         Verify that a Deferred, A, which is waiting on another Deferred, B,
565-        returned from one of its callbacks, will propagate L{CancelledError}
566-        when B is cancelled.
567+        returned from one of its callbacks, will propagate
568+        L{defer.CancelledError} when A is cancelled.
569         """
570         def innerCancel(d):
571-            self.assertIdentical(d, B)
572-            self.cancellerCalled = True
573+            self.cancellerCallCount += 1
574         def cancel(d):
575             self.assert_(False)
576 
577@@ -741,8 +896,11 @@
578         A.addCallback(lambda data: B)
579         A.cancel()
580         A.addCallbacks(self._callback, self._errback)
581-        self.assertEquals(self.cancellerCalled, True)
582-        self.assertEquals(self.errback_results.type, defer.CancelledError)
583+        # The cancel count should be one (the cancellation done by B)
584+        self.assertEquals(self.cancellerCallCount, 1)
585+        # B's canceller didn't errback, so defer.py will have called errback
586+        # with a CancelledError.
587+        self.assertEquals(self.errbackResults.type, defer.CancelledError)
588 
589 
590 
591@@ -775,9 +933,9 @@
592 
593     def test_errorLog(self):
594         """
595-        Verify that when a Deferred with no references to it is fired, and its
596-        final result (the one not handled by any callback) is an exception,
597-        that exception will be logged immediately.
598+        Verify that when a L{Deferred} with no references to it is fired,
599+        and its final result (the one not handled by any callback) is an
600+        exception, that exception will be logged immediately.
601         """
602         defer.Deferred().addCallback(lambda x: 1/0).callback(1)
603         gc.collect()
604@@ -884,6 +1042,33 @@
605         lock.release()
606         self.failIf(lock.locked)
607 
608+
609+    def test_cancelLockAfterAcquired(self):
610+        """
611+        When canceling a L{Deferred] from a L{DeferredLock} that already
612+        has the lock, the cancel should have no effect.
613+        """
614+        def _failOnErrback(_):
615+            self.fail("Unexpected errback call!")
616+        lock = defer.DeferredLock()
617+        d = lock.acquire()
618+        d.addErrback(_failOnErrback)
619+        d.cancel()
620+
621+
622+    def test_cancelLockBeforeAcquired(self):
623+        """
624+        When canceling a L{Deferred] from a L{DeferredLock} that does not
625+        yet have the lock (i.e., the L{Deferred} has not fired), the cancel
626+        should cause a L{defer.CancelledError} failure.
627+        """
628+        lock = defer.DeferredLock()
629+        _ign = lock.acquire()
630+        d = lock.acquire()
631+        self.failUnlessFailure(d, defer.CancelledError)
632+        d.cancel()
633+
634+
635     def testSemaphore(self):
636         N = 13
637         sem = defer.DeferredSemaphore(N)
638@@ -929,6 +1114,35 @@
639             sem.release()
640             self.assertEquals(self.counter, N + 1)
641 
642+
643+    def test_cancelSemaphoreAfterAcquired(self):
644+        """
645+        When canceling a L{Deferred] from a L{DeferredSemaphore} that
646+        already has the semaphore, the cancel should have no effect.
647+        """
648+        def _failOnErrback(_):
649+            self.fail("Unexpected errback call!")
650+           
651+        sem = defer.DeferredSemaphore(1)
652+        d = sem.acquire()
653+        d.addErrback(_failOnErrback)
654+        d.cancel()
655+
656+
657+    def test_cancelSemaphoreBeforeAcquired(self):
658+        """
659+        When canceling a L{Deferred] from a L{DeferredSemaphore} that does
660+        not yet have the semaphore (i.e., the L{Deferred} has not fired),
661+        the cancel should cause a L{defer.CancelledError} failure.
662+        """
663+        sem = defer.DeferredSemaphore(1)
664+        _ign = sem.acquire()
665+        d = sem.acquire()
666+        self.failUnlessFailure(d, defer.CancelledError)
667+        d.cancel()
668+        return d
669+
670+
671     def testQueue(self):
672         N, M = 2, 2
673         queue = defer.DeferredQueue(N, M)
674@@ -967,6 +1181,34 @@
675         self.assertRaises(defer.QueueUnderflow, queue.get)
676 
677 
678+    def test_cancelQueueAfterSynchronousGet(self):
679+        """
680+        When canceling a L{Deferred] from a L{DeferredQueue} that already has
681+        a result, the cancel should have no effect.
682+        """
683+        def _failOnErrback(_):
684+            self.fail("Unexpected errback call!")
685+           
686+        queue = defer.DeferredQueue()
687+        d = queue.get()
688+        d.addErrback(_failOnErrback)
689+        queue.put(None)
690+        d.cancel()
691+   
692+
693+    def test_cancelQueueAfterGet(self):
694+        """
695+        When canceling a L{Deferred] from a L{DeferredQueue} that does not
696+        have a result (i.e., the L{Deferred} has not fired), the cancel
697+        should cause a L{defer.CancelledError} failure.
698+        """
699+        queue = defer.DeferredQueue()
700+        d = queue.get()
701+        self.failUnlessFailure(d, defer.CancelledError)
702+        d.cancel()
703+        return d
704+
705+
706 
707 class DeferredFilesystemLockTestCase(unittest.TestCase):
708     """
709