~divmod-dev/divmod.org/trunk

« back to all changes in this revision

Viewing changes to Epsilon/epsilon/test/test_react.py

  • Committer: Jean-Paul Calderone
  • Date: 2014-06-29 20:33:04 UTC
  • mfrom: (2749.1.1 remove-epsilon-1325289)
  • Revision ID: exarkun@twistedmatrix.com-20140629203304-gdkmbwl1suei4m97
mergeĀ lp:~exarkun/divmod.org/remove-epsilon-1325289

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (c) 2008 Divmod.  See LICENSE for details.
2
 
 
3
 
"""
4
 
Tests for L{epsilon.react}.
5
 
"""
6
 
 
7
 
from twisted.internet.defer import Deferred, succeed, fail
8
 
from twisted.internet.task import Clock
9
 
from twisted.trial.unittest import TestCase
10
 
 
11
 
from epsilon.react import react
12
 
 
13
 
 
14
 
class _FakeReactor(object):
15
 
    """
16
 
    A fake implementation of L{IReactorCore}.
17
 
    """
18
 
    def __init__(self):
19
 
        self._running = False
20
 
        self._clock = Clock()
21
 
        self.callLater = self._clock.callLater
22
 
        self.seconds = self._clock.seconds
23
 
        self.getDelayedCalls = self._clock.getDelayedCalls
24
 
        self._whenRunning = []
25
 
        self._shutdownTriggers = {'before': [], 'during': []}
26
 
 
27
 
 
28
 
    def callWhenRunning(self, callable):
29
 
        if self._running:
30
 
            callable()
31
 
        else:
32
 
            self._whenRunning.append(callable)
33
 
 
34
 
 
35
 
    def addSystemEventTrigger(self, phase, event, callable, *args):
36
 
        assert phase in ('before', 'during')
37
 
        assert event == 'shutdown'
38
 
        self._shutdownTriggers[phase].append((callable, args))
39
 
 
40
 
 
41
 
    def run(self):
42
 
        """
43
 
        Call timed events until there are no more or the reactor is stopped.
44
 
 
45
 
        @raise RuntimeError: When no timed events are left and the reactor is
46
 
            still running.
47
 
        """
48
 
        self._running = True
49
 
        whenRunning = self._whenRunning
50
 
        self._whenRunning = None
51
 
        for callable in whenRunning:
52
 
            callable()
53
 
        while self._running:
54
 
            calls = self.getDelayedCalls()
55
 
            if not calls:
56
 
                raise RuntimeError("No DelayedCalls left")
57
 
            self._clock.advance(calls[0].getTime() - self.seconds())
58
 
        shutdownTriggers = self._shutdownTriggers
59
 
        self._shutdownTriggers = None
60
 
        for (trigger, args) in shutdownTriggers['before'] + shutdownTriggers['during']:
61
 
            trigger(*args)
62
 
 
63
 
 
64
 
    def stop(self):
65
 
        """
66
 
        Stop the reactor.
67
 
        """
68
 
        self._running = False
69
 
 
70
 
 
71
 
 
72
 
class ReactTests(TestCase):
73
 
    """
74
 
    Tests for L{epsilon.react.react}.
75
 
    """
76
 
    def test_runsUntilAsyncCallback(self):
77
 
        """
78
 
        L{react} runs the reactor until the L{Deferred} returned by the
79
 
        function it is passed is called back, then stops it.
80
 
        """
81
 
        timePassed = []
82
 
        def main(reactor):
83
 
            finished = Deferred()
84
 
            reactor.callLater(1, timePassed.append, True)
85
 
            reactor.callLater(2, finished.callback, None)
86
 
            return finished
87
 
        r = _FakeReactor()
88
 
        react(r, main, [])
89
 
        self.assertEqual(timePassed, [True])
90
 
        self.assertEqual(r.seconds(), 2)
91
 
 
92
 
 
93
 
    def test_runsUntilSyncCallback(self):
