def test_connection_lost(test_client, mock_treq): mock_treq.post.side_effect = ConnectionLost() with pytest.raises(ConnectionLost): yield test_client.request("POST", "/test/uri", SOME_JSON, is_retry=True)
def test_requestFinishAfterConnectionLost(self): app = self.app request = requestMock(b"/") finished = Deferred() @app.route("/") def root(request): request.notifyFinish().addBoth(lambda _: finished.callback(b'foo')) return finished d = _render(self.kr, request) def _eb(result): [failure] = self.flushLoggedErrors(RuntimeError) self.assertEqual( str(failure.value), ("Request.finish called on a request after its connection was " "lost; use Request.notifyFinish to keep track of this.")) d.addErrback(lambda _: finished) d.addErrback(_eb) self.assertNotFired(d) request.connectionLost(ConnectionLost()) self.assertFired(d)
def _init_browser(self): # XXX: open at most one browser at a time per client (i.e. per Scrapy # instance), ensure there is no communication between pages of a # browser. If not possible, open one browser per cookiejar but also # allow the user to have separate browsers on the same cookiejar. if self._browser is not None: return factory = pb.PBClientFactory(security=jelly.DummySecurityOptions()) broker = yield self._client_endpoint.connect(factory) if isinstance(self._client_endpoint, ProcessEndpoint): atexit.register(broker.transport.signalProcess, "TERM") # Endpoints do not call ClientFactory.clientConnectionLost(), so the # factory never calls back its own getRootObject() deferreds when an # error happens. root_dfd = factory.getRootObject() broker.notifyOnDisconnect(partial(root_dfd.errback, ConnectionLost())) root = yield root_dfd if self._downloader is None: self._downloader = BrowserRequestDownloader(self._crawler) self._browser = yield root.callRemote('open_browser', self._downloader)
def _respondToBadRequestAndDisconnect(self, streamID): """ This is a quick and dirty way of responding to bad requests. As described by HTTP standard we should be patient and accept the whole request from the client before sending a polite bad request response, even in the case when clients send tons of data. Unlike in the HTTP/1.1 case, this does not actually disconnect the underlying transport: there's no need. This instead just sends a 400 response and terminates the stream. @param streamID: The ID of the stream that needs the 100 Continue response @type streamID: L{int} """ headers = [(b":status", b"400")] self.conn.send_headers(headers=headers, stream_id=streamID, end_stream=True) stillActive = self._tryToWriteControlData() if stillActive: stream = self.streams[streamID] stream.connectionLost(Failure(ConnectionLost("Invalid request"))) self._requestDone(streamID)
def test_error_sending(self, logger): """ An error sending to one agent does not prevent others from being notified. """ control_amp_service = build_control_amp_service(self) self.patch(control_amp_service, 'logger', logger) connected_protocol = ControlAMP(Clock(), control_amp_service) # Patching is bad. # https://clusterhq.atlassian.net/browse/FLOC-1603 connected_protocol.callRemote = lambda *args, **kwargs: succeed({}) error = ConnectionLost() disconnected_protocol = ControlAMP(Clock(), control_amp_service) results = [succeed({}), fail(error)] # Patching is bad. # https://clusterhq.atlassian.net/browse/FLOC-1603 disconnected_protocol.callRemote = ( lambda *args, **kwargs: results.pop(0)) control_amp_service.connected(disconnected_protocol) control_amp_service.connected(connected_protocol) control_amp_service.node_changed( ChangeSource(), (NodeState(hostname=u"1.2.3.4"),) ) actions = LoggedAction.ofType(logger.messages, LOG_SEND_TO_AGENT) self.assertEqual( [action.end_message["exception"] for action in actions if not action.succeeded], [u"twisted.internet.error.ConnectionLost"])
def test_connection_lost(self): """ Connection lost events are passed on to the agent. """ self.client.connectionLost(Failure(ConnectionLost())) self.assertEqual(self.agent, FakeAgent(is_connected=True, is_disconnected=True))
def test_connection_lost(self): # pretend we connected self.proto._connectionMade() self.proto.connectionLost(Failure(ConnectionLost())) messages = ' '.join([str(x[1]) for x in self.proto.log.mock_calls]) self.assertTrue(' was lost ' in messages)
def checkRateLimit(self, hit_args): if self.divvyProtocol is None: # fail immediately if not connected return fail(ConnectionLost("on checkRateLimit")) if self.debug_mode: self.log.debug("DivvyClient: Checking ratelimit {hit_args}", hit_args=hit_args) self.divvyProtocol.checkRateLimit(**hit_args) return self.newDeferredResponse()
def stopProducing(self): """ Stop producing data. This tells the L{H2Connection} that its consumer has died, so it must stop producing data for good. """ self.connectionLost(Failure(ConnectionLost("Producing stopped")))
def test_finishAfterConnectionLost(self): """ Calling L{Request.finish} after L{Request.connectionLost} has been called results in a L{RuntimeError} being raised. """ channel = DummyChannel() transport = channel.transport req = http.Request(channel, False) req.connectionLost(Failure(ConnectionLost("The end."))) self.assertRaises(RuntimeError, req.finish)
def test_connectionLost(self): """ Ensure that the CGI process ends cleanly when the request connection is lost. """ d = DummyChannel() request = http.Request(d, True) protocol = twcgi.CGIProcessProtocol(request) request.connectionLost(failure.Failure(ConnectionLost("Connection done"))) protocol.processEnded(failure.Failure(error.ProcessTerminated()))
def testConnectionLost(self): failure = Failure(ConnectionLost("Unit test")) with mock.patch.object(self.proto.fsm, 'connectionFailed') as mock_method: self.proto.connectionLost(failure) mock_method.assert_called() mock_method.reset_mock() self.proto.disconnected = True self.proto.connectionLost(failure) mock_method.assert_not_called()
def test_connectionLostNotification(self): """ L{Request.connectionLost} triggers all finish notification Deferreds and cleans up per-request state. """ d = DummyChannel() request = http.Request(d, True) finished = request.notifyFinish() request.connectionLost(Failure(ConnectionLost("Connection done"))) self.assertIdentical(request.channel, None) return self.assertFailure(finished, ConnectionLost)
def massage_error(error): if error.check(RemoteAmpError): rje = error.value errorType = command.reverseErrors.get(rje.errorCode, UnknownRemoteError) return Failure(errorType(rje.description)) # In this case the actual AMP implementation closes the connection. # Weakly simulate that here by failing how things fail if the # connection closes and commands are outstanding. This is sort of # terrible behavior but oh well. https://tm.tl/7055 return Failure(ConnectionLost(str(error)))
def _requestAborted(self, event): """ Internal handler for when a request is aborted by a remote peer. @param event: The Hyper-h2 event that encodes information about the reset stream. @type event: L{h2.events.StreamReset} """ stream = self.streams[event.stream_id] stream.connectionLost( ConnectionLost("Stream reset with code %s" % event.error_code)) self._requestDone(event.stream_id)
def disconnected(_): """ Make sure deferreds do not linger on after disconnect. This errbacks all deferreds of iq's for which no response has been received with a L{ConnectionLost} failure. Otherwise, the deferreds will never be fired. """ iqDeferreds = xs.iqDeferreds xs.iqDeferreds = {} for d in iqDeferreds.itervalues(): d.errback(ConnectionLost())
def test_connection_lost(self): """ When a connection is lost the ``ControlAMP`` is removed from the service's set of connections. """ marker = object() self.control_amp_service.connections.add(marker) self.patch(self.protocol, "callRemote", lambda *args, **kwargs: succeed(None)) self.protocol.makeConnection(StringTransport()) self.protocol.connectionLost(Failure(ConnectionLost())) self.assertEqual(self.control_amp_service.connections, {marker})
def test_disconnected(self): """ Pending and future requests fail when the connection goes away. """ d = self.protocol.request(b'api corr stuff') self.assertNoResult(d) self.transport.disconnectReason = ConnectionLost('Bye.') self.transport.reportDisconnect() self.failureResultOf(d, ConnectionLost) self.failureResultOf(self.protocol.request(b'api corr more'), ConnectionLost)
def test_connectionLost_uncleanly(self): kp = KafkaProtocol() logsave = afkak.protocol.log try: afkak.protocol.log = MagicMock() kp.factory = MagicMock() failure = Failure(ConnectionLost()) kp.connectionLost(failure) self.assertIsNone(kp.factory) afkak.protocol.log.warning.assert_called_once_with( 'Lost Connection to Kafka Broker: %r', failure) finally: afkak.protocol.log = logsave
def test_connection_lost(self): """ When a connection is lost the ``ControlAMP`` is removed from the service's set of connections. """ marker = object() self.control_amp_service.connections.add(marker) # Patching is bad. # https://clusterhq.atlassian.net/browse/FLOC-1603 self.patch(self.protocol, "callRemote", lambda *args, **kwargs: succeed(None)) self.protocol.makeConnection(StringTransportWithAbort()) self.protocol.connectionLost(Failure(ConnectionLost())) self.assertEqual(self.control_amp_service.connections, {marker})
def test_write_after_connection_lost(self): """ Calling L{Request.write} after L{Request.connectionLost} has been called should not throw an exception. L{RuntimeError} will be raised when finish is called on the request. NOTE: This test is taken from the upstream fix to verify the monkey patch: https://github.com/twisted/twisted/commit/169fd1d93b7af06bf0f6893b193ce19970881868 """ channel = DummyChannel() req = http.Request(channel, False) req.connectionLost(Failure(ConnectionLost("The end."))) req.write(b"foobar") self.assertRaises(RuntimeError, req.finish)
def dataReceived(self, data): """ Called whenever a chunk of data is received from the transport. @param data: The data received from the transport. @type data: L{bytes} """ try: events = self.conn.receive_data(data) except h2.exceptions.ProtocolError: stillActive = self._tryToWriteControlData() if stillActive: self.transport.loseConnection() self.connectionLost(Failure(), _cancelTimeouts=False) return # Only reset the timeout if we've received an actual H2 # protocol message self.resetTimeout() for event in events: if isinstance(event, h2.events.RequestReceived): self._requestReceived(event) elif isinstance(event, h2.events.DataReceived): self._requestDataReceived(event) elif isinstance(event, h2.events.StreamEnded): self._requestEnded(event) elif isinstance(event, h2.events.StreamReset): self._requestAborted(event) elif isinstance(event, h2.events.WindowUpdated): self._handleWindowUpdate(event.stream_id) elif isinstance(event, h2.events.RemoteSettingsChanged): if h2.settings.SettingCodes.INITIAL_WINDOW_SIZE in event.changed_settings: self._handleWindowUpdate(None) elif isinstance(event, h2.events.PriorityUpdated): self._handlePriorityUpdate(event) elif isinstance(event, h2.events.ConnectionTerminated): self.transport.loseConnection() self.connectionLost( ConnectionLost("Remote peer sent GOAWAY"), _cancelTimeouts=False, ) self._tryToWriteControlData()
def test_connectionLost(self): """ L{http.Request.connectionLost} closes L{Request.content} and drops the reference to the L{HTTPChannel} to assist with garbage collection. """ req = http.Request(DummyChannel(), None) # Cause Request.content to be created at all. req.gotLength(10) # Grab a reference to content in case the Request drops it later on. content = req.content # Put some bytes into it req.handleContentChunk("hello") # Then something goes wrong and content should get closed. req.connectionLost(Failure(ConnectionLost("Finished"))) self.assertTrue(content.closed) self.assertIdentical(req.channel, None)
def test_cancelsOnConnectionLost(self): app = self.app request = requestMock(b"/") handler_d = Deferred() @app.route("/") def root(request): return handler_d d = _render(self.kr, request) self.assertNotFired(d) request.connectionLost(ConnectionLost()) handler_d.addErrback(lambda f: f.trap(CancelledError)) d.addErrback(lambda f: f.trap(ConnectionLost)) d.addCallback(lambda _: handler_d) self.assertFired(d)
def test_nack_for_outbound_message(self): client = self.web_client() # initiate session resp_d = client.callRemote('USSD.INIT', self.SESSION_INIT_BODY) [msg] = yield self.tx_helper.wait_for_dispatched_inbound(1) # cancel the request and mute the resulting error. request = self.transport._requests[msg['message_id']] request.http_request.connectionLost(ConnectionLost()) resp_d.cancel() resp_d.addErrback(lambda f: None) # send response rep = yield self.tx_helper.make_dispatch_reply(msg, "ping") [nack] = yield self.tx_helper.wait_for_dispatched_events(1) self.assertEqual(nack['event_type'], 'nack') self.assertEqual(nack['user_message_id'], rep['message_id']) self.assertEqual(nack['sent_message_id'], rep['message_id'])
def dataReceived(self, data): """ Called whenever a chunk of data is received from the transport. @param data: The data received from the transport. @type data: L{bytes} """ self.resetTimeout() try: events = self.conn.receive_data(data) except h2.exceptions.ProtocolError: # A remote protocol error terminates the connection. dataToSend = self.conn.data_to_send() self.transport.write(dataToSend) self.transport.loseConnection() self.connectionLost(Failure()) return for event in events: if isinstance(event, h2.events.RequestReceived): self._requestReceived(event) elif isinstance(event, h2.events.DataReceived): self._requestDataReceived(event) elif isinstance(event, h2.events.StreamEnded): self._requestEnded(event) elif isinstance(event, h2.events.StreamReset): self._requestAborted(event) elif isinstance(event, h2.events.WindowUpdated): self._handleWindowUpdate(event) elif isinstance(event, h2.events.PriorityUpdated): self._handlePriorityUpdate(event) elif isinstance(event, h2.events.ConnectionTerminated): self.transport.loseConnection() self.connectionLost(ConnectionLost("Remote peer sent GOAWAY")) dataToSend = self.conn.data_to_send() if dataToSend: self.transport.write(dataToSend)
def test_returnOnlyClosesIfNotLost(self): """ L{loseConnection} will only be called on the transport upon return of the connection-handling function if the connection hasn't been lost. This is like L{test_returnOnlyClosesIfNotClosed}, but it tests the case where the connection was closed by the other side, instead of with an explicit call to C{transport.close} by the connection-handling function. """ def nothing(transport): try: transport.read() except ConnectionLost: pass return twistedTransport, protocol = self.getTransportAndProtocol(nothing) twistedTransport.loseConnection = lambda: self.fail( "loseConnection shouldn't be called!") protocol.makeConnection(twistedTransport) protocol.connectionLost(Failure(ConnectionLost("Woops")))
def test_cancelledIsEatenOnConnectionLost(self): app = self.app request = requestMock(b"/") @app.route("/") def root(request): _d = Deferred() request.notifyFinish().addErrback(lambda _: _d.cancel()) return _d d = _render(self.kr, request) self.assertNotFired(d) request.connectionLost(ConnectionLost()) def _cb(result): self.assertEqual(request.processingFailed.call_count, 0) d.addErrback(lambda f: f.trap(ConnectionLost)) d.addCallback(_cb) self.assertFired(d)
def test_reconnecting(self): transport = yield self.get_transport() message_client = transport.message_client message_client.connectionLost(Failure(ConnectionLost('foo'))) config = transport.get_static_config() self.assertTrue(transport.delay > config.initial_delay) self.assertEqual(transport.retries, 1) self.assertTrue(transport.reconnect_call) self.clock.advance(transport.delay + 0.1) # write something to ensure connectionMade() is called on # the protocol message_req = yield self.get_next_request() message_req.write('') event_req = yield self.get_next_request() event_req.write('') self.assertEqual(transport.delay, config.initial_delay) self.assertEqual(transport.retries, 0) self.assertFalse(transport.reconnect_call)
error = [] def writeOnClosed(transport): # We'll read so that we can get the ConnectionLost. try: transport.read() except Exception, firstE: pass try: transport.write("foo") except Exception, secondE: assert type(firstE) == type(secondE), (firstE, secondE) error.append(secondE) twistedTransport, protocol = self.connect(writeOnClosed) e = ConnectionLost("Oops!") twistedTransport.disconnectReason = Failure(e) twistedTransport.reportDisconnect() self.assertEquals(error, [e]) def test_closedTransportOnlyThrowsForIO(self): """ If the I/O greenlet is switched away for a reason other than I/O, a connection being lost will not cause the other switched call to raise an exception; the exception will be raised the next time an I/O operation is done. """ dones = [] clock = Clock() def waitThenRead(transport):