// Copyright 2007 Google Inc. // All Rights Reserved. #include "talk/base/gunit.h" #include "talk/base/httpserver.h" #include "talk/base/testutils.h" using namespace testing; namespace talk_base { namespace { const char* const kRequest = "GET /index.html HTTP/1.1\r\n" "Host: localhost\r\n" "\r\n"; const char* const kResponse = "HTTP/1.1 200\r\n" "Connection: Close\r\n" "Content-Length: 0\r\n" "\r\n"; struct HttpServerMonitor : public sigslot::has_slots<> { HttpServerTransaction* transaction; bool server_closed, connection_closed; HttpServerMonitor(HttpServer* server) : transaction(NULL), server_closed(false), connection_closed(false) { server->SignalCloseAllComplete.connect(this, &HttpServerMonitor::OnClosed); server->SignalHttpRequest.connect(this, &HttpServerMonitor::OnRequest); server->SignalHttpRequestComplete.connect(this, &HttpServerMonitor::OnRequestComplete); server->SignalConnectionClosed.connect(this, &HttpServerMonitor::OnConnectionClosed); } void OnRequest(HttpServer*, HttpServerTransaction* t) { ASSERT_FALSE(transaction); transaction = t; transaction->response.set_success(); transaction->response.setHeader(HH_CONNECTION, "Close"); } void OnRequestComplete(HttpServer*, HttpServerTransaction* t, int) { ASSERT_EQ(transaction, t); transaction = NULL; } void OnClosed(HttpServer*) { server_closed = true; } void OnConnectionClosed(HttpServer*, int, StreamInterface* stream) { connection_closed = true; delete stream; } }; void CreateClientConnection(HttpServer& server, HttpServerMonitor& monitor, bool send_request) { StreamSource* client = new StreamSource; client->SetState(SS_OPEN); server.HandleConnection(client); EXPECT_FALSE(monitor.server_closed); EXPECT_FALSE(monitor.transaction); if (send_request) { // Simulate a request client->QueueString(kRequest); EXPECT_FALSE(monitor.server_closed); } } } // anonymous namespace TEST(HttpServer, DoesNotSignalCloseUnlessCloseAllIsCalled) { HttpServer server; HttpServerMonitor monitor(&server); // Add an active client connection CreateClientConnection(server, monitor, true); // Simulate a response ASSERT_TRUE(NULL != monitor.transaction); server.Respond(monitor.transaction); EXPECT_FALSE(monitor.transaction); // Connection has closed, but no server close signal EXPECT_FALSE(monitor.server_closed); EXPECT_TRUE(monitor.connection_closed); } TEST(HttpServer, SignalsCloseWhenNoConnectionsAreActive) { HttpServer server; HttpServerMonitor monitor(&server); // Add an idle client connection CreateClientConnection(server, monitor, false); // Perform graceful close server.CloseAll(false); // Connections have all closed EXPECT_TRUE(monitor.server_closed); EXPECT_TRUE(monitor.connection_closed); } TEST(HttpServer, SignalsCloseAfterGracefulCloseAll) { HttpServer server; HttpServerMonitor monitor(&server); // Add an active client connection CreateClientConnection(server, monitor, true); // Initiate a graceful close server.CloseAll(false); EXPECT_FALSE(monitor.server_closed); // Simulate a response ASSERT_TRUE(NULL != monitor.transaction); server.Respond(monitor.transaction); EXPECT_FALSE(monitor.transaction); // Connections have all closed EXPECT_TRUE(monitor.server_closed); EXPECT_TRUE(monitor.connection_closed); } TEST(HttpServer, SignalsCloseAfterForcedCloseAll) { HttpServer server; HttpServerMonitor monitor(&server); // Add an active client connection CreateClientConnection(server, monitor, true); // Initiate a forceful close server.CloseAll(true); // Connections have all closed EXPECT_TRUE(monitor.server_closed); EXPECT_TRUE(monitor.connection_closed); } } // namespace talk_base