~landscape/zope3/newer-from-ztk

« back to all changes in this revision

Viewing changes to src/twisted/test/test_task.py

  • Committer: Thomas Hervé
  • Date: 2009-07-08 13:52:04 UTC
  • Revision ID: thomas@canonical.com-20090708135204-df5eesrthifpylf8
Remove twisted copy

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
2
 
# See LICENSE for details.
3
 
 
4
 
from twisted.trial import unittest
5
 
 
6
 
from twisted.internet import interfaces, task, reactor, defer, error
7
 
 
8
 
# Be compatible with any jerks who used our private stuff
9
 
Clock = task.Clock
10
 
 
11
 
from twisted.python import failure
12
 
 
13
 
class TestableLoopingCall(task.LoopingCall):
14
 
    def __init__(self, clock, *a, **kw):
15
 
        super(TestableLoopingCall, self).__init__(*a, **kw)
16
 
        self._callLater = lambda delay: clock.callLater(delay, self)
17
 
        self._seconds = clock.seconds
18
 
 
19
 
 
20
 
 
21
 
class TestException(Exception):
22
 
    pass
23
 
 
24
 
 
25
 
 
26
 
class ClockTestCase(unittest.TestCase):
27
 
    """
28
 
    Test the non-wallclock based clock implementation.
29
 
    """
30
 
    def testSeconds(self):
31
 
        """
32
 
        Test that the L{seconds} method of the fake clock returns fake time.
33
 
        """
34
 
        c = task.Clock()
35
 
        self.assertEquals(c.seconds(), 0)
36
 
 
37
 
 
38
 
    def testCallLater(self):
39
 
        """
40
 
        Test that calls can be scheduled for later with the fake clock and
41
 
        hands back an L{IDelayedCall}.
42
 
        """
43
 
        c = task.Clock()
44
 
        call = c.callLater(1, lambda a, b: None, 1, b=2)
45
 
        self.failUnless(interfaces.IDelayedCall.providedBy(call))
46
 
        self.assertEquals(call.getTime(), 1)
47
 
        self.failUnless(call.active())
48
 
 
49
 
 
50
 
    def testCallLaterCancelled(self):
51
 
        """
52
 
        Test that calls can be cancelled.
53
 
        """
54
 
        c = task.Clock()
55
 
        call = c.callLater(1, lambda a, b: None, 1, b=2)
56
 
        call.cancel()
57
 
        self.failIf(call.active())
58
 
 
59
 
 
60
 
    def testAdvance(self):
61
 
        """
62
 
        Test that advancing the clock will fire some calls.
63
 
        """
64
 
        events = []
65
 
        c = task.Clock()
66
 
        call = c.callLater(2, lambda: events.append(None))
67
 
        c.advance(1)
68
 
        self.assertEquals(events, [])
69
 
        c.advance(1)
70
 
        self.assertEquals(events, [None])
71
 
        self.failIf(call.active())
72
 
 
73
 
 
74
 
    def testAdvanceCancel(self):
75
 
        """
76
 
        Test attemping to cancel the call in a callback.
77
 
 
78
 
        AlreadyCalled should be raised, not for example a ValueError from
79
 
        removing the call from Clock.calls. This requires call.called to be
80
 
        set before the callback is called.
81
 
        """
82
 
        c = task.Clock()
83
 
        def cb():
84
 
            self.assertRaises(error.AlreadyCalled, call.cancel)
85
 
        call = c.callLater(1, cb)
86
 
        c.advance(1)
87
 
 
88
 
 
89
 
    def testCallLaterDelayed(self):
90
 
        """
91
 
        Test that calls can be delayed.
92
 
        """
93
 
        events = []
94
 
        c = task.Clock()
95
 
        call = c.callLater(1, lambda a, b: events.append((a, b)), 1, b=2)
96
 
        call.delay(1)
97
 
        self.assertEquals(call.getTime(), 2)
98
 
        c.advance(1.5)
99
 
        self.assertEquals(events, [])
100
 
        c.advance(1.0)
101
 
        self.assertEquals(events, [(1, 2)])
