summaryrefslogtreecommitdiffstats
path: root/src/lib/http/tests/http_thread_pool_unittests.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/http/tests/http_thread_pool_unittests.cc')
-rw-r--r--src/lib/http/tests/http_thread_pool_unittests.cc265
1 files changed, 265 insertions, 0 deletions
diff --git a/src/lib/http/tests/http_thread_pool_unittests.cc b/src/lib/http/tests/http_thread_pool_unittests.cc
new file mode 100644
index 0000000..aa08ada
--- /dev/null
+++ b/src/lib/http/tests/http_thread_pool_unittests.cc
@@ -0,0 +1,265 @@
+// Copyright (C) 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/interval_timer.h>
+#include <asiolink/io_service.h>
+#include <exceptions/exceptions.h>
+#include <http/http_thread_pool.h>
+#include <testutils/gtest_utils.h>
+
+#include <gtest/gtest.h>
+#include <string>
+
+using namespace isc;
+using namespace isc::asiolink;
+using namespace isc::http;
+
+namespace {
+
+/// @brief Test timeout (ms).
+const long TEST_TIMEOUT = 10000;
+
+/// @brief Simple test fixture for testing HttpThreadPool.
+class HttpThreadPoolTest : public ::testing::Test {
+public:
+ /// @brief Constructor.
+ HttpThreadPoolTest()
+ : io_service_(new IOService()) {
+ }
+
+ /// @brief Destructor.
+ virtual ~HttpThreadPoolTest() {
+ io_service_->stop();
+ }
+
+ /// @brief IOService instance used by thread pools.
+ IOServicePtr io_service_;
+};
+
+// URL contains scheme and hostname.
+TEST_F(HttpThreadPoolTest, invalidConstruction) {
+ HttpThreadPoolPtr pool;
+
+ // Constructing with pool size of 0 should fail.
+ ASSERT_THROW_MSG(pool.reset(new HttpThreadPool(io_service_, 0)), BadValue,
+ "pool_size must be non 0");
+}
+
+// Verifies that a pool can be created without starting it.
+TEST_F(HttpThreadPoolTest, deferredStartConstruction) {
+ HttpThreadPoolPtr pool;
+
+ ASSERT_NO_THROW_LOG(pool.reset(new HttpThreadPool(io_service_, 3, true)));
+
+ // State should be stopped.
+ // Pool size should be 3.
+ // IOService should be there.
+ // IOService is new, so it should not be stopped.
+ // No threads in the pool.
+ ASSERT_TRUE(pool->isStopped());
+ EXPECT_EQ(pool->getPoolSize(), 3);
+ ASSERT_TRUE(pool->getIOService());
+ EXPECT_FALSE(pool->getIOService()->stopped());
+ EXPECT_EQ(pool->getThreadCount(), 0);
+
+ // Destructor should not throw.
+ ASSERT_NO_THROW_LOG(pool.reset());
+}
+
+// Verifies that a pool can be started within the constructor.
+TEST_F(HttpThreadPoolTest, startDuringConstruction) {
+ HttpThreadPoolPtr pool;
+
+ ASSERT_NO_THROW_LOG(pool.reset(new HttpThreadPool(io_service_, 3)));
+
+ // State should be running.
+ // Pool size should be 3.
+ // IOService should be there.
+ // IOService is new, so it should not be stopped.
+ // Should have 3 threads in the pool.
+ ASSERT_TRUE(pool->isRunning());
+ EXPECT_EQ(pool->getPoolSize(), 3);
+ ASSERT_TRUE(pool->getIOService());
+ EXPECT_FALSE(pool->getIOService()->stopped());
+ EXPECT_EQ(pool->getThreadCount(), 3);
+
+ // Destructor should not throw.
+ ASSERT_NO_THROW_LOG(pool.reset());
+}
+
+// Verifies that pool can move from STOPPED to RUNNING.
+TEST_F(HttpThreadPoolTest, stoppedToRunning) {
+ HttpThreadPoolPtr pool;
+
+ // Create a stopped pool.
+ ASSERT_NO_THROW_LOG(pool.reset(new HttpThreadPool(io_service_, 3, true)));
+ ASSERT_TRUE(pool->isStopped());
+
+ // Call run from STOPPED.
+ ASSERT_NO_THROW_LOG(pool->run());
+
+ // State should be RUNNING, IOService should not be stopped, we should
+ // have 3 threads in the pool.
+ ASSERT_TRUE(pool->isRunning());
+ EXPECT_FALSE(pool->getIOService()->stopped());
+ EXPECT_EQ(pool->getThreadCount(), 3);
+
+ // Calling run again should be harmless.
+ ASSERT_NO_THROW_LOG(pool->run());
+
+ // State should be RUNNING, IOService should not be stopped, we should
+ // have 3 threads in the pool.
+ ASSERT_TRUE(pool->isRunning());
+ EXPECT_FALSE(pool->getIOService()->stopped());
+ EXPECT_EQ(pool->getThreadCount(), 3);
+
+ // Destroying the pool should be fine.
+ ASSERT_NO_THROW_LOG(pool.reset());
+}
+
+// Verifies that pool can move from RUNNING to STOPPED.
+TEST_F(HttpThreadPoolTest, runningToStopped) {
+ HttpThreadPoolPtr pool;
+
+ // Create a running pool.
+ ASSERT_NO_THROW_LOG(pool.reset(new HttpThreadPool(io_service_, 3, false)));
+ ASSERT_TRUE(pool->isRunning());
+
+ // Call stop.
+ ASSERT_NO_THROW_LOG(pool->stop());
+
+ // State should be STOPPED, IOService should be stopped, we should
+ // have 0 threads in the pool.
+ ASSERT_TRUE(pool->isStopped());
+ EXPECT_TRUE(pool->getIOService()->stopped());
+ EXPECT_EQ(pool->getThreadCount(), 0);
+
+ // Calling stop again should be harmless.
+ ASSERT_NO_THROW_LOG(pool->stop());
+
+ // State should be STOPPED, IOService should be stopped, we should
+ // have 0 threads in the pool.
+ ASSERT_TRUE(pool->isStopped());
+ EXPECT_TRUE(pool->getIOService()->stopped());
+ EXPECT_EQ(pool->getThreadCount(), 0);
+
+ // Destroying the pool should be fine.
+ ASSERT_NO_THROW_LOG(pool.reset());
+}
+
+// Verifies that pool can move from RUNNING to PAUSED.
+TEST_F(HttpThreadPoolTest, runningToPaused) {
+ HttpThreadPoolPtr pool;
+
+ // Create a running pool.
+ ASSERT_NO_THROW_LOG(pool.reset(new HttpThreadPool(io_service_, 3, false)));
+ ASSERT_TRUE(pool->isRunning());
+
+ // Call pause from RUNNING.
+ ASSERT_NO_THROW_LOG(pool->pause());
+
+ // State should be PAUSED, IOService should be stopped, we should
+ // have 3 threads in the pool.
+ ASSERT_TRUE(pool->isPaused());
+ EXPECT_TRUE(pool->getIOService()->stopped());
+ EXPECT_EQ(pool->getThreadCount(), 3);
+
+ // Calling pause again should be harmless.
+ ASSERT_NO_THROW_LOG(pool->pause());
+
+ // State should be PAUSED, IOService should be stopped, we should
+ // have 3 threads in the pool.
+ ASSERT_TRUE(pool->isPaused());
+ EXPECT_TRUE(pool->getIOService()->stopped());
+ EXPECT_EQ(pool->getThreadCount(), 3);
+
+ // Destroying the pool should be fine.
+ ASSERT_NO_THROW_LOG(pool.reset());
+}
+
+// Verifies that pool can move from PAUSED to RUNNING.
+TEST_F(HttpThreadPoolTest, pausedToRunning) {
+ HttpThreadPoolPtr pool;
+
+ // Create a running pool.
+ ASSERT_NO_THROW_LOG(pool.reset(new HttpThreadPool(io_service_, 3, false)));
+ ASSERT_TRUE(pool->isRunning());
+
+ // Call pause from RUNNING.
+ ASSERT_NO_THROW_LOG(pool->pause());
+ ASSERT_TRUE(pool->isPaused());
+
+ // Call run.
+ ASSERT_NO_THROW_LOG(pool->run());
+
+ // State should be RUNNING, IOService should not be stopped, we should
+ // have 3 threads in the pool.
+ ASSERT_TRUE(pool->isRunning());
+ EXPECT_FALSE(pool->getIOService()->stopped());
+ EXPECT_EQ(pool->getThreadCount(), 3);
+
+ // Destroying the pool should be fine.
+ ASSERT_NO_THROW_LOG(pool.reset());
+}
+
+// Verifies that pool can move from PAUSED to STOPPED.
+TEST_F(HttpThreadPoolTest, pausedToStopped) {
+ HttpThreadPoolPtr pool;
+
+ // Create a running pool.
+ ASSERT_NO_THROW_LOG(pool.reset(new HttpThreadPool(io_service_, 3, false)));
+ ASSERT_TRUE(pool->isRunning());
+
+ // Call pause from RUNNING.
+ ASSERT_NO_THROW_LOG(pool->pause());
+ ASSERT_TRUE(pool->isPaused());
+
+ // Call stop.
+ ASSERT_NO_THROW_LOG(pool->stop());
+
+ // State should be STOPPED, IOService should be stopped, we should
+ // have 0 threads in the pool.
+ ASSERT_TRUE(pool->isStopped());
+ EXPECT_TRUE(pool->getIOService()->stopped());
+ EXPECT_EQ(pool->getThreadCount(), 0);
+
+ // Destroying the pool should be fine.
+ ASSERT_NO_THROW_LOG(pool.reset());
+}
+
+// Verifies that attempting to pause a STOPPED pool has no effect.
+TEST_F(HttpThreadPoolTest, stoppedToPaused) {
+ HttpThreadPoolPtr pool;
+
+ // Create a stopped pool.
+ ASSERT_NO_THROW_LOG(pool.reset(new HttpThreadPool(io_service_, 3, true)));
+ ASSERT_TRUE(pool->isStopped());
+
+ // State should be STOPPED, IOService won't be stopped because it was
+ // never started. We should have 0 threads in the pool.
+ ASSERT_TRUE(pool->isStopped());
+ EXPECT_FALSE(pool->getIOService()->stopped());
+ EXPECT_EQ(pool->getThreadCount(), 0);
+
+ // Call pause from STOPPED.
+ ASSERT_NO_THROW_LOG(pool->pause());
+
+ // Should have no effect.
+ ASSERT_TRUE(pool->isStopped());
+
+ // State should be STOPPED, IOService won't be stopped because it was
+ // never started. We should have 0 threads in the pool.
+ ASSERT_TRUE(pool->isStopped());
+ EXPECT_FALSE(pool->getIOService()->stopped());
+ EXPECT_EQ(pool->getThreadCount(), 0);
+
+ // Destroying the pool should be fine.
+ ASSERT_NO_THROW_LOG(pool.reset());
+}
+
+}