From 4491901f960f27e88bd5fdc4fd2e5a84a2dc6b03 Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Tue, 31 Jan 2017 13:35:06 +0100 Subject: [PATCH] [5099] Added unit test for HttpConnectionPool. --- src/lib/http/connection_pool.h | 2 +- src/lib/http/tests/Makefile.am | 3 +- .../http/tests/connection_pool_unittests.cc | 185 ++++++++++++++++++ 3 files changed, 188 insertions(+), 2 deletions(-) create mode 100644 src/lib/http/tests/connection_pool_unittests.cc diff --git a/src/lib/http/connection_pool.h b/src/lib/http/connection_pool.h index a6dd556d64..8705651a4a 100644 --- a/src/lib/http/connection_pool.h +++ b/src/lib/http/connection_pool.h @@ -46,7 +46,7 @@ public: /// @brief Stops all connections and removes them from the pool. void stopAll(); -private: +protected: /// @brief Set of connections. std::set connections_; diff --git a/src/lib/http/tests/Makefile.am b/src/lib/http/tests/Makefile.am index d962542f9f..d2c8ec3d48 100644 --- a/src/lib/http/tests/Makefile.am +++ b/src/lib/http/tests/Makefile.am @@ -20,7 +20,8 @@ TESTS = if HAVE_GTEST TESTS += libhttp_unittests -libhttp_unittests_SOURCES = date_time_unittests.cc +libhttp_unittests_SOURCES = connection_pool_unittests.cc +libhttp_unittests_SOURCES += date_time_unittests.cc libhttp_unittests_SOURCES += listener_unittests.cc libhttp_unittests_SOURCES += post_request_json_unittests.cc libhttp_unittests_SOURCES += request_parser_unittests.cc diff --git a/src/lib/http/tests/connection_pool_unittests.cc b/src/lib/http/tests/connection_pool_unittests.cc new file mode 100644 index 0000000000..1901237117 --- /dev/null +++ b/src/lib/http/tests/connection_pool_unittests.cc @@ -0,0 +1,185 @@ +// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace isc::asiolink; +using namespace isc::http; +using namespace isc::http::test; + +namespace { + +/// @brief Test HTTP response. +typedef TestHttpResponseBase Response; + +/// @brief Pointer to test HTTP response. +typedef boost::shared_ptr ResponsePtr; + +/// @brief Implementation of the @ref HttpResponseCreator. +class TestHttpResponseCreator : public HttpResponseCreator { +public: + + /// @brief Create a new request. + /// + /// @return Pointer to the new instance of the @ref HttpRequest. + virtual HttpRequestPtr + createNewHttpRequest() const { + return (HttpRequestPtr(new PostHttpRequestJson())); + } + +private: + + /// @brief Creates HTTP response. + /// + /// @param request Pointer to the HTTP request. + /// @return Pointer to the generated HTTP response. + virtual HttpResponsePtr + createStockHttpResponse(const ConstHttpRequestPtr& request, + const HttpStatusCode& status_code) const { + // The request hasn't been finalized so the request object + // doesn't contain any information about the HTTP version number + // used. But, the context should have this data (assuming the + // HTTP version is parsed ok). + HttpVersion http_version(request->context()->http_version_major_, + request->context()->http_version_minor_); + // This will generate the response holding JSON content. + ResponsePtr response(new Response(http_version, status_code)); + return (response); + } + + /// @brief Creates HTTP response. + /// + /// @param request Pointer to the HTTP request. + /// @return Pointer to the generated HTTP OK response with no content. + virtual HttpResponsePtr + createDynamicHttpResponse(const ConstHttpRequestPtr& request) { + // The simplest thing is to create a response with no content. + // We don't need content to test our class. + ResponsePtr response(new Response(request->getHttpVersion(), + HttpStatusCode::OK)); + return (response); + } +}; + +/// @brief Derivation of @ref HttpConnectionPool exposing protected member. +class TestHttpConnectionPool : public HttpConnectionPool { +public: + + using HttpConnectionPool::connections_; + +}; + +/// @brief Test fixture class for @ref HttpConnectionPool. +class HttpConnectionPoolTest : public ::testing::Test { +public: + + /// @brief Constructor. + HttpConnectionPoolTest() + : io_service_(), acceptor_(io_service_), connection_pool_(), + response_creator_(new TestHttpResponseCreator()) { + } + + IOService io_service_; ///< IO service. + HttpAcceptor acceptor_; ///< Test acceptor. + HttpConnectionPool connection_pool_; ///< Test connection pool. + HttpResponseCreatorPtr response_creator_; ///< Test response creator. + +}; + +// This test verifies that connections can be added to the pool and removed. +TEST_F(HttpConnectionPoolTest, startStop) { + // Create two distinct connections. + HttpConnectionPtr conn1(new HttpConnection(io_service_, acceptor_, + connection_pool_, + response_creator_, + HttpAcceptorCallback(), + 1000)); + HttpConnectionPtr conn2(new HttpConnection(io_service_, acceptor_, + connection_pool_, + response_creator_, + HttpAcceptorCallback(), + 1000)); + // The pool should be initally empty. + TestHttpConnectionPool pool; + ASSERT_TRUE(pool.connections_.empty()); + + // Start first connection and check that it has been added to the pool. + ASSERT_NO_THROW(pool.start(conn1)); + ASSERT_EQ(1, pool.connections_.size()); + ASSERT_EQ(1, pool.connections_.count(conn1)); + + // Start second connection and check that it also has been added. + ASSERT_NO_THROW(pool.start(conn2)); + ASSERT_EQ(2, pool.connections_.size()); + ASSERT_EQ(1, pool.connections_.count(conn2)); + + // Stop first connection. + ASSERT_NO_THROW(pool.stop(conn1)); + ASSERT_EQ(1, pool.connections_.size()); + // Check that it has been removed but the second connection is still there. + ASSERT_EQ(0, pool.connections_.count(conn1)); + ASSERT_EQ(1, pool.connections_.count(conn2)); + + // Remove second connection and verify. + ASSERT_NO_THROW(pool.stop(conn2)); + EXPECT_TRUE(pool.connections_.empty()); +} + +// Check that all connections can be remove with a single call. +TEST_F(HttpConnectionPoolTest, stopAll) { + HttpConnectionPtr conn1(new HttpConnection(io_service_, acceptor_, + connection_pool_, + response_creator_, + HttpAcceptorCallback(), + 1000)); + HttpConnectionPtr conn2(new HttpConnection(io_service_, acceptor_, + connection_pool_, + response_creator_, + HttpAcceptorCallback(), + 1000)); + TestHttpConnectionPool pool; + ASSERT_NO_THROW(pool.start(conn1)); + ASSERT_NO_THROW(pool.start(conn2)); + + // There are two distinct connections in the pool. + ASSERT_EQ(2, pool.connections_.size()); + + // This should remove all connections. + ASSERT_NO_THROW(pool.stopAll()); + EXPECT_TRUE(pool.connections_.empty()); +} + +// Check that stopping non-existing connection is no-op. +TEST_F(HttpConnectionPoolTest, stopInvalid) { + HttpConnectionPtr conn1(new HttpConnection(io_service_, acceptor_, + connection_pool_, + response_creator_, + HttpAcceptorCallback(), + 1000)); + HttpConnectionPtr conn2(new HttpConnection(io_service_, acceptor_, + connection_pool_, + response_creator_, + HttpAcceptorCallback(), + 1000)); + TestHttpConnectionPool pool; + ASSERT_NO_THROW(pool.start(conn1)); + ASSERT_NO_THROW(pool.stop(conn2)); + ASSERT_EQ(1, pool.connections_.size()); + ASSERT_EQ(1, pool.connections_.count(conn1)); +} + +} -- 2.47.3