summaryrefslogtreecommitdiffstats
path: root/src/lib/http/tests/connection_pool_unittests.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/http/tests/connection_pool_unittests.cc')
-rw-r--r--src/lib/http/tests/connection_pool_unittests.cc270
1 files changed, 270 insertions, 0 deletions
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 0000000..b8337c3
--- /dev/null
+++ b/src/lib/http/tests/connection_pool_unittests.cc
@@ -0,0 +1,270 @@
+// Copyright (C) 2017-2021 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 <config.h>
+#include <asiolink/asio_wrapper.h>
+#include <asiolink/io_service.h>
+#include <http/http_acceptor.h>
+#include <http/connection.h>
+#include <http/connection_pool.h>
+#include <http/post_request_json.h>
+#include <http/response_creator.h>
+#include <http/response_json.h>
+#include <http/tests/response_test.h>
+#include <util/multi_threading_mgr.h>
+
+#include <boost/shared_ptr.hpp>
+#include <gtest/gtest.h>
+#include <algorithm>
+
+using namespace isc::asiolink;
+using namespace isc::http;
+using namespace isc::http::test;
+using namespace isc::util;
+
+namespace {
+
+/// @brief Test HTTP response.
+typedef TestHttpResponseBase<HttpResponseJson> Response;
+
+/// @brief Pointer to test HTTP response.
+typedef boost::shared_ptr<Response> ResponsePtr;
+
+/// @brief Request timeout used in tests.
+const long CONN_REQUEST_TIMEOUT = 1000;
+
+/// @brief Idle connection timeout used in tests.
+const long CONN_IDLE_TIMEOUT = 1000;
+
+/// @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 HttpRequestPtr& 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(HttpRequestPtr 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 Checks if specified connection belongs to the pool.
+ bool hasConnection(const HttpConnectionPtr& conn) const {
+ return (std::find(connections_.begin(), connections_.end(), conn)
+ != connections_.end());
+ }
+
+};
+
+/// @brief Test fixture class for @ref HttpConnectionPool.
+class HttpConnectionPoolTest : public ::testing::Test {
+public:
+
+ /// @brief Constructor.
+ HttpConnectionPoolTest()
+ : io_service_(),
+ acceptor_(new HttpAcceptor(io_service_)),
+ connection_pool_(),
+ response_creator_(new TestHttpResponseCreator()) {
+ MultiThreadingMgr::instance().setMode(false);
+ }
+
+ /// @brief Destructor.
+ ~HttpConnectionPoolTest() {
+ MultiThreadingMgr::instance().setMode(false);
+ }
+
+ /// @brief Verifies that connections can be added to the pool and removed.
+ void startStopTest() {
+ // Create two distinct connections.
+ HttpConnectionPtr conn1(new HttpConnection(io_service_, acceptor_,
+ TlsContextPtr(),
+ connection_pool_,
+ response_creator_,
+ HttpAcceptorCallback(),
+ CONN_REQUEST_TIMEOUT,
+ CONN_IDLE_TIMEOUT));
+
+ HttpConnectionPtr conn2(new HttpConnection(io_service_, acceptor_,
+ TlsContextPtr(),
+ connection_pool_,
+ response_creator_,
+ HttpAcceptorCallback(),
+ CONN_REQUEST_TIMEOUT,
+ CONN_IDLE_TIMEOUT));
+ // The pool should be initially 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.hasConnection(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.hasConnection(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.hasConnection(conn1));
+ ASSERT_EQ(1, pool.hasConnection(conn2));
+
+ // Remove second connection and verify.
+ ASSERT_NO_THROW(pool.stop(conn2));
+ EXPECT_TRUE(pool.connections_.empty());
+ }
+
+ /// @brief Verifies that all connections can be remove with a single call.
+ void stopAllTest() {
+ // Create two distinct connections.
+ HttpConnectionPtr conn1(new HttpConnection(io_service_, acceptor_,
+ TlsContextPtr(),
+ connection_pool_,
+ response_creator_,
+ HttpAcceptorCallback(),
+ CONN_REQUEST_TIMEOUT,
+ CONN_IDLE_TIMEOUT));
+
+ HttpConnectionPtr conn2(new HttpConnection(io_service_, acceptor_,
+ TlsContextPtr(),
+ connection_pool_,
+ response_creator_,
+ HttpAcceptorCallback(),
+ CONN_REQUEST_TIMEOUT,
+ CONN_IDLE_TIMEOUT));
+ 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());
+ }
+
+ /// @brief Verifies that stopping a non-existing connection is no-op.
+ void stopInvalidTest() {
+ HttpConnectionPtr conn1(new HttpConnection(io_service_, acceptor_,
+ TlsContextPtr(),
+ connection_pool_,
+ response_creator_,
+ HttpAcceptorCallback(),
+ CONN_REQUEST_TIMEOUT,
+ CONN_IDLE_TIMEOUT));
+
+ HttpConnectionPtr conn2(new HttpConnection(io_service_, acceptor_,
+ TlsContextPtr(),
+ connection_pool_,
+ response_creator_,
+ HttpAcceptorCallback(),
+ CONN_REQUEST_TIMEOUT,
+ CONN_IDLE_TIMEOUT));
+ TestHttpConnectionPool pool;
+ ASSERT_NO_THROW(pool.start(conn1));
+ ASSERT_NO_THROW(pool.stop(conn2));
+ ASSERT_EQ(1, pool.connections_.size());
+ ASSERT_EQ(1, pool.hasConnection(conn1));
+ }
+
+ IOService io_service_; ///< IO service.
+ HttpAcceptorPtr acceptor_; ///< Test acceptor.
+ HttpConnectionPool connection_pool_; ///< Test connection pool.
+ HttpResponseCreatorPtr response_creator_; ///< Test response creator.
+
+};
+
+// Verifies that connections can be added to the pool and removed.
+// with MultiThreading disabled.
+TEST_F(HttpConnectionPoolTest, startStopTest) {
+ ASSERT_FALSE(MultiThreadingMgr::instance().getMode());
+ startStopTest();
+}
+
+// Verifies that connections can be added to the pool and removed
+// with MultiThreading enabled.
+TEST_F(HttpConnectionPoolTest, startStopTestMultiThreading) {
+ MultiThreadingMgr::instance().setMode(true);
+ startStopTest();
+}
+
+// Check that all connections can be remove with a single call.
+// with MultiThreading disabled.
+TEST_F(HttpConnectionPoolTest, stopAll) {
+ ASSERT_FALSE(MultiThreadingMgr::instance().getMode());
+ stopAllTest();
+}
+
+// Check that all connections can be remove with a single call
+// with MultiThreading enabled.
+TEST_F(HttpConnectionPoolTest, stopAllMultiThreading) {
+ MultiThreadingMgr::instance().setMode(true);
+ ASSERT_TRUE(MultiThreadingMgr::instance().getMode());
+ stopAllTest();
+}
+
+// Check that stopping non-existing connection is no-op.
+// with MultiThreading disabled.
+TEST_F(HttpConnectionPoolTest, stopInvalid) {
+ ASSERT_FALSE(MultiThreadingMgr::instance().getMode());
+ stopInvalidTest();
+}
+
+// Check that stopping non-existing connection is no-op.
+// with MultiThreading enabled.
+TEST_F(HttpConnectionPoolTest, stopInvalidMultiThreading) {
+ MultiThreadingMgr::instance().setMode(true);
+ ASSERT_TRUE(MultiThreadingMgr::instance().getMode());
+ stopInvalidTest();
+}
+
+}