diff options
Diffstat (limited to 'src/lib/util/tests/thread_pool_unittest.cc')
-rw-r--r-- | src/lib/util/tests/thread_pool_unittest.cc | 804 |
1 files changed, 804 insertions, 0 deletions
diff --git a/src/lib/util/tests/thread_pool_unittest.cc b/src/lib/util/tests/thread_pool_unittest.cc new file mode 100644 index 0000000..976960a --- /dev/null +++ b/src/lib/util/tests/thread_pool_unittest.cc @@ -0,0 +1,804 @@ +// Copyright (C) 2018-2024 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 <gtest/gtest.h> + +#include <exceptions/exceptions.h> +#include <util/thread_pool.h> + +#include <signal.h> + +using namespace isc; +using namespace isc::util; +using namespace std; + +namespace { + +/// @brief define CallBack type +typedef function<void()> CallBack; + +/// @brief Test Fixture for testing isc::dhcp::ThreadPool +class ThreadPoolTest : public ::testing::Test { +public: + /// @brief Constructor + ThreadPoolTest() : thread_count_(0), count_(0), wait_(false) { + } + + /// @brief task function which registers the thread id and signals main + /// thread to stop waiting and then waits for main thread to signal to exit + void runAndWait() { + // run task + run(); + // wait for main thread signal to exit + unique_lock<mutex> lk(wait_mutex_); + wait_cv_.wait(lk, [&]() {return (wait() == false);}); + } + + /// @brief task function which registers the thread id and signals main + /// thread to stop waiting + void run() { + { + // make sure this thread has started and it is accounted for + lock_guard<mutex> lk(mutex_); + auto id = this_thread::get_id(); + // register this thread as doing work on items + ids_.emplace(id); + // finish task + ++count_; + // register this task on the history of this thread + history_[id].push_back(count_); + } + // wake main thread if it is waiting for this thread to process + cv_.notify_all(); + } + + /// @brief task function which tries to stop the thread pool and then calls + /// @ref runAndWait + /// + /// @param thread_pool the thread pool + void runStopResetAndWait(ThreadPool<CallBack>* thread_pool) { + EXPECT_THROW(thread_pool->stop(), MultiThreadingInvalidOperation); + EXPECT_THROW(thread_pool->reset(), MultiThreadingInvalidOperation); + EXPECT_THROW(thread_pool->wait(), MultiThreadingInvalidOperation); + EXPECT_THROW(thread_pool->wait(0), MultiThreadingInvalidOperation); + sigset_t nsset; + pthread_sigmask(SIG_SETMASK, 0, &nsset); + EXPECT_EQ(1, sigismember(&nsset, SIGCHLD)); + EXPECT_EQ(1, sigismember(&nsset, SIGINT)); + EXPECT_EQ(1, sigismember(&nsset, SIGHUP)); + EXPECT_EQ(1, sigismember(&nsset, SIGTERM)); + EXPECT_NO_THROW(runAndWait()); + } + + /// @brief reset all counters and internal test state + /// + /// @param thread_count number of threads + void reset(uint32_t thread_count) { + // stop test threads + stopThreads(); + // reset the internal state of the test + thread_count_ = thread_count; + count_ = 0; + wait_ = true; + ids_.clear(); + history_.clear(); + } + + /// @brief start test threads and block main thread until all tasks have + /// been processed + /// + /// @param thread_count number of threads to be started + /// @param items_count number of items to wait for being processed + /// @param start create processing threads + /// @param signal give main thread control over the threads exit + void waitTasks(uint32_t thread_count, uint32_t items_count, + bool start = false, bool signal = true) { + // make sure we have all threads running when performing all the checks + unique_lock<mutex> lck(mutex_); + if (start) { + // start test threads if explicitly specified + startThreads(thread_count, signal); + } + // wait for the threads to process all the items + cv_.wait(lck, [&]() {return (count() == items_count);}); + } + + /// @brief start test threads + /// + /// @param thread_count number of threads to be started + /// @param signal give main thread control over the threads exit + void startThreads(uint32_t thread_count, bool signal = true) { + // set default task function to wait for main thread signal + auto runFunction = &ThreadPoolTest::runAndWait; + if (!signal) { + // set the task function to finish immediately + runFunction = &ThreadPoolTest::run; + } + // start test threads + for (uint32_t i = 0; i < thread_count; ++i) { + threads_.push_back(boost::make_shared<std::thread>(runFunction, this)); + } + } + + /// @brief stop test threads + void stopThreads() { + // signal threads that are waiting + signalThreads(); + // wait for all test threads to exit + for (auto const& thread : threads_) { + thread->join(); + } + // reset all threads + threads_.clear(); + } + + /// @brief function used by main thread to unblock processing threads + void signalThreads() { + { + lock_guard<mutex> lk(wait_mutex_); + // clear the wait flag so that threads will no longer wait for the main + // thread signal + wait_ = false; + } + // wake all threads if waiting for main thread signal + wait_cv_.notify_all(); + } + + /// @brief number of completed tasks + /// + /// @return the number of completed tasks + uint32_t count() { + return (count_); + } + + /// @brief flag which indicates if working thread should wait for main + /// thread signal + /// + /// @return the wait flag + bool wait() { + return (wait_); + } + + /// @brief check the total number of tasks that have been processed + /// Some of the tasks may have been run on the same thread and none may have + /// been processed by other threads + /// + /// @param items_count the number of tasks + void checkRunHistory(uint32_t items_count) { + uint32_t count = 0; + // iterate over all threads history and count all the processed tasks + for (auto const& element : history_) { + count += element.second.size(); + } + ASSERT_EQ(count, items_count); + } + + /// @brief check the total number of threads that have processed tasks + /// + /// @param number of threads processing tasks + void checkIds(uint32_t count) { + ASSERT_EQ(ids_.size(), count); + } + + /// @brief check the thread pool state + /// + /// @param thread_pool the thread pool + /// @param count the number of tasks + /// @param size the thread pool size + void checkState(ThreadPool<CallBack>& thread_pool, uint32_t count, uint32_t size) { + // the item count should match + ASSERT_EQ(thread_pool.count(), count); + // the thread count should match + ASSERT_EQ(thread_pool.size(), size); + } + +private: + /// @brief thread count used by the test + uint32_t thread_count_; + + /// @brief mutex used to keep the internal state consistent + std::mutex mutex_; + + /// @brief condition variable used to signal main thread that all threads + /// have started processing + condition_variable cv_; + + /// @brief mutex used to keep the internal state consistent + /// related to the control of the main thread over the working threads exit + std::mutex wait_mutex_; + + /// @brief condition variable used to signal working threads to exit + condition_variable wait_cv_; + + /// @brief number of completed tasks + uint32_t count_; + + /// @brief flag which indicates if working thread should wait for main + /// thread signal + bool wait_; + + /// @brief the set of thread ids which have completed tasks + set<std::thread::id> ids_; + + /// @brief the list of completed tasks run by each thread + map<std::thread::id, list<uint32_t>> history_; + + /// @brief the list of test threads + list<boost::shared_ptr<std::thread>> threads_; +}; + +/// @brief test ThreadPool add and count +TEST_F(ThreadPoolTest, addAndCount) { + uint32_t items_count; + CallBack call_back; + ThreadPool<CallBack> thread_pool; + checkState(thread_pool, 0, 0); + + items_count = 4; + + call_back = std::bind(&ThreadPoolTest::run, this); + + // add items to stopped thread pool + for (uint32_t i = 0; i < items_count; ++i) { + bool ret = true; + EXPECT_NO_THROW(ret = thread_pool.add(boost::make_shared<CallBack>(call_back))); + EXPECT_TRUE(ret); + } + + // the item count should match + ASSERT_EQ(thread_pool.count(), items_count); + + // calling reset should clear all threads and should remove all queued items + EXPECT_NO_THROW(thread_pool.reset()); + checkState(thread_pool, 0, 0); +} + +/// @brief test ThreadPool start and stop +TEST_F(ThreadPoolTest, startAndStop) { + uint32_t items_count; + uint32_t thread_count; + CallBack call_back; + ThreadPool<CallBack> thread_pool; + checkState(thread_pool, 0, 0); + + items_count = 4; + thread_count = 4; + // prepare setup + reset(thread_count); + + // create tasks which block thread pool threads until signaled by main + // thread to force all threads of the thread pool to run exactly one task + call_back = std::bind(&ThreadPoolTest::runAndWait, this); + + // calling start should create the threads and should keep the queued items + EXPECT_THROW(thread_pool.start(0), InvalidParameter); + // calling start should create the threads and should keep the queued items + EXPECT_NO_THROW(thread_pool.start(thread_count)); + checkState(thread_pool, 0, thread_count); + + // do it once again to check if it works + EXPECT_THROW(thread_pool.start(thread_count), InvalidOperation); + checkState(thread_pool, 0, thread_count); + + // calling stop should clear all threads and should keep queued items + EXPECT_NO_THROW(thread_pool.stop()); + checkState(thread_pool, 0, 0); + + // do it once again to check if it works + EXPECT_THROW(thread_pool.stop(), InvalidOperation); + checkState(thread_pool, 0, 0); + + // add items to stopped thread pool + for (uint32_t i = 0; i < items_count; ++i) { + bool ret = true; + EXPECT_NO_THROW(ret = thread_pool.add(boost::make_shared<CallBack>(call_back))); + EXPECT_TRUE(ret); + } + + checkState(thread_pool, items_count, 0); + + // calling stop should clear all threads and should keep queued items + EXPECT_THROW(thread_pool.stop(), InvalidOperation); + checkState(thread_pool, items_count, 0); + + // calling reset should clear all threads and should remove all queued items + EXPECT_NO_THROW(thread_pool.reset()); + checkState(thread_pool, 0, 0); + + // do it once again to check if it works + EXPECT_NO_THROW(thread_pool.reset()); + checkState(thread_pool, 0, 0); + + // calling start should create the threads and should keep the queued items + EXPECT_NO_THROW(thread_pool.start(thread_count)); + checkState(thread_pool, 0, thread_count); + + // add items to running thread pool + for (uint32_t i = 0; i < items_count; ++i) { + bool ret = true; + EXPECT_NO_THROW(ret = thread_pool.add(boost::make_shared<CallBack>(call_back))); + EXPECT_TRUE(ret); + } + + // wait for all items to be processed + waitTasks(thread_count, items_count); + checkState(thread_pool, 0, thread_count); + // as each thread pool thread is still waiting on main to unblock, each + // thread should have been registered in ids list + checkIds(items_count); + // all items should have been processed + ASSERT_EQ(count(), items_count); + + // check that the number of processed tasks matches the number of items + checkRunHistory(items_count); + + // signal thread pool tasks to continue + signalThreads(); + + // calling stop should clear all threads and should keep queued items + EXPECT_NO_THROW(thread_pool.stop()); + checkState(thread_pool, 0, 0); + + items_count = 64; + thread_count = 16; + // prepare setup + reset(thread_count); + + // create tasks which do not block the thread pool threads so that several + // tasks can be run on the same thread and some of the threads never even + // having a chance to run + call_back = std::bind(&ThreadPoolTest::run, this); + + // add items to stopped thread pool + for (uint32_t i = 0; i < items_count; ++i) { + bool ret = true; + EXPECT_NO_THROW(ret = thread_pool.add(boost::make_shared<CallBack>(call_back))); + EXPECT_TRUE(ret); + } + + checkState(thread_pool, items_count, 0); + + // calling start should create the threads and should keep the queued items + EXPECT_NO_THROW(thread_pool.start(thread_count)); + // the thread count should match + ASSERT_EQ(thread_pool.size(), thread_count); + + // wait for all items to be processed + waitTasks(thread_count, items_count); + checkState(thread_pool, 0, thread_count); + // all items should have been processed + ASSERT_EQ(count(), items_count); + + // check that the number of processed tasks matches the number of items + checkRunHistory(items_count); + + // calling stop should clear all threads and should keep queued items + EXPECT_NO_THROW(thread_pool.stop()); + checkState(thread_pool, 0, 0); + + items_count = 16; + thread_count = 16; + // prepare setup + reset(thread_count); + + // create tasks which try to stop the thread pool and then block thread pool + // threads until signaled by main thread to force all threads of the thread + // pool to run exactly one task + call_back = std::bind(&ThreadPoolTest::runStopResetAndWait, this, &thread_pool); + + // calling start should create the threads and should keep the queued items + EXPECT_NO_THROW(thread_pool.start(thread_count)); + checkState(thread_pool, 0, thread_count); + + // add items to running thread pool + for (uint32_t i = 0; i < items_count; ++i) { + bool ret = true; + EXPECT_NO_THROW(ret = thread_pool.add(boost::make_shared<CallBack>(call_back))); + EXPECT_TRUE(ret); + } + + // wait for all items to be processed + waitTasks(thread_count, items_count); + checkState(thread_pool, 0, thread_count); + // as each thread pool thread is still waiting on main to unblock, each + // thread should have been registered in ids list + checkIds(items_count); + // all items should have been processed + ASSERT_EQ(count(), items_count); + + // check that the number of processed tasks matches the number of items + checkRunHistory(items_count); + + // signal thread pool tasks to continue + signalThreads(); + + // calling stop should clear all threads and should keep queued items + EXPECT_NO_THROW(thread_pool.stop()); + checkState(thread_pool, 0, 0); + + /// statistics + std::cout << "stat10: " << thread_pool.getQueueStat(10) << std::endl; + std::cout << "stat100: " << thread_pool.getQueueStat(100) << std::endl; + std::cout << "stat1000: " << thread_pool.getQueueStat(1000) << std::endl; +} + +/// @brief test ThreadPool wait +TEST_F(ThreadPoolTest, wait) { + uint32_t items_count; + uint32_t thread_count; + CallBack call_back; + ThreadPool<CallBack> thread_pool; + checkState(thread_pool, 0, 0); + + // calling wait should do nothing if not started + EXPECT_NO_THROW(thread_pool.wait()); + checkState(thread_pool, 0, 0); + + // do it once again to check if it works + EXPECT_NO_THROW(thread_pool.wait()); + checkState(thread_pool, 0, 0); + + items_count = 16; + thread_count = 16; + // prepare setup + reset(thread_count); + + // create tasks which block thread pool threads until signaled by main + // thread to force all threads of the thread pool to run exactly one task + call_back = std::bind(&ThreadPoolTest::runAndWait, this); + + // add items to stopped thread pool + for (uint32_t i = 0; i < items_count; ++i) { + bool ret = true; + EXPECT_NO_THROW(ret = thread_pool.add(boost::make_shared<CallBack>(call_back))); + EXPECT_TRUE(ret); + } + + checkState(thread_pool, items_count, 0); + + // calling start should create the threads and should keep the queued items + EXPECT_NO_THROW(thread_pool.start(thread_count)); + // the thread count should match + ASSERT_EQ(thread_pool.size(), thread_count); + + // wait for all items to be processed + waitTasks(thread_count, items_count); + checkState(thread_pool, 0, thread_count); + // as each thread pool thread is still waiting on main to unblock, each + // thread should have been registered in ids list + checkIds(items_count); + // all items should have been processed + ASSERT_EQ(count(), items_count); + + // check that the number of processed tasks matches the number of items + checkRunHistory(items_count); + + // check that waiting on tasks does timeout + ASSERT_FALSE(thread_pool.wait(1)); + + // signal thread pool tasks to continue + signalThreads(); + + // calling stop should clear all threads and should keep queued items + EXPECT_NO_THROW(thread_pool.stop()); + checkState(thread_pool, 0, 0); + + items_count = 64; + thread_count = 16; + // prepare setup + reset(thread_count); + + // create tasks which do not block the thread pool threads so that several + // tasks can be run on the same thread and some of the threads never even + // having a chance to run + call_back = std::bind(&ThreadPoolTest::run, this); + + // add items to stopped thread pool + for (uint32_t i = 0; i < items_count; ++i) { + bool ret = true; + EXPECT_NO_THROW(ret = thread_pool.add(boost::make_shared<CallBack>(call_back))); + EXPECT_TRUE(ret); + } + + checkState(thread_pool, items_count, 0); + + // calling start should create the threads and should keep the queued items + EXPECT_NO_THROW(thread_pool.start(thread_count)); + // the thread count should match + ASSERT_EQ(thread_pool.size(), thread_count); + + // wait for all items to be processed + thread_pool.wait(); + checkState(thread_pool, 0, thread_count); + // all items should have been processed + ASSERT_EQ(count(), items_count); + + // check that the number of processed tasks matches the number of items + checkRunHistory(items_count); + + // calling stop should clear all threads and should keep queued items + EXPECT_NO_THROW(thread_pool.stop()); + checkState(thread_pool, 0, 0); + + items_count = 16; + thread_count = 256; + // prepare setup + reset(thread_count); + + // add items to stopped thread pool + for (uint32_t i = 0; i < items_count; ++i) { + bool ret = true; + EXPECT_NO_THROW(ret = thread_pool.add(boost::make_shared<CallBack>(call_back))); + EXPECT_TRUE(ret); + } + + checkState(thread_pool, items_count, 0); + + // calling start should create the threads and should keep the queued items + EXPECT_NO_THROW(thread_pool.start(thread_count)); + // the thread count should match + ASSERT_EQ(thread_pool.size(), thread_count); + + // calling stop should clear all threads and should keep queued items + EXPECT_NO_THROW(thread_pool.stop()); + checkState(thread_pool, 0, 0); + + // wait for all items to be processed + ASSERT_TRUE(thread_pool.wait(1)); + checkState(thread_pool, 0, 0); +} + +/// @brief test ThreadPool pause and resume +TEST_F(ThreadPoolTest, pauseAndResume) { + uint32_t items_count; + uint32_t thread_count; + CallBack call_back; + ThreadPool<CallBack> thread_pool; + checkState(thread_pool, 0, 0); + + items_count = 4; + thread_count = 4; + // prepare setup + reset(thread_count); + + // create tasks which block thread pool threads until signaled by main + // thread to force all threads of the thread pool to run exactly one task + call_back = std::bind(&ThreadPoolTest::runAndWait, this); + + // calling resume should do nothing if not started + EXPECT_NO_THROW(thread_pool.resume()); + checkState(thread_pool, 0, 0); + + // do it once again to check if it works + EXPECT_NO_THROW(thread_pool.resume()); + checkState(thread_pool, 0, 0); + + // calling pause should do nothing if not started + EXPECT_NO_THROW(thread_pool.pause()); + checkState(thread_pool, 0, 0); + + // do it once again to check if it works + EXPECT_NO_THROW(thread_pool.pause()); + checkState(thread_pool, 0, 0); + + // calling resume should do nothing if not started + EXPECT_NO_THROW(thread_pool.resume()); + checkState(thread_pool, 0, 0); + + // add items to stopped thread pool + for (uint32_t i = 0; i < items_count; ++i) { + bool ret = true; + EXPECT_NO_THROW(ret = thread_pool.add(boost::make_shared<CallBack>(call_back))); + EXPECT_TRUE(ret); + } + + checkState(thread_pool, items_count, 0); + + // calling pause should do nothing if not started + EXPECT_NO_THROW(thread_pool.pause()); + checkState(thread_pool, items_count, 0); + + // calling resume should do nothing if not started + EXPECT_NO_THROW(thread_pool.resume()); + checkState(thread_pool, items_count, 0); + + // calling pause should do nothing if not started + EXPECT_NO_THROW(thread_pool.pause()); + checkState(thread_pool, items_count, 0); + + // calling start should create the threads and should keep the queued items + EXPECT_NO_THROW(thread_pool.start(thread_count)); + checkState(thread_pool, items_count, thread_count); + + // calling resume should resume threads + EXPECT_NO_THROW(thread_pool.resume()); + // the thread count should match + ASSERT_EQ(thread_pool.size(), thread_count); + + // wait for all items to be processed + waitTasks(thread_count, items_count); + checkState(thread_pool, 0, thread_count); + // as each thread pool thread is still waiting on main to unblock, each + // thread should have been registered in ids list + checkIds(items_count); + // all items should have been processed + ASSERT_EQ(count(), items_count); + + // check that the number of processed tasks matches the number of items + checkRunHistory(items_count); + + // signal thread pool tasks to continue + signalThreads(); + + // do it once again to check if it works + EXPECT_NO_THROW(thread_pool.resume()); + checkState(thread_pool, 0, thread_count); + + // calling stop should clear all threads and should keep queued items + EXPECT_NO_THROW(thread_pool.stop()); + checkState(thread_pool, 0, 0); + + items_count = 64; + thread_count = 16; + // prepare setup + reset(thread_count); + + // create tasks which do not block the thread pool threads so that several + // tasks can be run on the same thread and some of the threads never even + // having a chance to run + call_back = std::bind(&ThreadPoolTest::run, this); + + // add items to stopped thread pool + for (uint32_t i = 0; i < items_count; ++i) { + bool ret = true; + EXPECT_NO_THROW(ret = thread_pool.add(boost::make_shared<CallBack>(call_back))); + EXPECT_TRUE(ret); + } + + checkState(thread_pool, items_count, 0); + + // calling start should create the threads and should keep the queued items + EXPECT_NO_THROW(thread_pool.start(thread_count)); + // the thread count should match + ASSERT_EQ(thread_pool.size(), thread_count); + + // wait for all items to be processed + waitTasks(thread_count, items_count); + checkState(thread_pool, 0, thread_count); + // all items should have been processed + ASSERT_EQ(count(), items_count); + + // check that the number of processed tasks matches the number of items + checkRunHistory(items_count); + + // calling pause should pause threads + EXPECT_NO_THROW(thread_pool.pause()); + checkState(thread_pool, 0, thread_count); + + // do it once again to check if it works + EXPECT_NO_THROW(thread_pool.pause()); + checkState(thread_pool, 0, thread_count); + + // prepare setup + reset(thread_count); + + // add items to paused thread pool + for (uint32_t i = 0; i < items_count; ++i) { + bool ret = true; + EXPECT_NO_THROW(ret = thread_pool.add(boost::make_shared<CallBack>(call_back))); + EXPECT_TRUE(ret); + } + + checkState(thread_pool, items_count, thread_count); + + // calling resume should resume threads + EXPECT_NO_THROW(thread_pool.resume()); + // the thread count should match + ASSERT_EQ(thread_pool.size(), thread_count); + + // wait for all items to be processed + waitTasks(thread_count, items_count); + checkState(thread_pool, 0, thread_count); + // all items should have been processed + ASSERT_EQ(count(), items_count); + + // check that the number of processed tasks matches the number of items + checkRunHistory(items_count); + + // calling stop should clear all threads and should keep queued items + EXPECT_NO_THROW(thread_pool.stop()); + checkState(thread_pool, 0, 0); +} + +/// @brief test ThreadPool max queue size +TEST_F(ThreadPoolTest, maxQueueSize) { + uint32_t items_count; + CallBack call_back; + ThreadPool<CallBack> thread_pool; + // the item count should be 0 + ASSERT_EQ(thread_pool.count(), 0); + // the thread count should be 0 + ASSERT_EQ(thread_pool.size(), 0); + + items_count = 20; + + call_back = std::bind(&ThreadPoolTest::run, this); + + // add items to stopped thread pool + bool ret = true; + for (uint32_t i = 0; i < items_count; ++i) { + EXPECT_NO_THROW(ret = thread_pool.add(boost::make_shared<CallBack>(call_back))); + EXPECT_TRUE(ret); + } + + // the item count should match + ASSERT_EQ(thread_pool.count(), items_count); + + // change the max count + ASSERT_EQ(thread_pool.getMaxQueueSize(), 0); + size_t max_queue_size = 10; + thread_pool.setMaxQueueSize(max_queue_size); + EXPECT_EQ(thread_pool.getMaxQueueSize(), max_queue_size); + + // adding an item should squeeze the queue + EXPECT_EQ(thread_pool.count(), items_count); + EXPECT_NO_THROW(ret = thread_pool.add(boost::make_shared<CallBack>(call_back))); + EXPECT_FALSE(ret); + EXPECT_EQ(thread_pool.count(), max_queue_size); +} + +/// @brief test ThreadPool add front. +TEST_F(ThreadPoolTest, addFront) { + uint32_t items_count; + CallBack call_back; + ThreadPool<CallBack> thread_pool; + // the item count should be 0 + ASSERT_EQ(thread_pool.count(), 0); + // the thread count should be 0 + ASSERT_EQ(thread_pool.size(), 0); + + items_count = 20; + + call_back = std::bind(&ThreadPoolTest::run, this); + + // add items to stopped thread pool + bool ret = true; + for (uint32_t i = 0; i < items_count; ++i) { + EXPECT_NO_THROW(ret = thread_pool.addFront(boost::make_shared<CallBack>(call_back))); + EXPECT_TRUE(ret); + } + + // the item count should match + ASSERT_EQ(thread_pool.count(), items_count); + + // change the max count + ASSERT_EQ(thread_pool.getMaxQueueSize(), 0); + size_t max_queue_size = 10; + thread_pool.setMaxQueueSize(max_queue_size); + EXPECT_EQ(thread_pool.getMaxQueueSize(), max_queue_size); + + // adding an item at front should change nothing queue + EXPECT_EQ(thread_pool.count(), items_count); + EXPECT_NO_THROW(ret = thread_pool.addFront(boost::make_shared<CallBack>(call_back))); + EXPECT_FALSE(ret); + EXPECT_EQ(thread_pool.count(), items_count); +} + +/// @brief test ThreadPool get queue statistics. +TEST_F(ThreadPoolTest, getQueueStat) { + ThreadPool<CallBack> thread_pool; + EXPECT_THROW(thread_pool.getQueueStat(0), InvalidParameter); + EXPECT_THROW(thread_pool.getQueueStat(1), InvalidParameter); + EXPECT_THROW(thread_pool.getQueueStat(-10), InvalidParameter); + EXPECT_THROW(thread_pool.getQueueStat(10000), InvalidParameter); + EXPECT_NO_THROW(thread_pool.getQueueStat(10)); + EXPECT_NO_THROW(thread_pool.getQueueStat(100)); + EXPECT_NO_THROW(thread_pool.getQueueStat(1000)); +} + +} // namespace |