Initial import to Tizen
[profile/ivi/python-twisted.git] / twisted / internet / test / test_win32events.py
1 # Copyright (c) Twisted Matrix Laboratories.
2 # See LICENSE for details.
3
4 """
5 Tests for implementations of L{IReactorWin32Events}.
6 """
7
8 from thread import get_ident
9
10 try:
11     import win32event
12 except ImportError:
13     win32event = None
14
15 from zope.interface.verify import verifyObject
16
17 from twisted.python.threadable import isInIOThread
18 from twisted.internet.interfaces import IReactorWin32Events
19 from twisted.internet.defer import Deferred
20 from twisted.internet.test.reactormixins import ReactorBuilder
21
22
23 class Listener(object):
24     """
25     L{Listener} is an object that can be added to a L{IReactorWin32Events}
26     reactor to receive callback notification when a Windows event is set.  It
27     records what thread its callback is invoked in and fires a Deferred.
28
29     @ivar success: A flag which is set to C{True} when the event callback is
30         called.
31
32     @ivar logThreadID: The id of the thread in which the C{logPrefix} method is
33         called.
34
35     @ivar eventThreadID: The id of the thread in which the event callback is
36         called.
37
38     @ivar connLostThreadID: The id of the thread in which the C{connectionLost}
39         method is called.
40
41     @ivar _finished: The L{Deferred} which will be fired when the event callback
42         is called.
43     """
44     success = False
45     logThreadID = eventThreadID = connLostThreadID = None
46
47     def __init__(self, finished):
48         self._finished = finished
49
50
51     def logPrefix(self):
52         self.logThreadID = get_ident()
53         return 'Listener'
54
55
56     def occurred(self):
57         self.success = True
58         self.eventThreadID = get_ident()
59         self._finished.callback(None)
60
61
62     def brokenOccurred(self):
63         raise RuntimeError("Some problem")
64
65
66     def returnValueOccurred(self):
67         return EnvironmentError("Entirely different problem")
68
69
70     def connectionLost(self, reason):
71         self.connLostThreadID = get_ident()
72         self._finished.errback(reason)
73
74
75
76 class Win32EventsTestsBuilder(ReactorBuilder):
77     """
78     Builder defining tests relating to L{IReactorWin32Events}.
79     """
80     requiredInterfaces = [IReactorWin32Events]
81
82     def test_interface(self):
83         """
84         An instance of the reactor has all of the methods defined on
85         L{IReactorWin32Events}.
86         """
87         reactor = self.buildReactor()
88         verifyObject(IReactorWin32Events, reactor)
89
90
91     def test_addEvent(self):
92         """
93         When an event which has been added to the reactor is set, the action
94         associated with the event is invoked in the reactor thread.
95         """
96         reactorThreadID = get_ident()
97         reactor = self.buildReactor()
98         event = win32event.CreateEvent(None, False, False, None)
99         finished = Deferred()
100         finished.addCallback(lambda ignored: reactor.stop())
101         listener = Listener(finished)
102         reactor.addEvent(event, listener, 'occurred')
103         reactor.callWhenRunning(win32event.SetEvent, event)
104         self.runReactor(reactor)
105         self.assertTrue(listener.success)
106         self.assertEqual(reactorThreadID, listener.logThreadID)
107         self.assertEqual(reactorThreadID, listener.eventThreadID)
108
109
110     def test_ioThreadDoesNotChange(self):
111         """
112         Using L{IReactorWin32Events.addEvent} does not change which thread is
113         reported as the I/O thread.
114         """
115         results = []
116         def check(ignored):
117             results.append(isInIOThread())
118             reactor.stop()
119         reactor = self.buildReactor()
120         event = win32event.CreateEvent(None, False, False, None)
121         finished = Deferred()
122         listener = Listener(finished)
123         finished.addCallback(check)
124         reactor.addEvent(event, listener, 'occurred')
125         reactor.callWhenRunning(win32event.SetEvent, event)
126         self.runReactor(reactor)
127         self.assertTrue(listener.success)
128         self.assertEqual([True], results)
129
130
131     def test_disconnectedOnError(self):
132         """
133         If the event handler raises an exception, the event is removed from the
134         reactor and the handler's C{connectionLost} method is called in the I/O
135         thread and the exception is logged.
136         """
137         reactorThreadID = get_ident()
138         reactor = self.buildReactor()
139         event = win32event.CreateEvent(None, False, False, None)
140         finished = self.assertFailure(Deferred(), RuntimeError)
141         finished.addCallback(lambda ignored: reactor.stop())
142         listener = Listener(finished)
143         reactor.addEvent(event, listener, 'brokenOccurred')
144         reactor.callWhenRunning(win32event.SetEvent, event)
145         self.runReactor(reactor)
146         self.assertEqual(reactorThreadID, listener.connLostThreadID)
147         self.assertEqual(1, len(self.flushLoggedErrors(RuntimeError)))
148
149
150     def test_disconnectOnReturnValue(self):
151         """
152         If the event handler returns a value, the event is removed from the
153         reactor and the handler's C{connectionLost} method is called in the I/O
154         thread.
155         """
156         reactorThreadID = get_ident()
157         reactor = self.buildReactor()
158         event = win32event.CreateEvent(None, False, False, None)
159         finished = self.assertFailure(Deferred(), EnvironmentError)
160         finished.addCallback(lambda ignored: reactor.stop())
161         listener = Listener(finished)
162         reactor.addEvent(event, listener, 'returnValueOccurred')
163         reactor.callWhenRunning(win32event.SetEvent, event)
164         self.runReactor(reactor)
165         self.assertEqual(reactorThreadID, listener.connLostThreadID)
166
167
168     def test_notDisconnectedOnShutdown(self):
169         """
170         Event handlers added with L{IReactorWin32Events.addEvent} do not have
171         C{connectionLost} called on them if they are still active when the
172         reactor shuts down.
173         """
174         reactor = self.buildReactor()
175         event = win32event.CreateEvent(None, False, False, None)
176         finished = Deferred()
177         listener = Listener(finished)
178         reactor.addEvent(event, listener, 'occurred')
179         reactor.callWhenRunning(reactor.stop)
180         self.runReactor(reactor)
181         self.assertIdentical(None, listener.connLostThreadID)
182
183 globals().update(Win32EventsTestsBuilder.makeTestCaseClasses())