102
 
 
103
 
 
104
 
    def testCallLaterResetLater(self):
105
 
        """
106
 
        Test that calls can have their time reset to a later time.
107
 
        """
108
 
        events = []
109
 
        c = task.Clock()
110
 
        call = c.callLater(2, lambda a, b: events.append((a, b)), 1, b=2)
111
 
        c.advance(1)
112
 
        call.reset(3)
113
 
        self.assertEquals(call.getTime(), 4)
114
 
        c.advance(2)
115
 
        self.assertEquals(events, [])
116
 
        c.advance(1)
117
 
        self.assertEquals(events, [(1, 2)])
118
 
 
119
 
 
120
 
    def testCallLaterResetSooner(self):
121
 
        """
122
 
        Test that calls can have their time reset to an earlier time.
123
 
        """
124
 
        events = []
125
 
        c = task.Clock()
126
 
        call = c.callLater(4, lambda a, b: events.append((a, b)), 1, b=2)
127
 
        call.reset(3)
128
 
        self.assertEquals(call.getTime(), 3)
129
 
        c.advance(3)
130
 
        self.assertEquals(events, [(1, 2)])
131
 
 
132
 
 
133
 
 
134
 
class LoopTestCase(unittest.TestCase):
135
 
    def testBasicFunction(self):
136
 
        # Arrange to have time advanced enough so that our function is
137
 
        # called a few times.
138
 
        # Only need to go to 2.5 to get 3 calls, since the first call
139
 
        # happens before any time has elapsed.
140
 
        timings = [0.05, 0.1, 0.1]
141
 
 
142
 
        clock = task.Clock()
143
 
 
144
 
        L = []
145
 
        def foo(a, b, c=None, d=None):
146
 
            L.append((a, b, c, d))
147
 
 
148
 
        lc = TestableLoopingCall(clock, foo, "a", "b", d="d")
149
 
        D = lc.start(0.1)
150
 
 
151
 
        theResult = []
152
 
        def saveResult(result):
153
 
            theResult.append(result)
154
 
        D.addCallback(saveResult)
155
 
 
156
 
        clock.pump(timings)
157
 
 
158
 
        self.assertEquals(len(L), 3,
159
 
                          "got %d iterations, not 3" % (len(L),))
160
 
 
161
 
        for (a, b, c, d) in L:
162
 
            self.assertEquals(a, "a")
163
 
            self.assertEquals(b, "b")
164
 
            self.assertEquals(c, None)
165
 
            self.assertEquals(d, "d")
166
 
 
167
 
        lc.stop()
168
 
        self.assertIdentical(theResult[0], lc)
169
 
 
170
 
        # Make sure it isn't planning to do anything further.
171
 
        self.failIf(clock.calls)
172
 
 
173
 
 
174
 
    def testDelayedStart(self):
175
 
        timings = [0.05, 0.1, 0.1]
176
 
 
177
 
        clock = task.Clock()
178
 
 
179
 
        L = []
180
 
        lc = TestableLoopingCall(clock, L.append, None)
181
 
        d = lc.start(0.1, now=False)
182
 
        
183
 
        theResult = []
184
 
        def saveResult(result):
185
 
            theResult.append(result)
186
 
        d.addCallback(saveResult)
187
 
 
188
 
        clock.pump(timings)
189
 
 
190
 
        self.assertEquals(len(L), 2,
191
 
                          "got %d iterations, not 2" % (len(L),))
192
 
        lc.stop()
193
 
        self.assertIdentical(theResult[0], lc)
194
 
 
195
 
        self.failIf(clock.calls)
196
 
 
197
 
 
198
 
    def testBadDelay(self):
199
 
        lc = task.LoopingCall(lambda: None)
200
 
        self.assertRaises(ValueError, lc.start, -1)
201
 
 
202
 
 
203
 
    # Make sure that LoopingCall.stop() prevents any subsequent calls.
204
 
    def _stoppingTest(self, delay):
205
 
        ran = []
206
 
        def foo():
207
 
            ran.append(None)
208
 
 
209
 
        clock = task.Clock()
