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_makeUnconnectedRequest(self): """ Ensure that sending a request when not connected will attempt to bring up a connection if one isn't already in the process of being brought up """ id1 = 65432 reactor = MemoryReactorClock() c = KafkaBrokerClient(reactor, 'testmakeUnconnectedRequest', 9092, 'clientId') request = KafkaCodec.encode_fetch_request( b'testmakeUnconnectedRequest', id1) d = c.makeRequest(id1, request) self.assertIsInstance(d, Deferred) # Make sure the request shows unsent self.assertFalse(c.requests[id1].sent) # Make sure a connection was attempted self.assertTrue(c.connector) 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(1.0) # Now, we should have seen the 'sendString' called c.proto.sendString.assert_called_once_with(request)
def test_makeRequest(self): id1 = 54321 id2 = 76543 reactor = MemoryReactorClock() c = KafkaBrokerClient(reactor, 'testmakeRequest', 9092, 'clientId') request = KafkaCodec.encode_fetch_request(b'testmakeRequest', id1) d = c.makeRequest(id1, request) eb1 = Mock() self.assertIsInstance(d, Deferred) d.addErrback(eb1) # Make sure the request shows unsent self.assertFalse(c.requests[id1].sent) # Make sure a connection was attempted self.assertTrue(c.connector) 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() # Advance the clock so sendQueued() will be called reactor.advance(1.0) # The proto should have be asked to sendString the request c.proto.sendString.assert_called_once_with(request) # now call with 'expectReply=False' c.proto = Mock() request = KafkaCodec.encode_fetch_request(b'testmakeRequest2', id2) d2 = c.makeRequest(id2, request, expectResponse=False) self.assertIsInstance(d2, Deferred) c.proto.sendString.assert_called_once_with(request) # Now close the KafkaBrokerClient c.close() fail1 = eb1.call_args[0][0] # The actual failure sent to errback self.assertTrue(fail1.check(CancelledError))
def test_connected(self): reactor = MemoryReactorClock() reactor.running = True c = KafkaBrokerClient(reactor, 'test_connect', 9092, 'clientId') c._connect() # Force a connection attempt c.connector.factory = c # MemoryReactor doesn't make this connection. self.assertFalse(c.connected()) # Build the protocol, like a real connector would c.buildProtocol(None) self.assertTrue(c.connected()) reactor.advance(1.0) # Trigger the DelayedCall to _notify
def test_connect(self): reactor = MemoryReactorClock() reactor.running = True c = KafkaBrokerClient(reactor, 'kafka.example.com', 9092, 'clientId') c._connect() # Force a connection attempt c.connector.factory = c # MemoryReactor doesn't make this connection. # Build the protocol, like a real connector would addr = IPv4Address('TCP', '1.2.3.4', 9092) c.buildProtocol(addr) self.assertEqual(("<KafkaBrokerClient kafka.example.com:9092 " "clientId='clientId' connected>"), repr(c))
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_connectNotify(self): from afkak.protocol import KafkaProtocol reactor = MemoryReactorClock() c = KafkaBrokerClient(reactor, 'test_connectNotify', 9092, 'clientId') c._connect() # Force a connection attempt c.connector.factory = c # MemoryReactor doesn't make this connection. proto = c.buildProtocol(None) self.assertIsInstance(proto, KafkaProtocol) reactor.advance(1.0) self.assertEqual([], reactor.getDelayedCalls())
def test_makeRequest_fails(self): id1 = 15432 reactor = MemoryReactorClock() c = KafkaBrokerClient(reactor, 'testmakeRequest', 9092, 'clientId') request = KafkaCodec.encode_fetch_request(b'testmakeRequest', id1) d = c.makeRequest(id1, request) eb1 = Mock() self.assertIsInstance(d, Deferred) d.addErrback(eb1) 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() c.proto.sendString.side_effect = StringTooLongError( "Tried to send too many bytes") # Advance the clock so sendQueued() will be called reactor.advance(1.0) # The proto should have be asked to sendString the request c.proto.sendString.assert_called_once_with(request) # Now close the KafkaBrokerClient c.close()
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)