def test_stopTryingWhenConnected(self): """ If a L{KafkaBrokerClient} has C{stopTrying} called while it is connected, it does not subsequently attempt to reconnect if the connection is later lost. """ reactor = MemoryReactorClock() class NoConnectConnector(object): def stopConnecting(self): raise ClientError("Shouldn't be called, " "we're connected.") # pragma: no cover def connect(self): raise ClientError( "Shouldn't be reconnecting.") # pragma: no cover c = KafkaBrokerClient(reactor, 'broker', 9092, 'clientId') c.protocol = Protocol # Let's pretend we've connected: c.buildProtocol(None) # Now we stop trying, then disconnect: c.stopTrying() c.clientConnectionLost(NoConnectConnector(), Failure(ConnectionDone())) self.assertFalse(c.continueTrying)
def test_parametrizedClock(self): """ The clock used by L{KafkaBrokerClient} can be parametrized, so that one can cleanly test reconnections. """ reactor = MemoryReactorClock() factory = KafkaBrokerClient(reactor, 'broker', 9092, 'clientId') # XXX This ignores internal invariants, not a great test... factory.clientConnectionLost(FactoryAwareFakeConnector(None), Failure(ConnectionDone())) self.assertEqual(len(reactor.getDelayedCalls()), 2)
def test_closeNotify(self): from twisted.internet.error import ConnectionDone reactor = MemoryReactorClock() c = KafkaBrokerClient(reactor, 'test_closeNotify', 9092, 'clientId') c._connect() # Force a connection attempt c.connector.factory = c # MemoryReactor doesn't make this connection. c.buildProtocol(None) reactor.advance(1.0) self.assertEqual([], reactor.getDelayedCalls()) c.continueTrying = False c.close() c.clientConnectionLost(c.connector, Failure(ConnectionDone())) reactor.advance(1.0) self.assertEqual([], reactor.getDelayedCalls())
def test_close(self): reactor = MemoryReactorClock() c = KafkaBrokerClient(reactor, 'test_close', 9092, 'clientId') c._connect() # Force a connection attempt c.connector.factory = c # MemoryReactor doesn't make this connection. c.connector.state = 'connected' # set the connector to connected state dd = c.close() self.assertIsInstance(dd, Deferred) self.assertNoResult(dd) f = Failure(ConnectionDone('test_close')) c.clientConnectionLost(c.connector, f) self.assertNoResult(dd) # Advance the clock so the notify() call fires reactor.advance(0.1) r = self.successResultOf(dd) self.assertIs(r, None)
def test_requestsRetried(self): id1 = 65432 reactor = MemoryReactorClock() c = KafkaBrokerClient(reactor, 'testrequestsRetried', 9092, 'clientId') request = KafkaCodec.encode_fetch_request(b'testrequestsRetried', id1) c.makeRequest(id1, request) # Make sure the request shows unsent self.assertFalse(c.requests[id1].sent) c.connector.factory = c # MemoryReactor doesn't make this connection. # Bring up the "connection"... c.buildProtocol(None) # Replace the created proto with a mock c.proto = Mock() reactor.advance(0.1) # Now, we should have seen the 'sendString' called c.proto.sendString.assert_called_once_with(request) # And the request should be 'sent' self.assertTrue(c.requests[id1].sent) # Before the reply 'comes back' drop the connection from twisted.internet.main import CONNECTION_LOST c.clientConnectionLost(c.connector, Failure(CONNECTION_LOST)) # Make sure the proto was reset self.assertIs(c.proto, None) # Advance the clock again reactor.advance(0.1) # Make sure the request shows unsent self.assertFalse(c.requests[id1].sent) # Bring up the "connection"... c.buildProtocol(None) # Replace the created proto with a mock c.proto = Mock() reactor.advance(0.1) # Now, we should have seen the 'sendString' called c.proto.sendString.assert_called_once_with(request) # And the request should be 'sent' self.assertTrue(c.requests[id1].sent)
def test_delay_reset(self): """ Test that reconnect delay is handled correctly: 1) That initializer values are respected 2) That delay maximum is respected 3) That delay is reset to initial delay on successful connection """ init_delay = last_delay = 0.025 max_delay = 14 reactor = MemoryReactorClock() c = KafkaBrokerClient(reactor, 'test_delay_reset', 9092, 'clientId', initDelay=init_delay, maxDelay=max_delay) c.jitter = 0 # Eliminate randomness for test # Ensure KBC was initialized correctly self.assertEqual(c.retries, 0) self.assertEqual(c.delay, init_delay) self.assertEqual(c.maxDelay, max_delay) self.assertTrue(c.continueTrying) c._connect() # Force a connection attempt c.connector.factory = c # MemoryReactor doesn't make this connection. self.assertTrue(c.connector.connectCalled) # Reset it so we can track future calls c.connector.connectCalled = False # Build the protocol, like a real connector would on successful connect c.buildProtocol(None) # Fake server connection close f = Failure(ConnectionDone('test_delay_reset')) c.clientConnectionLost(c.connector, f) # Now loop failing connection attempts until we get to the max while c.delay < max_delay: # Assert a reconnect wasn't immediately attempted self.assertFalse(c.connector.connectCalled) # Assert the new delay was calculated correctly self.assertEqual(last_delay * c.factor, c.delay) last_delay = c.delay # advance the reactor, but not enough to connect reactor.advance(0.1 * c.delay) # Still no connection self.assertFalse(c.connector.connectCalled) # Should see a connection attempt after this reactor.advance(c.delay) self.assertTrue(c.connector.connectCalled) c.connector.connectCalled = False # Reset again # Claim the connection failed e = ConnectionRefusedError() c.connector.connectionFailed(e) # Assert the delay was calculated correctly self.assertEqual(max_delay, c.delay) self.assertFalse(c.connector.connectCalled) # "run" the reactor, but not enough to connect reactor.advance(0.1 * c.delay) # Still no connection self.assertFalse(c.connector.connectCalled) # Should see a connection attempt after this reactor.advance(c.delay) self.assertTrue(c.connector.connectCalled) # Build the protocol, like a real connector would on successful connect c.buildProtocol(None) # Assert that the delay and retry count were reset self.assertEqual(init_delay, c.delay) self.assertEqual(c.retries, 0)