Initial import to Tizen
[profile/ivi/python-twisted.git] / twisted / internet / test / test_protocol.py
1 # Copyright (c) Twisted Matrix Laboratories.
2 # See LICENSE for details.
3
4 """
5 Tests for L{twisted.internet.protocol}.
6 """
7
8 from zope.interface.verify import verifyObject
9
10 from twisted.python.failure import Failure
11 from twisted.internet.interfaces import IProtocol, ILoggingContext
12 from twisted.internet.defer import CancelledError
13 from twisted.internet.protocol import Protocol, ClientCreator
14 from twisted.internet.task import Clock
15 from twisted.trial.unittest import TestCase
16 from twisted.test.proto_helpers import MemoryReactor, StringTransport
17
18
19
20 class MemoryConnector:
21     _disconnected = False
22
23     def disconnect(self):
24         self._disconnected = True
25
26
27
28 class MemoryReactorWithConnectorsAndTime(MemoryReactor, Clock):
29     """
30     An extension of L{MemoryReactor} which returns L{IConnector}
31     providers from its C{connectTCP} method.
32     """
33     def __init__(self):
34         MemoryReactor.__init__(self)
35         Clock.__init__(self)
36         self.connectors = []
37
38
39     def connectTCP(self, *a, **kw):
40         MemoryReactor.connectTCP(self, *a, **kw)
41         connector = MemoryConnector()
42         self.connectors.append(connector)
43         return connector
44
45
46     def connectUNIX(self, *a, **kw):
47         MemoryReactor.connectUNIX(self, *a, **kw)
48         connector = MemoryConnector()
49         self.connectors.append(connector)
50         return connector
51
52
53     def connectSSL(self, *a, **kw):
54         MemoryReactor.connectSSL(self, *a, **kw)
55         connector = MemoryConnector()
56         self.connectors.append(connector)
57         return connector
58
59
60
61 class ClientCreatorTests(TestCase):
62     """
63     Tests for L{twisted.internet.protocol.ClientCreator}.
64     """
65     def _basicConnectTest(self, check):
66         """
67         Helper for implementing a test to verify that one of the I{connect}
68         methods of L{ClientCreator} passes the right arguments to the right
69         reactor method.
70
71         @param check: A function which will be invoked with a reactor and a
72             L{ClientCreator} instance and which should call one of the
73             L{ClientCreator}'s I{connect} methods and assert that all of its
74             arguments except for the factory are passed on as expected to the
75             reactor.  The factory should be returned.
76         """
77         class SomeProtocol(Protocol):
78             pass
79
80         reactor = MemoryReactorWithConnectorsAndTime()
81         cc = ClientCreator(reactor, SomeProtocol)
82         factory = check(reactor, cc)
83         protocol = factory.buildProtocol(None)
84         self.assertIsInstance(protocol, SomeProtocol)
85
86
87     def test_connectTCP(self):
88         """
89         L{ClientCreator.connectTCP} calls C{reactor.connectTCP} with the host
90         and port information passed to it, and with a factory which will
91         construct the protocol passed to L{ClientCreator.__init__}.
92         """
93         def check(reactor, cc):
94             cc.connectTCP('example.com', 1234, 4321, ('1.2.3.4', 9876))
95             host, port, factory, timeout, bindAddress = reactor.tcpClients.pop()
96             self.assertEqual(host, 'example.com')
97             self.assertEqual(port, 1234)
98             self.assertEqual(timeout, 4321)
99             self.assertEqual(bindAddress, ('1.2.3.4', 9876))
100             return factory
101         self._basicConnectTest(check)
102
103
104     def test_connectUNIX(self):
105         """
106         L{ClientCreator.connectUNIX} calls C{reactor.connectUNIX} with the
107         filename passed to it, and with a factory which will construct the
108         protocol passed to L{ClientCreator.__init__}.
109         """
110         def check(reactor, cc):
111             cc.connectUNIX('/foo/bar', 123, True)
112             address, factory, timeout, checkPID = reactor.unixClients.pop()
113             self.assertEqual(address, '/foo/bar')
114             self.assertEqual(timeout, 123)
115             self.assertEqual(checkPID, True)
116             return factory
117         self._basicConnectTest(check)
118
119
120     def test_connectSSL(self):
121         """
122         L{ClientCreator.connectSSL} calls C{reactor.connectSSL} with the host,
123         port, and context factory passed to it, and with a factory which will
124         construct the protocol passed to L{ClientCreator.__init__}.
125         """
126         def check(reactor, cc):
127             expectedContextFactory = object()
128             cc.connectSSL('example.com', 1234, expectedContextFactory, 4321, ('4.3.2.1', 5678))
129             host, port, factory, contextFactory, timeout, bindAddress = reactor.sslClients.pop()
130             self.assertEqual(host, 'example.com')
131             self.assertEqual(port, 1234)
132             self.assertIdentical(contextFactory, expectedContextFactory)
133             self.assertEqual(timeout, 4321)
134             self.assertEqual(bindAddress, ('4.3.2.1', 5678))
135             return factory
136         self._basicConnectTest(check)
137
138
139     def _cancelConnectTest(self, connect):
140         """
141         Helper for implementing a test to verify that cancellation of the
142         L{Deferred} returned by one of L{ClientCreator}'s I{connect} methods is
143         implemented to cancel the underlying connector.
144
145         @param connect: A function which will be invoked with a L{ClientCreator}
146             instance as an argument and which should call one its I{connect}
147             methods and return the result.
148
149         @return: A L{Deferred} which fires when the test is complete or fails if
150             there is a problem.
151         """
152         reactor = MemoryReactorWithConnectorsAndTime()
153         cc = ClientCreator(reactor, Protocol)
154         d = connect(cc)
155         connector = reactor.connectors.pop()
156         self.assertFalse(connector._disconnected)
157         d.cancel()
158         self.assertTrue(connector._disconnected)
159         return self.assertFailure(d, CancelledError)
160
161
162     def test_cancelConnectTCP(self):
163         """
164         The L{Deferred} returned by L{ClientCreator.connectTCP} can be cancelled
165         to abort the connection attempt before it completes.
166         """
167         def connect(cc):
168             return cc.connectTCP('example.com', 1234)
169         return self._cancelConnectTest(connect)
170
171
172     def test_cancelConnectUNIX(self):
173         """
174         The L{Deferred} returned by L{ClientCreator.connectTCP} can be cancelled
175         to abort the connection attempt before it completes.
176         """
177         def connect(cc):
178             return cc.connectUNIX('/foo/bar')
179         return self._cancelConnectTest(connect)
180
181
182     def test_cancelConnectSSL(self):
183         """
184         The L{Deferred} returned by L{ClientCreator.connectTCP} can be cancelled
185         to abort the connection attempt before it completes.
186         """
187         def connect(cc):
188             return cc.connectSSL('example.com', 1234, object())
189         return self._cancelConnectTest(connect)
190
191
192     def _cancelConnectTimeoutTest(self, connect):
193         """
194         Like L{_cancelConnectTest}, but for the case where the L{Deferred} is
195         cancelled after the connection is set up but before it is fired with the
196         resulting protocol instance.
197         """
198         reactor = MemoryReactorWithConnectorsAndTime()
199         cc = ClientCreator(reactor, Protocol)
200         d = connect(reactor, cc)
201         connector = reactor.connectors.pop()
202         # Sanity check - there is an outstanding delayed call to fire the
203         # Deferred.
204         self.assertEqual(len(reactor.getDelayedCalls()), 1)
205
206         # Cancel the Deferred, disconnecting the transport just set up and
207         # cancelling the delayed call.
208         d.cancel()
209
210         self.assertEqual(reactor.getDelayedCalls(), [])
211
212         # A real connector implementation is responsible for disconnecting the
213         # transport as well.  For our purposes, just check that someone told the
214         # connector to disconnect.
215         self.assertTrue(connector._disconnected)
216
217         return self.assertFailure(d, CancelledError)
218
219
220     def test_cancelConnectTCPTimeout(self):
221         """
222         L{ClientCreator.connectTCP} inserts a very short delayed call between
223         the time the connection is established and the time the L{Deferred}
224         returned from one of its connect methods actually fires.  If the
225         L{Deferred} is cancelled in this interval, the established connection is
226         closed, the timeout is cancelled, and the L{Deferred} fails with
227         L{CancelledError}.
228         """
229         def connect(reactor, cc):
230             d = cc.connectTCP('example.com', 1234)
231             host, port, factory, timeout, bindAddress = reactor.tcpClients.pop()
232             protocol = factory.buildProtocol(None)
233             transport = StringTransport()
234             protocol.makeConnection(transport)
235             return d
236         return self._cancelConnectTimeoutTest(connect)
237
238
239     def test_cancelConnectUNIXTimeout(self):
240         """
241         L{ClientCreator.connectUNIX} inserts a very short delayed call between
242         the time the connection is established and the time the L{Deferred}
243         returned from one of its connect methods actually fires.  If the
244         L{Deferred} is cancelled in this interval, the established connection is
245         closed, the timeout is cancelled, and the L{Deferred} fails with
246         L{CancelledError}.
247         """
248         def connect(reactor, cc):
249             d = cc.connectUNIX('/foo/bar')
250             address, factory, timeout, bindAddress = reactor.unixClients.pop()
251             protocol = factory.buildProtocol(None)
252             transport = StringTransport()
253             protocol.makeConnection(transport)
254             return d
255         return self._cancelConnectTimeoutTest(connect)
256
257
258     def test_cancelConnectSSLTimeout(self):
259         """
260         L{ClientCreator.connectSSL} inserts a very short delayed call between
261         the time the connection is established and the time the L{Deferred}
262         returned from one of its connect methods actually fires.  If the
263         L{Deferred} is cancelled in this interval, the established connection is
264         closed, the timeout is cancelled, and the L{Deferred} fails with
265         L{CancelledError}.
266         """
267         def connect(reactor, cc):
268             d = cc.connectSSL('example.com', 1234, object())
269             host, port, factory, contextFactory, timeout, bindADdress = reactor.sslClients.pop()
270             protocol = factory.buildProtocol(None)
271             transport = StringTransport()
272             protocol.makeConnection(transport)
273             return d
274         return self._cancelConnectTimeoutTest(connect)
275
276
277     def _cancelConnectFailedTimeoutTest(self, connect):
278         """
279         Like L{_cancelConnectTest}, but for the case where the L{Deferred} is
280         cancelled after the connection attempt has failed but before it is fired
281         with the resulting failure.
282         """
283         reactor = MemoryReactorWithConnectorsAndTime()
284         cc = ClientCreator(reactor, Protocol)
285         d, factory = connect(reactor, cc)
286         connector = reactor.connectors.pop()
287         factory.clientConnectionFailed(
288             connector, Failure(Exception("Simulated failure")))
289
290         # Sanity check - there is an outstanding delayed call to fire the
291         # Deferred.
292         self.assertEqual(len(reactor.getDelayedCalls()), 1)
293
294         # Cancel the Deferred, cancelling the delayed call.
295         d.cancel()
296
297         self.assertEqual(reactor.getDelayedCalls(), [])
298
299         return self.assertFailure(d, CancelledError)
300
301
302     def test_cancelConnectTCPFailedTimeout(self):
303         """
304         Similar to L{test_cancelConnectTCPTimeout}, but for the case where the
305         connection attempt fails.
306         """
307         def connect(reactor, cc):
308             d = cc.connectTCP('example.com', 1234)
309             host, port, factory, timeout, bindAddress = reactor.tcpClients.pop()
310             return d, factory
311         return self._cancelConnectFailedTimeoutTest(connect)
312
313
314     def test_cancelConnectUNIXFailedTimeout(self):
315         """
316         Similar to L{test_cancelConnectUNIXTimeout}, but for the case where the
317         connection attempt fails.
318         """
319         def connect(reactor, cc):
320             d = cc.connectUNIX('/foo/bar')
321             address, factory, timeout, bindAddress = reactor.unixClients.pop()
322             return d, factory
323         return self._cancelConnectFailedTimeoutTest(connect)
324
325
326     def test_cancelConnectSSLFailedTimeout(self):
327         """
328         Similar to L{test_cancelConnectSSLTimeout}, but for the case where the
329         connection attempt fails.
330         """
331         def connect(reactor, cc):
332             d = cc.connectSSL('example.com', 1234, object())
333             host, port, factory, contextFactory, timeout, bindADdress = reactor.sslClients.pop()
334             return d, factory
335         return self._cancelConnectFailedTimeoutTest(connect)
336
337
338 class ProtocolTests(TestCase):
339     """
340     Tests for L{twisted.internet.protocol.Protocol}.
341     """
342     def test_interfaces(self):
343         """
344         L{Protocol} instances provide L{IProtocol} and L{ILoggingContext}.
345         """
346         proto = Protocol()
347         self.assertTrue(verifyObject(IProtocol, proto))
348         self.assertTrue(verifyObject(ILoggingContext, proto))
349
350
351     def test_logPrefix(self):
352         """
353         L{Protocol.logPrefix} returns the protocol class's name.
354         """
355         class SomeThing(Protocol):
356             pass
357         self.assertEqual("SomeThing", SomeThing().logPrefix())