210
 
        lc = TestableLoopingCall(clock, foo)
211
 
        d = lc.start(delay, now=False)
212
 
        lc.stop()
213
 
        self.failIf(ran)
214
 
        self.failIf(clock.calls)
215
 
 
216
 
 
217
 
    def testStopAtOnce(self):
218
 
        return self._stoppingTest(0)
219
 
 
220
 
 
221
 
    def testStoppingBeforeDelayedStart(self):
222
 
        return self._stoppingTest(10)
223
 
 
224
 
 
225
 
 
226
 
class ReactorLoopTestCase(unittest.TestCase):
227
 
    # Slightly inferior tests which exercise interactions with an actual
228
 
    # reactor.
229
 
    def testFailure(self):
230
 
        def foo(x):
231
 
            raise TestException(x)
232
 
 
233
 
        lc = task.LoopingCall(foo, "bar")
234
 
        return self.assertFailure(lc.start(0.1), TestException)
235
 
 
236
 
 
237
 
    def testFailAndStop(self):
238
 
        def foo(x):
239
 
            lc.stop()
240
 
            raise TestException(x)
241
 
 
242
 
        lc = task.LoopingCall(foo, "bar")
243
 
        return self.assertFailure(lc.start(0.1), TestException)
244
 
 
245
 
 
246
 
    def testEveryIteration(self):
247
 
        ran = []
248
 
 
249
 
        def foo():
250
 
            ran.append(None)
251
 
            if len(ran) > 5:
252
 
                lc.stop()
253
 
 
254
 
        lc = task.LoopingCall(foo)
255
 
        d = lc.start(0)
256
 
        def stopped(ign):
257
 
            self.assertEquals(len(ran), 6)
258
 
        return d.addCallback(stopped)
259
 
 
260
 
 
261
 
    def testStopAtOnceLater(self):
262
 
        # Ensure that even when LoopingCall.stop() is called from a
263
 
        # reactor callback, it still prevents any subsequent calls.
264
 
        d = defer.Deferred()
265
 
        def foo():
266
 
            d.errback(failure.DefaultException(
267
 
                "This task also should never get called."))
268
 
        self._lc = task.LoopingCall(foo)
269
 
        self._lc.start(1, now=False)
270
 
        reactor.callLater(0, self._callback_for_testStopAtOnceLater, d)
271
 
        return d
272
 
 
273
 
 
274
 
    def _callback_for_testStopAtOnceLater(self, d):
275
 
        self._lc.stop()
276
 
        reactor.callLater(0, d.callback, "success")
277
 
 
278
 
    def testWaitDeferred(self):
279
 
        # Tests if the callable isn't scheduled again before the returned
280
 
        # deferred has fired.
281
 
        timings = [0.2, 0.8]
282
 
        clock = task.Clock()
283
 
 
284
 
        def foo():
285
 
            d = defer.Deferred()
286
 
            d.addCallback(lambda _: lc.stop())
287
 
            clock.callLater(1, d.callback, None)
288
 
            return d
289
 
 
290
 
        lc = TestableLoopingCall(clock, foo)
291
 
        d = lc.start(0.2)
292
 
        clock.pump(timings)
293
 
        self.failIf(clock.calls)
294
 
 
295
 
    def testFailurePropagation(self):
296
 
        # Tests if the failure of the errback of the deferred returned by the
297
 
        # callable is propagated to the lc errback.
298
 
        #
299
 
        # To make sure this test does not hang trial when LoopingCall does not
300
 
        # wait for the callable's deferred, it also checks there are no
301
 
        # calls in the clock's callLater queue.
302
 
        timings = [0.3]
303
 
        clock = task.Clock()
304
 
 
305
 
        def foo():
306
 
            d = defer.Deferred()
307
 
            clock.callLater(0.3, d.errback, TestException())
308
 
            return d
309
 
 
310
 
        lc = TestableLoopingCall(clock, foo)
311
 
        d = lc.start(1)
312
 
        self.assertFailure(d, TestException)
313
 
 
314
 
        clock.pump(timings)
315
 
        self.failIf(clock.calls)
316
 
        return d