1# Copyright (c) Twisted Matrix Laboratories. 2# See LICENSE for details. 3 4""" 5Test code for basic Factory classes. 6""" 7 8from __future__ import division, absolute_import 9 10import pickle 11 12from twisted.trial.unittest import TestCase 13 14from twisted.internet.task import Clock 15from twisted.internet.protocol import ReconnectingClientFactory, Protocol 16 17 18class FakeConnector(object): 19 """ 20 A fake connector class, to be used to mock connections failed or lost. 21 """ 22 23 def stopConnecting(self): 24 pass 25 26 27 def connect(self): 28 pass 29 30 31 32class ReconnectingFactoryTestCase(TestCase): 33 """ 34 Tests for L{ReconnectingClientFactory}. 35 """ 36 37 def test_stopTryingWhenConnected(self): 38 """ 39 If a L{ReconnectingClientFactory} has C{stopTrying} called while it is 40 connected, it does not subsequently attempt to reconnect if the 41 connection is later lost. 42 """ 43 class NoConnectConnector(object): 44 def stopConnecting(self): 45 raise RuntimeError("Shouldn't be called, we're connected.") 46 def connect(self): 47 raise RuntimeError("Shouldn't be reconnecting.") 48 49 c = ReconnectingClientFactory() 50 c.protocol = Protocol 51 # Let's pretend we've connected: 52 c.buildProtocol(None) 53 # Now we stop trying, then disconnect: 54 c.stopTrying() 55 c.clientConnectionLost(NoConnectConnector(), None) 56 self.assertFalse(c.continueTrying) 57 58 59 def test_stopTryingDoesNotReconnect(self): 60 """ 61 Calling stopTrying on a L{ReconnectingClientFactory} doesn't attempt a 62 retry on any active connector. 63 """ 64 class FactoryAwareFakeConnector(FakeConnector): 65 attemptedRetry = False 66 67 def stopConnecting(self): 68 """ 69 Behave as though an ongoing connection attempt has now 70 failed, and notify the factory of this. 71 """ 72 f.clientConnectionFailed(self, None) 73 74 def connect(self): 75 """ 76 Record an attempt to reconnect, since this is what we 77 are trying to avoid. 78 """ 79 self.attemptedRetry = True 80 81 f = ReconnectingClientFactory() 82 f.clock = Clock() 83 84 # simulate an active connection - stopConnecting on this connector should 85 # be triggered when we call stopTrying 86 f.connector = FactoryAwareFakeConnector() 87 f.stopTrying() 88 89 # make sure we never attempted to retry 90 self.assertFalse(f.connector.attemptedRetry) 91 self.assertFalse(f.clock.getDelayedCalls()) 92 93 94 def test_serializeUnused(self): 95 """ 96 A L{ReconnectingClientFactory} which hasn't been used for anything 97 can be pickled and unpickled and end up with the same state. 98 """ 99 original = ReconnectingClientFactory() 100 reconstituted = pickle.loads(pickle.dumps(original)) 101 self.assertEqual(original.__dict__, reconstituted.__dict__) 102 103 104 def test_serializeWithClock(self): 105 """ 106 The clock attribute of L{ReconnectingClientFactory} is not serialized, 107 and the restored value sets it to the default value, the reactor. 108 """ 109 clock = Clock() 110 original = ReconnectingClientFactory() 111 original.clock = clock 112 reconstituted = pickle.loads(pickle.dumps(original)) 113 self.assertIdentical(reconstituted.clock, None) 114 115 116 def test_deserializationResetsParameters(self): 117 """ 118 A L{ReconnectingClientFactory} which is unpickled does not have an 119 L{IConnector} and has its reconnecting timing parameters reset to their 120 initial values. 121 """ 122 factory = ReconnectingClientFactory() 123 factory.clientConnectionFailed(FakeConnector(), None) 124 self.addCleanup(factory.stopTrying) 125 126 serialized = pickle.dumps(factory) 127 unserialized = pickle.loads(serialized) 128 self.assertEqual(unserialized.connector, None) 129 self.assertEqual(unserialized._callID, None) 130 self.assertEqual(unserialized.retries, 0) 131 self.assertEqual(unserialized.delay, factory.initialDelay) 132 self.assertEqual(unserialized.continueTrying, True) 133 134 135 def test_parametrizedClock(self): 136 """ 137 The clock used by L{ReconnectingClientFactory} can be parametrized, so 138 that one can cleanly test reconnections. 139 """ 140 clock = Clock() 141 factory = ReconnectingClientFactory() 142 factory.clock = clock 143 144 factory.clientConnectionLost(FakeConnector(), None) 145 self.assertEqual(len(clock.calls), 1) 146