def test_01_writeResponse(self): """ L{HTTP._writeResponse} writes a HTTP response to the protocol's transport, then closes the connection. It takes a L{Response} object that is constructed with three arguments, a numberic response code and the body of the response, whose length is included as a content-length header, and additional headers (as a dictionary mapping keys to values). """ self.assertTrue(issubclass(HTTP, Protocol)) protocol = HTTP(None, reactor=task.Clock()) # Connect a fake, in-memory transport to the protocol: transport = AbortableTransport() protocol.makeConnection(transport) protocol._writeResponse(Response(200, "Response body!", {"content-type": "text/plain"})) self.assertEqual(transport.value(), "HTTP/1.1 200 Reason\r\n" "Content-Length: 14\r\n" "content-type: text/plain\r\n" "\r\n" "Response body!") # The connection is closed once the response has been written, # i.e. transport.loseConnection() was called: self.assertEqual(transport.disconnecting, True)
def test_02_handler(self): """ L{HTTP.__init__} is called with a function as its argument. This function is called by L{HTTP.requestReceived} with the request parameters, and its response is passed to L{HTTP._writeResponse}. In other words, this function determines how the HTTP server processes and handles requests. """ def handler(method, path, headers, body): self.assertEqual(method, "WOO") self.assertEqual(path, "/path") self.assertEqual(headers, {"Key": "value"}) return Response(300, "hello", {"k": "v"}) protocol = HTTP(handler, reactor=task.Clock()) response = [] protocol._writeResponse = lambda r: response.append(r) # Handler is stored as an attribute of the protocol: self.assertIdentical(protocol._handler, handler) # requestReceived calls handler, and then takes the results and passes # it to _writeResponse: protocol.requestReceived("WOO", "/path", {"Key": "value"}, "") self.assertResponsesEqual(response[0], Response(300, "hello", {"k": "v"}))
def test_14_handlerReturnsDeferredWithFailure(self): """ If the handler returns a Deferred that fires with a failure, L{HTTP.requestReceived} writes a 500 response code using L{HTTP._writeResponse} and logs the exception. """ # Handler that returns eventual result: result = defer.Deferred() def handler(method, path, headers, body): return result protocol = HTTP(handler, reactor=task.Clock()) response = [] protocol._writeResponse = lambda r: response.append(r) protocol.requestReceived("GET", "/", [], "") # Deferred hasn't fired yet, so no response is sent yet: self.assertEqual(len(response), 0) # Now we fire the Deferred with an exception: result.errback(ZeroDivisionError()) # 500 response code: self.assertEqual(len(response), 1) self.assertEqual(response[0].code, 500) # The error was logged using twisted.python.log.err(): excs = self.flushLoggedErrors(ZeroDivisionError) self.assertEqual(len(excs), 1)
def test_11_handlerException(self): """ If the handler throws an exception, L{HTTP.requestReceived} writes a response with error code 500 (internal server error), and the exception is logged. """ def handler(method, path, headers, body): raise RuntimeError("I am a buggy handler!") protocol = HTTP(handler, reactor=task.Clock()) response = [] protocol._writeResponse = lambda r: response.append(r) protocol.requestReceived("GET", "/", [], "") # We don't assert anything on the body of the response; if you're # feeling ambitious you can include the text of the traceback in your # response: self.assertEqual(len(response), 1) self.assertEqual(response[0].code, 500) # You should log the error using twisted.python.log.err(). This makes # sure the logged error doesn't cause the test to fail: excs = self.flushLoggedErrors(RuntimeError) # And this asserts that you logged it, i.e. that there was one # RuntimeError logged: self.assertEqual(len(excs), 1)
def test_09_badRequestResponse(self): """ L{HTTP.badRequestReceived} writes a response with a 400 code ("Bad Client Request") using L{HTTP._writeResponse). """ protocol = HTTP(None, reactor=task.Clock()) response = [] protocol._writeResponse = lambda r: response.append(r) protocol.badRequestReceived() self.assertResponsesEqual(response[0], Response(400, "", {}))
def test_19_requestBodyToHandler(self): """ If the HTTP request includes a body, it is passed to the handler function. """ result = [] def handler(method, path, headers, body): result.append(body) return Response(200, "hello", {}) protocol = HTTP(handler, reactor=task.Clock()) response = [] protocol._writeResponse = lambda r: response.append(r) protocol.requestReceived("GET", "/", {}, "the body") self.assertEqual(result, ["the body"])
def test_12_handlerReturnsDeferred(self): """ If the handler returns a Deferred that fires with (code, body, headers), L{HTTP.requestReceived} writes it as a response using L{HTTP._writeResponse}. """ # Handler that returns eventual result: result = defer.Deferred() def handler(method, path, headers, body): return result protocol = HTTP(handler, reactor=task.Clock()) response = [] protocol._writeResponse = lambda r: response.append(r) protocol.requestReceived("GET", "/", [], "") # Deferred hasn't fired yet, so no response is sent yet: self.assertEqual(len(response), 0) # Now we fire the Deferred, and response should be written: result.callback(Response(200, "response", {"key": "value"})) self.assertResponsesEqual(response[0], Response(200, "response", {"key": "value"}))