def _cancelConnectTimeoutTest(self, connect): """ Like L{_cancelConnectTest}, but for the case where the L{Deferred} is cancelled after the connection is set up but before it is fired with the resulting protocol instance. """ reactor = MemoryReactorClock() cc = ClientCreator(reactor, Protocol) d = connect(reactor, cc) connector = reactor.connectors.pop() # Sanity check - there is an outstanding delayed call to fire the # Deferred. self.assertEqual(len(reactor.getDelayedCalls()), 1) # Cancel the Deferred, disconnecting the transport just set up and # cancelling the delayed call. d.cancel() self.assertEqual(reactor.getDelayedCalls(), []) # A real connector implementation is responsible for disconnecting the # transport as well. For our purposes, just check that someone told the # connector to disconnect. self.assertTrue(connector._disconnected) return self.assertFailure(d, CancelledError)
def _cancelConnectTimeoutTest(self, connect): """ Like L{_cancelConnectTest}, but for the case where the L{Deferred} is cancelled after the connection is set up but before it is fired with the resulting protocol instance. """ reactor = MemoryReactorClock() cc = ClientCreator(reactor, Protocol) d = connect(reactor, cc) connector = reactor.connectors.pop() # Sanity check - there is an outstanding delayed call to fire the # Deferred. self.assertEqual(len(reactor.getDelayedCalls()), 1) # Cancel the Deferred, disconnecting the transport just set up and # cancelling the delayed call. d.cancel() self.assertEqual(reactor.getDelayedCalls(), []) # A real connector implementation is responsible for disconnecting the # transport as well. For our purposes, just check that someone told the # connector to disconnect. self.assertTrue(connector._disconnected) return self.assertFailure(d, CancelledError)
def test_closeNotifyDuringConnect(self): 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. reactor.advance(1.0) self.assertEqual([], reactor.getDelayedCalls()) c.close() c.clientConnectionFailed(c.connector, Failure(UserError())) reactor.advance(1.0) self.assertEqual([], reactor.getDelayedCalls())
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_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 _cancelConnectFailedTimeoutTest(self, connect): """ Like L{_cancelConnectTest}, but for the case where the L{Deferred} is cancelled after the connection attempt has failed but before it is fired with the resulting failure. """ reactor = MemoryReactorClock() cc = ClientCreator(reactor, Protocol) d, factory = connect(reactor, cc) connector = reactor.connectors.pop() factory.clientConnectionFailed( connector, Failure(Exception("Simulated failure"))) # Sanity check - there is an outstanding delayed call to fire the # Deferred. self.assertEqual(len(reactor.getDelayedCalls()), 1) # Cancel the Deferred, cancelling the delayed call. d.cancel() self.assertEqual(reactor.getDelayedCalls(), []) return self.assertFailure(d, CancelledError)
def _cancelConnectFailedTimeoutTest(self, connect): """ Like L{_cancelConnectTest}, but for the case where the L{Deferred} is cancelled after the connection attempt has failed but before it is fired with the resulting failure. """ reactor = MemoryReactorClock() cc = ClientCreator(reactor, Protocol) d, factory = connect(reactor, cc) connector = reactor.connectors.pop() factory.clientConnectionFailed( connector, Failure(Exception("Simulated failure"))) # Sanity check - there is an outstanding delayed call to fire the # Deferred. self.assertEqual(len(reactor.getDelayedCalls()), 1) # Cancel the Deferred, cancelling the delayed call. d.cancel() self.assertEqual(reactor.getDelayedCalls(), []) return self.assertFailure(d, CancelledError)
def test_parser(self): """ ``AcmeParser`` creates an endpoint with the specified ACME directory and directory store. """ directory = URL.fromText(u'https://example.com/acme') parser = _AcmeParser(u'prefix', directory) tempdir = self.useFixture(TempDir()).path temp_path = FilePath(tempdir) key_path = temp_path.child('client.key') reactor = MemoryReactorClock() self.assertThat( parser.parseStreamServer(reactor, tempdir, 'tcp', '443', timeout=0), MatchesAll( IsInstance(AutoTLSEndpoint), MatchesStructure( reactor=Is(reactor), directory=Equals(directory), cert_store=MatchesAll( IsInstance(DirectoryStore), MatchesStructure(path=Equals(temp_path))), cert_mapping=MatchesAll( IsInstance(HostDirectoryMap), MatchesStructure(directoryPath=Equals(temp_path))), sub_endpoint=MatchesPredicate( IStreamServerEndpoint.providedBy, '%r is not a stream server endpoint')))) self.assertThat(key_path.isfile(), Equals(True)) key_data = key_path.getContent() # Multiple instances with certificates from the same local directory, # will serve the same certificates. parser.parseStreamServer(reactor, tempdir, 'tcp', '443', timeout=0) self.assertThat(key_path.getContent(), Equals(key_data)) # Check that reactor is clean. self.assertEquals(0, len(reactor.getDelayedCalls()))
class ServiceProtocolTest(TestCase): def setUp(self): super(ServiceProtocolTest, self).setUp() self.logger = self.useFixture(FakeLogger()) self.reactor = MemoryReactorClock() self.process = MemoryProcess() self.protocol = ServiceProtocol(self.reactor) self.process.proto = self.protocol def test_fork(self): """ When the connection is made it means that we sucessfully forked the service process, so we start waiting a bit to see if it stays running or exits shortly. """ self.protocol.makeConnection(self.process) [call1, call2] = self.reactor.getDelayedCalls() self.assertEqual(call1.time, self.protocol.minUptime) self.assertEqual(call2.time, self.protocol.timeout) self.assertIn("Service process spawned", self.logger.output) def test_min_uptime(self): """ If the process stays running for at least minUptime seconds, the 'ready' Deferred gets fired. """ self.protocol.makeConnection(self.process) self.reactor.advance(0.2) self.assertThat(self.protocol.ready, succeeded(Is(None))) self.assertIn("Service process alive for 0.2 seconds", self.logger.output) def test_expected_output(self): """ If some expected output is required, the 'ready' deferred fires only when such output has been received. """ self.protocol.expectedOutput = "hello" self.protocol.makeConnection(self.process) self.reactor.advance(self.protocol.minUptime) self.assertThat(self.protocol.ready, has_no_result()) self.protocol.outReceived(b"hello world!\n") self.assertThat(self.protocol.ready, succeeded(Is(None))) self.assertIn("Service process emitted 'hello'", self.logger.output) def test_expected_port(self): """ If some expected port is required, the 'ready' deferred fires only when such port has been opened. """ self.protocol.expectedPort = 1234 self.protocol.makeConnection(self.process) self.reactor.advance(self.protocol.minUptime) self.assertThat(self.protocol.ready, has_no_result()) factory = self.reactor.tcpClients[0][2] factory.buildProtocol(None).connectionMade() self.assertThat(self.protocol.ready, succeeded(Is(None))) self.assertIn("Service opened port 1234", self.logger.output) def test_expected_port_probe_failed(self): """ If probing for the expected port fails, the probe will be retried. """ self.protocol.expectedPort = 1234 self.protocol.makeConnection(self.process) self.reactor.advance(self.protocol.minUptime) self.assertThat(self.protocol.ready, has_no_result()) factory = self.reactor.tcpClients[0][2] factory.clientConnectionFailed(None, ConnectionRefusedError()) self.assertIn("Service port probe failed", self.logger.output) self.reactor.advance(0.1) factory = self.reactor.tcpClients[1][2] factory.buildProtocol(None).connectionMade() self.assertThat(self.protocol.ready, succeeded(Is(None))) self.assertIn("Service opened port 1234", self.logger.output) def test_process_dies_shortly_after_fork(self): """ If the service process exists right after having been spawned (for example the executable was not found), the 'ready' Deferred fires with an errback. """ self.protocol.makeConnection(self.process) error = ProcessTerminated(exitCode=1, signal=None) self.protocol.processExited(Failure(error)) self.assertThat(self.protocol.ready, failed(MatchesStructure(value=Is(error)))) def test_cancel_while_waiting_for_uptime(self): """ If the 'ready' deferred gets cancelled while still waiting for the minumum uptime, a proper message is emitted. """ self.protocol.makeConnection(self.process) self.protocol.ready.cancel() self.assertIn("minimum uptime not yet elapsed", self.logger.output) self.assertThat( self.protocol.ready, failed(MatchesStructure(value=IsInstance(CancelledError)))) def test_process_dies_while_waiting_expected_output(self): """ If the service process exists while waiting for the expected output, the 'ready' Deferred fires with an errback. """ self.protocol.expectedOutput = "hello" self.protocol.makeConnection(self.process) self.reactor.advance(self.protocol.minUptime) error = ProcessTerminated(exitCode=1, signal=None) self.protocol.processExited(Failure(error)) self.assertThat(self.protocol.ready, failed(MatchesStructure(value=Is(error)))) # Further input received on the file descriptor will be discarded self.protocol.ready = Deferred() # pretend that we didn't get fired self.protocol.outReceived(b"hello world!\n") self.assertThat(self.protocol.ready, has_no_result()) def test_timeout_while_waiting_expected_output(self): """ If the timeout elapses while waiting for the expected output, the 'ready' Deferred fires with an errback. """ self.protocol.expectedOutput = "hello" self.protocol.makeConnection(self.process) self.reactor.advance(self.protocol.minUptime) self.reactor.advance(self.protocol.timeout) self.assertThat( self.protocol.ready, failed(MatchesStructure(value=IsInstance(TimeoutError)))) self.assertIn("expected output not yet received", self.logger.output) def test_process_dies_while_probing_port(self): """ If the service process exists while waiting for the expected port to, be open, the 'ready' Deferred fires with an errback. """ self.protocol.expectedPort = 1234 self.protocol.makeConnection(self.process) self.reactor.advance(self.protocol.minUptime) error = ProcessTerminated(exitCode=1, signal=None) self.protocol.processExited(Failure(error)) self.assertThat(self.protocol.ready, failed(MatchesStructure(value=Is(error)))) # No further probe will happen self.reactor.advance(0.1) self.assertEqual(1, len(self.reactor.tcpClients)) def test_timeout_while_probing_port(self): """ If the service process doesn't listen to the expected port within the, timeout, 'ready' Deferred fires with an errback. """ self.protocol.expectedPort = 1234 self.protocol.makeConnection(self.process) self.reactor.advance(self.protocol.minUptime) self.reactor.advance(self.protocol.timeout) self.assertThat( self.protocol.ready, failed(MatchesStructure(value=IsInstance(TimeoutError)))) self.assertIn("expected port not yet open", self.logger.output) def test_cancel_ready(self): """ If the `ready` deferred gets cancelled, the protocol will stop doing anything related to waiting for the service to be ready. """ self.protocol.makeConnection(self.process) self.protocol.ready.cancel() self.assertThat( self.protocol.ready, failed(MatchesStructure(value=IsInstance(CancelledError)))) self.assertEqual(0, len(self.reactor.getDelayedCalls())) def test_terminated(self): """ When the process is fully terminated, the 'terminated' deferred gets fired. """ self.protocol.makeConnection(self.process) self.reactor.advance(self.protocol.minUptime) self.protocol.transport.processEnded(0) self.assertThat(self.protocol.terminated, succeeded(Is(None)))