94
 
        """
95
 
        L{react} returns quickly if the L{Deferred} returned by the function it
96
 
        is passed has already been called back at the time it is returned.
97
 
        """
98
 
        def main(reactor):
99
 
            return succeed(None)
100
 
        r = _FakeReactor()
101
 
        react(r, main, [])
102
 
        self.assertEqual(r.seconds(), 0)
103
 
 
104
 
 
105
 
    def test_runsUntilAsyncErrback(self):
106
 
        """
107
 
        L{react} runs the reactor until the L{Deferred} returned by the
108
 
        function it is passed is errbacked, then it stops the reactor and
109
 
        reports the error.
110
 
        """
111
 
        class ExpectedException(Exception):
112
 
            pass
113
 
 
114
 
        def main(reactor):
115
 
            finished = Deferred()
116
 
            reactor.callLater(1, finished.errback, ExpectedException())
117
 
            return finished
118
 
        r = _FakeReactor()
119
 
        react(r, main, [])
120
 
        errors = self.flushLoggedErrors(ExpectedException)
121
 
        self.assertEqual(len(errors), 1)
122
 
 
123
 
 
124
 
    def test_runsUntilSyncErrback(self):
125
 
        """
126
 
        L{react} returns quickly if the L{Deferred} returned by the function it
127
 
        is passed has already been errbacked at the time it is returned.
128
 
        """
129
 
        class ExpectedException(Exception):
130
 
            pass
131
 
 
132
 
        def main(reactor):
133
 
            return fail(ExpectedException())
134
 
        r = _FakeReactor()
135
 
        react(r, main, [])
136
 
        self.assertEqual(r.seconds(), 0)
137
 
        errors = self.flushLoggedErrors(ExpectedException)
138
 
        self.assertEqual(len(errors), 1)
139
 
 
140
 
 
141
 
    def test_singleStopCallback(self):
142
 
        """
143
 
        L{react} doesn't try to stop the reactor if the L{Deferred} the
144
 
        function it is passed is called back after the reactor has already been
145
 
        stopped.
146
 
        """
147
 
        def main(reactor):
148
 
            reactor.callLater(1, reactor.stop)
149
 
            finished = Deferred()
150
 
            reactor.addSystemEventTrigger(
151
 
                'during', 'shutdown', finished.callback, None)
152
 
            return finished
153
 
        r = _FakeReactor()
154
 
        react(r, main, [])
155
 
        self.assertEqual(r.seconds(), 1)
156
 
 
157
 
 
158
 
    def test_singleStopErrback(self):
159
 
        """
160
 
        L{react} doesn't try to stop the reactor if the L{Deferred} the
161
 
        function it is passed is errbacked after the reactor has already been
162
 
        stopped.
163
 
        """
164
 
        class ExpectedException(Exception):
165
 
            pass
166
 
 
167
 
        def main(reactor):
168
 
            reactor.callLater(1, reactor.stop)
169
 
            finished = Deferred()
170
 
            reactor.addSystemEventTrigger(
171
 
                'during', 'shutdown', finished.errback, ExpectedException())
172
 
            return finished
173
 
        r = _FakeReactor()
174
 
        react(r, main, [])
175
 
        self.assertEqual(r.seconds(), 1)
176
 
        errors = self.flushLoggedErrors(ExpectedException)
177
 
        self.assertEqual(len(errors), 1)
178
 
 
179
 
 
180
 
    def test_arguments(self):
181
 
        """
182
 
        L{react} passes the elements of the list it is passed as positional
183
 
        arguments to the function it is passed.
184
 
        """
185
 
        args = []
186
 
        def main(reactor, x, y, z):
187
 
            args.extend((x, y, z))
188
 
            return succeed(None)
189
 
        r = _FakeReactor()
190
 
        react(r, main, [1, 2, 3])
191
 
        self.assertEqual(args, [1, 2, 3])