1
# Copyright (c) 2001-2009 Twisted Matrix Laboratories.
2
# See LICENSE for details.
5
Test code for basic Factory classes.
10
from twisted.trial.unittest import TestCase
12
from twisted.internet import reactor, defer
13
from twisted.internet.task import Clock
14
from twisted.internet.protocol import Factory, ReconnectingClientFactory
15
from twisted.protocols.basic import Int16StringReceiver
19
class In(Int16StringReceiver):
23
def connectionMade(self):
24
self.factory.connections += 1
26
def stringReceived(self, msg):
27
n, msg = pickle.loads(msg)
29
self.sendString(pickle.dumps(n))
31
def connectionLost(self, reason):
32
self.factory.allMessages.append(self.msgs)
33
if len(self.factory.allMessages) >= self.factory.goal:
34
self.factory.d.callback(None)
38
class Out(Int16StringReceiver):
39
msgs = dict([(x, 'X' * x) for x in range(10)])
42
self.msgs = Out.msgs.copy()
44
def connectionMade(self):
45
for i in self.msgs.keys():
46
self.sendString(pickle.dumps( (i, self.msgs[i])))
48
def stringReceived(self, msg):
52
self.transport.loseConnection()
53
self.factory.howManyTimes -= 1
54
if self.factory.howManyTimes <= 0:
55
self.factory.stopTrying()
59
class FakeConnector(object):
61
A fake connector class, to be used to mock connections failed or lost.
64
def stopConnecting(self):
73
class ReconnectingFactoryTestCase(TestCase):
75
Tests for L{ReconnectingClientFactory}.
78
def testStopTrying(self):
84
f.d = defer.Deferred()
86
c = ReconnectingClientFactory()
87
c.initialDelay = c.delay = 0.2
91
port = reactor.listenTCP(0, f)
92
self.addCleanup(port.stopListening)
93
PORT = port.getHost().port
94
reactor.connectTCP('127.0.0.1', PORT, c)
96
f.d.addCallback(self._testStopTrying_1, f, c)
98
testStopTrying.timeout = 10
101
def _testStopTrying_1(self, res, f, c):
102
self.assertEquals(len(f.allMessages), 2,
103
"not enough messages -- %s" % f.allMessages)
104
self.assertEquals(f.connections, 2,
105
"Number of successful connections incorrect %d" %
107
self.assertEquals(f.allMessages, [Out.msgs] * 2)
108
self.failIf(c.continueTrying, "stopTrying never called or ineffective")
111
def test_serializeUnused(self):
113
A L{ReconnectingClientFactory} which hasn't been used for anything
114
can be pickled and unpickled and end up with the same state.
116
original = ReconnectingClientFactory()
117
reconstituted = pickle.loads(pickle.dumps(original))
118
self.assertEqual(original.__dict__, reconstituted.__dict__)
121
def test_serializeWithClock(self):
123
The clock attribute of L{ReconnectingClientFactory} is not serialized,
124
and the restored value sets it to the default value, the reactor.
127
original = ReconnectingClientFactory()
128
original.clock = clock
129
reconstituted = pickle.loads(pickle.dumps(original))
130
self.assertIdentical(reconstituted.clock, None)
133
def test_deserializationResetsParameters(self):
135
A L{ReconnectingClientFactory} which is unpickled does not have an
136
L{IConnector} and has its reconnecting timing parameters reset to their
139
factory = ReconnectingClientFactory()
140
factory.clientConnectionFailed(FakeConnector(), None)
141
self.addCleanup(factory.stopTrying)
143
serialized = pickle.dumps(factory)
144
unserialized = pickle.loads(serialized)
145
self.assertEqual(unserialized.connector, None)
146
self.assertEqual(unserialized._callID, None)
147
self.assertEqual(unserialized.retries, 0)
148
self.assertEqual(unserialized.delay, factory.initialDelay)
149
self.assertEqual(unserialized.continueTrying, True)
152
def test_parametrizedClock(self):
154
The clock used by L{ReconnectingClientFactory} can be parametrized, so
155
that one can cleanly test reconnections.
158
factory = ReconnectingClientFactory()
159
factory.clock = clock
161
factory.clientConnectionLost(FakeConnector(), None)
162
self.assertEquals(len(clock.calls), 1)