Imported Upstream version 12.1.0
[contrib/python-twisted.git] / twisted / internet / test / test_core.py
1 # Copyright (c) Twisted Matrix Laboratories.
2 # See LICENSE for details.
3
4 """
5 Tests for implementations of L{IReactorCore}.
6 """
7
8 __metaclass__ = type
9
10 import signal
11 import time
12 import inspect
13
14 from twisted.internet.abstract import FileDescriptor
15 from twisted.internet.error import ReactorAlreadyRunning, ReactorNotRestartable
16 from twisted.internet.defer import Deferred
17 from twisted.internet.test.reactormixins import ReactorBuilder
18
19
20 class ObjectModelIntegrationMixin(object):
21     """
22     Helpers for tests about the object model of reactor-related objects.
23     """
24     def assertFullyNewStyle(self, instance):
25         """
26         Assert that the given object is an instance of a new-style class and
27         that there are no classic classes in the inheritance hierarchy of
28         that class.
29
30         This is a beneficial condition because PyPy is better able to
31         optimize attribute lookup on such classes.
32         """
33         self.assertIsInstance(instance, object)
34         mro = inspect.getmro(type(instance))
35         for subclass in mro:
36             self.assertTrue(
37                 issubclass(subclass, object),
38                 "%r is not new-style" % (subclass,))
39
40
41
42 class ObjectModelIntegrationTest(ReactorBuilder, ObjectModelIntegrationMixin):
43     """
44     Test details of object model integration against all reactors.
45     """
46
47     def test_newstyleReactor(self):
48         """
49         Checks that all reactors on a platform have method resolution order
50         containing only new style classes.
51         """
52         reactor = self.buildReactor()
53         self.assertFullyNewStyle(reactor)
54
55
56
57 class SystemEventTestsBuilder(ReactorBuilder):
58     """
59     Builder defining tests relating to L{IReactorCore.addSystemEventTrigger}
60     and L{IReactorCore.fireSystemEvent}.
61     """
62     def test_stopWhenNotStarted(self):
63         """
64         C{reactor.stop()} raises L{RuntimeError} when called when the reactor
65         has not been started.
66         """
67         reactor = self.buildReactor()
68         self.assertRaises(RuntimeError, reactor.stop)
69
70
71     def test_stopWhenAlreadyStopped(self):
72         """
73         C{reactor.stop()} raises L{RuntimeError} when called after the reactor
74         has been stopped.
75         """
76         reactor = self.buildReactor()
77         reactor.callWhenRunning(reactor.stop)
78         self.runReactor(reactor)
79         self.assertRaises(RuntimeError, reactor.stop)
80
81
82     def test_callWhenRunningOrder(self):
83         """
84         Functions are run in the order that they were passed to
85         L{reactor.callWhenRunning}.
86         """
87         reactor = self.buildReactor()
88         events = []
89         reactor.callWhenRunning(events.append, "first")
90         reactor.callWhenRunning(events.append, "second")
91         reactor.callWhenRunning(reactor.stop)
92         self.runReactor(reactor)
93         self.assertEqual(events, ["first", "second"])
94
95
96     def test_runningForStartupEvents(self):
97         """
98         The reactor is not running when C{"before"} C{"startup"} triggers are
99         called and is running when C{"during"} and C{"after"} C{"startup"}
100         triggers are called.
101         """
102         reactor = self.buildReactor()
103         state = {}
104         def beforeStartup():
105             state['before'] = reactor.running
106         def duringStartup():
107             state['during'] = reactor.running
108         def afterStartup():
109             state['after'] = reactor.running
110         reactor.addSystemEventTrigger("before", "startup", beforeStartup)
111         reactor.addSystemEventTrigger("during", "startup", duringStartup)
112         reactor.addSystemEventTrigger("after", "startup", afterStartup)
113         reactor.callWhenRunning(reactor.stop)
114         self.assertEqual(state, {})
115         self.runReactor(reactor)
116         self.assertEqual(
117             state,
118             {"before": False,
119              "during": True,
120              "after": True})
121
122
123     def test_signalHandlersInstalledDuringStartup(self):
124         """
125         Signal handlers are installed in responsed to the C{"during"}
126         C{"startup"}.
127         """
128         reactor = self.buildReactor()
129         phase = [None]
130         def beforeStartup():
131             phase[0] = "before"
132         def afterStartup():
133             phase[0] = "after"
134         reactor.addSystemEventTrigger("before", "startup", beforeStartup)
135         reactor.addSystemEventTrigger("after", "startup", afterStartup)
136
137         sawPhase = []
138         def fakeSignal(signum, action):
139             sawPhase.append(phase[0])
140         self.patch(signal, 'signal', fakeSignal)
141         reactor.callWhenRunning(reactor.stop)
142         self.assertEqual(phase[0], None)
143         self.assertEqual(sawPhase, [])
144         self.runReactor(reactor)
145         self.assertIn("before", sawPhase)
146         self.assertEqual(phase[0], "after")
147
148
149     def test_stopShutDownEvents(self):
150         """
151         C{reactor.stop()} fires all three phases of shutdown event triggers
152         before it makes C{reactor.run()} return.
153         """
154         reactor = self.buildReactor()
155         events = []
156         reactor.addSystemEventTrigger(
157             "before", "shutdown",
158             lambda: events.append(("before", "shutdown")))
159         reactor.addSystemEventTrigger(
160             "during", "shutdown",
161             lambda: events.append(("during", "shutdown")))
162         reactor.addSystemEventTrigger(
163             "after", "shutdown",
164             lambda: events.append(("after", "shutdown")))
165         reactor.callWhenRunning(reactor.stop)
166         self.runReactor(reactor)
167         self.assertEqual(events, [("before", "shutdown"),
168                                    ("during", "shutdown"),
169                                    ("after", "shutdown")])
170
171
172     def test_shutdownFiresTriggersAsynchronously(self):
173         """
174         C{"before"} C{"shutdown"} triggers are not run synchronously from
175         L{reactor.stop}.
176         """
177         reactor = self.buildReactor()
178         events = []
179         reactor.addSystemEventTrigger(
180             "before", "shutdown", events.append, "before shutdown")
181         def stopIt():
182             reactor.stop()
183             events.append("stopped")
184         reactor.callWhenRunning(stopIt)
185         self.assertEqual(events, [])
186         self.runReactor(reactor)
187         self.assertEqual(events, ["stopped", "before shutdown"])
188
189
190     def test_shutdownDisconnectsCleanly(self):
191         """
192         A L{IFileDescriptor.connectionLost} implementation which raises an
193         exception does not prevent the remaining L{IFileDescriptor}s from
194         having their C{connectionLost} method called.
195         """
196         lostOK = [False]
197
198         # Subclass FileDescriptor to get logPrefix
199         class ProblematicFileDescriptor(FileDescriptor):
200             def connectionLost(self, reason):
201                 raise RuntimeError("simulated connectionLost error")
202
203         class OKFileDescriptor(FileDescriptor):
204             def connectionLost(self, reason):
205                 lostOK[0] = True
206
207         reactor = self.buildReactor()
208
209         # Unfortunately, it is necessary to patch removeAll to directly control
210         # the order of the returned values.  The test is only valid if
211         # ProblematicFileDescriptor comes first.  Also, return these
212         # descriptors only the first time removeAll is called so that if it is
213         # called again the file descriptors aren't re-disconnected.
214         fds = iter([ProblematicFileDescriptor(), OKFileDescriptor()])
215         reactor.removeAll = lambda: fds
216         reactor.callWhenRunning(reactor.stop)
217         self.runReactor(reactor)
218         self.assertEqual(len(self.flushLoggedErrors(RuntimeError)), 1)
219         self.assertTrue(lostOK[0])
220
221
222     def test_multipleRun(self):
223         """
224         C{reactor.run()} raises L{ReactorAlreadyRunning} when called when
225         the reactor is already running.
226         """
227         events = []
228         def reentrantRun():
229             self.assertRaises(ReactorAlreadyRunning, reactor.run)
230             events.append("tested")
231         reactor = self.buildReactor()
232         reactor.callWhenRunning(reentrantRun)
233         reactor.callWhenRunning(reactor.stop)
234         self.runReactor(reactor)
235         self.assertEqual(events, ["tested"])
236
237
238     def test_runWithAsynchronousBeforeStartupTrigger(self):
239         """
240         When there is a C{'before'} C{'startup'} trigger which returns an
241         unfired L{Deferred}, C{reactor.run()} starts the reactor and does not
242         return until after C{reactor.stop()} is called
243         """
244         events = []
245         def trigger():
246             events.append('trigger')
247             d = Deferred()
248             d.addCallback(callback)
249             reactor.callLater(0, d.callback, None)
250             return d
251         def callback(ignored):
252             events.append('callback')
253             reactor.stop()
254         reactor = self.buildReactor()
255         reactor.addSystemEventTrigger('before', 'startup', trigger)
256         self.runReactor(reactor)
257         self.assertEqual(events, ['trigger', 'callback'])
258
259
260     def test_iterate(self):
261         """
262         C{reactor.iterate()} does not block.
263         """
264         reactor = self.buildReactor()
265         t = reactor.callLater(5, reactor.crash)
266
267         start = time.time()
268         reactor.iterate(0) # Shouldn't block
269         elapsed = time.time() - start
270
271         self.failUnless(elapsed < 2)
272         t.cancel()
273
274
275     def test_crash(self):
276         """
277         C{reactor.crash()} stops the reactor and does not fire shutdown
278         triggers.
279         """
280         reactor = self.buildReactor()
281         events = []
282         reactor.addSystemEventTrigger(
283             "before", "shutdown",
284             lambda: events.append(("before", "shutdown")))
285         reactor.callWhenRunning(reactor.callLater, 0, reactor.crash)
286         self.runReactor(reactor)
287         self.assertFalse(reactor.running)
288         self.assertFalse(
289             events,
290             "Shutdown triggers invoked but they should not have been.")
291
292
293     def test_runAfterCrash(self):
294         """
295         C{reactor.run()} restarts the reactor after it has been stopped by
296         C{reactor.crash()}.
297         """
298         events = []
299         def crash():
300             events.append('crash')
301             reactor.crash()
302         reactor = self.buildReactor()
303         reactor.callWhenRunning(crash)
304         self.runReactor(reactor)
305         def stop():
306             events.append(('stop', reactor.running))
307             reactor.stop()
308         reactor.callWhenRunning(stop)
309         self.runReactor(reactor)
310         self.assertEqual(events, ['crash', ('stop', True)])
311
312
313     def test_runAfterStop(self):
314         """
315         C{reactor.run()} raises L{ReactorNotRestartable} when called when
316         the reactor is being run after getting stopped priorly.
317         """
318         events = []
319         def restart():
320             self.assertRaises(ReactorNotRestartable, reactor.run)
321             events.append('tested')
322         reactor = self.buildReactor()
323         reactor.callWhenRunning(reactor.stop)
324         reactor.addSystemEventTrigger('after', 'shutdown', restart)
325         self.runReactor(reactor)
326         self.assertEqual(events, ['tested'])
327
328
329
330 globals().update(SystemEventTestsBuilder.makeTestCaseClasses())
331 globals().update(ObjectModelIntegrationTest.makeTestCaseClasses())