From 21111b3e67e3e32881c743ada7a25c6e0d1b071e Mon Sep 17 00:00:00 2001 From: Ivan Pelipenko Date: Fri, 31 Jul 2020 15:47:08 +0300 Subject: [PATCH] move tests to separate dir create macro "pip_test()" for easily add new tests --- CMakeLists.txt | 34 +- tests/CMakeLists.txt | 15 + .../GTestCMakeLists.txt.in | 30 +- .../concurrent}/BlockingDequeueUnitTest.cpp | 528 +++++++++--------- .../ConditionLockIntegrationTest.cpp | 106 ++-- .../ConditionVariableIntegrationTest.cpp | 400 ++++++------- .../concurrent}/ExecutorIntegrationTest.cpp | 108 ++-- .../test => tests/concurrent}/testutil.h | 120 ++-- 8 files changed, 675 insertions(+), 666 deletions(-) create mode 100644 tests/CMakeLists.txt rename GTestCMakeLists.txt.in => tests/GTestCMakeLists.txt.in (97%) rename {lib/concurrent/test => tests/concurrent}/BlockingDequeueUnitTest.cpp (97%) rename {lib/concurrent/test => tests/concurrent}/ConditionLockIntegrationTest.cpp (95%) rename {lib/concurrent/test => tests/concurrent}/ConditionVariableIntegrationTest.cpp (96%) rename {lib/concurrent/test => tests/concurrent}/ExecutorIntegrationTest.cpp (96%) rename {lib/concurrent/test => tests/concurrent}/testutil.h (96%) diff --git a/CMakeLists.txt b/CMakeLists.txt index f530f135..678f5e13 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_policy(SET CMP0017 NEW) # need include() with .cmake project(pip) set(_PIP_MAJOR 1) set(_PIP_MINOR 99) -set(_PIP_REVISION 1) +set(_PIP_REVISION 2) set(_PIP_SUFFIX _prebeta) set(_PIP_COMPANY SHS) set(_PIP_DOMAIN org.SHS) @@ -98,11 +98,7 @@ set(PIP_OPENCL "no") set(PIP_LUA "no") set(PIP_IOUTILS "yes") set(PIP_UTILS_LIST) - -if (TESTS) - include(DownloadGTest) - set(PIP_CONCURRENT_TEST "lib/concurrent/test") -endif() +set(PIP_TESTS_LIST) if (DEFINED ENV{QNX_HOST} OR PIP_FREERTOS) set(STATIC_LIB ON) @@ -199,6 +195,11 @@ foreach(F ${PIP_FOLDERS}) include_directories("${PIP_SRC_MAIN}/${F}") gather_src("${PIP_SRC_MAIN}/${F}" CPP_LIB_MAIN HDRS PHDRS) endforeach(F) + +if (TESTS) + add_subdirectory(tests) +endif() + # Crypt lib gather_src("${PIP_SRC_CRYPT}" CPP_LIB_CRYPT HDRS PHDRS) @@ -226,11 +227,6 @@ gather_src("${PIP_SRC_CLOUD}" CPP_LIB_CLOUD HDRS PHDRS) # LUA lib gather_src("${PIP_SRC_LUA}" CPP_LIB_LUA HDRS PHDRS) -if (TESTS) - # Concurrent lib tests - gather_src("${PIP_CONCURRENT_TEST}" CPP_CONCURRENT_TEST HDRS PHDRS) -endif() - if(PIP_FREERTOS) add_definitions(-DPIP_FREERTOS) set(ICU OFF) @@ -579,15 +575,6 @@ if (NOT CROSSTOOLS) list(APPEND PIP_LIBS_TARGETS pip_io_utils) - # Enable build tests for concurrent module - if(PIP_CONCURRENT_TEST) - add_executable(pip_concurrent_test ${CPP_CONCURRENT_TEST}) - target_link_libraries(pip_concurrent_test pip gtest_main gmock_main) - add_test(NAME pip_concurrent_test COMMAND tests) - add_custom_target(pip_concurrent_test_perform ALL COMMAND pip_concurrent_test) - endif() - - # Build cloud library if crypt enabled if(sodium_FOUND) import_version(pip_cloud pip) @@ -800,6 +787,13 @@ message(" OpenCL : ${PIP_OPENCL}") message(" IOUtils : ${PIP_IOUTILS}") message(" Cloud : ${PIP_CLOUD}") message(" Lua : ${PIP_LUA}") +if (PIP_TESTS_LIST) + message("") + message(" Tests:") + foreach(_test ${PIP_TESTS_LIST}) + message(" * ${_test}") + endforeach() +endif() message("") message(" Utilites:") foreach(_util ${PIP_UTILS_LIST}) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 00000000..bcb399c3 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,15 @@ +include(DownloadGTest) + +macro(pip_test NAME LIBS) + gather_src("${NAME}" CPP_${NAME}_TEST _T_H _T_PH) + set(_target pip_${NAME}_test) + add_executable(${_target} ${CPP_${NAME}_TEST}) + target_link_libraries(${_target} pip ${LIBS} gtest_main gmock_main) + add_test(NAME ${_target} COMMAND tests) + add_custom_target(${_target}_perform ALL COMMAND ${_target}) + list(APPEND PIP_TESTS_LIST "${NAME}") + set(PIP_TESTS_LIST ${PIP_TESTS_LIST} PARENT_SCOPE) +endmacro() + +# Concurrent tests +pip_test(concurrent "") diff --git a/GTestCMakeLists.txt.in b/tests/GTestCMakeLists.txt.in similarity index 97% rename from GTestCMakeLists.txt.in rename to tests/GTestCMakeLists.txt.in index aacb573a..51b1cc0c 100644 --- a/GTestCMakeLists.txt.in +++ b/tests/GTestCMakeLists.txt.in @@ -1,16 +1,16 @@ -cmake_minimum_required(VERSION 2.8.2) - -project(googletest-download NONE) - -include(ExternalProject) -ExternalProject_Add(googletest - GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG "dea0216d0c6bc5e63cf5f6c8651cd268668032ec" - GIT_CONFIG "advice.detachedHead=false" - SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src" - BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build" - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" - TEST_COMMAND "" +cmake_minimum_required(VERSION 2.8.2) + +project(googletest-download NONE) + +include(ExternalProject) +ExternalProject_Add(googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG "dea0216d0c6bc5e63cf5f6c8651cd268668032ec" + GIT_CONFIG "advice.detachedHead=false" + SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src" + BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" ) \ No newline at end of file diff --git a/lib/concurrent/test/BlockingDequeueUnitTest.cpp b/tests/concurrent/BlockingDequeueUnitTest.cpp similarity index 97% rename from lib/concurrent/test/BlockingDequeueUnitTest.cpp rename to tests/concurrent/BlockingDequeueUnitTest.cpp index fb673059..fae9f3ff 100644 --- a/lib/concurrent/test/BlockingDequeueUnitTest.cpp +++ b/tests/concurrent/BlockingDequeueUnitTest.cpp @@ -1,264 +1,264 @@ -#include "gtest/gtest.h" -#include "piblockingdequeue.h" - -class MockConditionVar: public PIConditionVariable { -public: - bool isWaitCalled = false; - bool isWaitForCalled = false; - bool isTrueCondition = false; - int timeout = -1; - - void wait(PIMutex& lk) override { - isWaitCalled = true; - } - - void wait(PIMutex& lk, const std::function& condition) override { - isWaitCalled = true; - lk.lock(); - isTrueCondition = condition(); - lk.unlock(); - } - - bool waitFor(PIMutex& lk, int timeoutMs) override { - isWaitForCalled = true; - timeout = timeoutMs; - return false; - } - - bool waitFor(PIMutex& lk, int timeoutMs, const std::function& condition) override { - isWaitForCalled = true; - lk.lock(); - isTrueCondition = condition(); - timeout = timeoutMs; - lk.unlock(); - return isTrueCondition; - } -}; - -TEST(BlockingDequeueUnitTest, put_is_block_when_capacity_reach) { - size_t capacity = 0; - auto conditionVarAdd = new MockConditionVar(); - auto conditionVarRem = new MockConditionVar(); - PIBlockingDequeue dequeue(capacity, conditionVarAdd, conditionVarRem); - dequeue.put(11); - ASSERT_TRUE(conditionVarRem->isWaitCalled); - ASSERT_FALSE(conditionVarRem->isTrueCondition); -} - -TEST(BlockingDequeueUnitTest, offer_timedout_is_false_when_capacity_reach) { - size_t capacity = 0; - int timeout = 11; - auto conditionVarAdd = new MockConditionVar(); - auto conditionVarRem = new MockConditionVar(); - PIBlockingDequeue dequeue(capacity, conditionVarAdd, conditionVarRem); - ASSERT_FALSE(dequeue.offer(11, timeout)); -} - -TEST(BlockingDequeueUnitTest, offer_timedout_is_block_when_capacity_reach) { - size_t capacity = 0; - int timeout = 11; - auto conditionVarAdd = new MockConditionVar(); - auto conditionVarRem = new MockConditionVar(); - PIBlockingDequeue dequeue(capacity, conditionVarAdd, conditionVarRem); - dequeue.offer(11, timeout); - EXPECT_TRUE(conditionVarRem->isWaitForCalled); - EXPECT_EQ(timeout, conditionVarRem->timeout); - ASSERT_FALSE(conditionVarRem->isTrueCondition); -} - -TEST(BlockingDequeueUnitTest, offer_is_true_before_capacity_reach) { - size_t capacity = 1; - PIBlockingDequeue dequeue(capacity); - ASSERT_TRUE(dequeue.offer(10)); -} - -TEST(BlockingDequeueUnitTest, offer_is_false_when_capacity_reach) { - size_t capacity = 1; - PIBlockingDequeue dequeue(capacity); - dequeue.offer(11); - ASSERT_FALSE(dequeue.offer(10)); -} - -// TODO change take_is_block_when_empty to prevent segfault -TEST(DISABLED_BlockingDequeueUnitTest, take_is_block_when_empty) { - size_t capacity = 1; - auto conditionVar = new MockConditionVar(); - PIBlockingDequeue dequeue(capacity, conditionVar); - // May cause segfault because take front of empty queue - dequeue.take(); - EXPECT_TRUE(conditionVar->isWaitCalled); - ASSERT_FALSE(conditionVar->isTrueCondition); -} - -TEST(BlockingDequeueUnitTest, take_is_not_block_when_not_empty) { - size_t capacity = 1; - auto conditionVar = new MockConditionVar(); - PIBlockingDequeue dequeue(capacity, conditionVar); - dequeue.offer(111); - dequeue.take(); - - EXPECT_TRUE(conditionVar->isWaitCalled); - ASSERT_TRUE(conditionVar->isTrueCondition); -} - -TEST(BlockingDequeueUnitTest, take_is_value_eq_to_offer_value) { - size_t capacity = 1; - auto conditionVar = new MockConditionVar(); - PIBlockingDequeue dequeue(capacity, conditionVar); - - dequeue.offer(111); - ASSERT_EQ(dequeue.take(), 111); -} - -TEST(BlockingDequeueUnitTest, take_is_last) { - size_t capacity = 10; - auto conditionVar = new MockConditionVar(); - PIBlockingDequeue dequeue(capacity, conditionVar); - EXPECT_TRUE(dequeue.offer(111)); - EXPECT_TRUE(dequeue.offer(222)); - ASSERT_EQ(dequeue.take(), 111); - ASSERT_EQ(dequeue.take(), 222); -} - -TEST(BlockingDequeueUnitTest, poll_is_not_block_when_empty) { - size_t capacity = 1; - bool isOk; - auto conditionVar = new MockConditionVar(); - PIBlockingDequeue dequeue(capacity, conditionVar); - dequeue.poll(111, &isOk); - EXPECT_FALSE(conditionVar->isWaitForCalled); -} - -TEST(BlockingDequeueUnitTest, poll_is_default_value_when_empty) { - size_t capacity = 1; - bool isOk; - auto conditionVar = new MockConditionVar(); - PIBlockingDequeue dequeue(capacity, conditionVar); - ASSERT_EQ(dequeue.poll(111, &isOk), 111); -} - -TEST(BlockingDequeueUnitTest, poll_is_offer_value_when_not_empty) { - size_t capacity = 1; - bool isOk; - auto conditionVar = new MockConditionVar(); - PIBlockingDequeue dequeue(capacity, conditionVar); - dequeue.offer(111); - ASSERT_EQ(dequeue.poll(-1, &isOk), 111); -} - -TEST(BlockingDequeueUnitTest, poll_timeouted_is_block_when_empty) { - size_t capacity = 1; - int timeout = 11; - auto conditionVar = new MockConditionVar(); - PIBlockingDequeue dequeue(capacity, conditionVar); - dequeue.poll(timeout, 111); - EXPECT_TRUE(conditionVar->isWaitForCalled); - EXPECT_EQ(timeout, conditionVar->timeout); - ASSERT_FALSE(conditionVar->isTrueCondition); -} - -TEST(BlockingDequeueUnitTest, poll_timeouted_is_default_value_when_empty) { - size_t capacity = 1; - int timeout = 11; - auto conditionVar = new MockConditionVar(); - PIBlockingDequeue dequeue(capacity, conditionVar); - ASSERT_EQ(dequeue.poll(timeout, 111), 111); -} - -TEST(BlockingDequeueUnitTest, poll_timeouted_is_not_block_when_not_empty) { - size_t capacity = 1; - int timeout = 11; - auto conditionVar = new MockConditionVar(); - PIBlockingDequeue dequeue(capacity, conditionVar); - dequeue.offer(111); - dequeue.poll(timeout, -1); - - EXPECT_TRUE(conditionVar->isWaitForCalled); - ASSERT_TRUE(conditionVar->isTrueCondition); -} - -TEST(BlockingDequeueUnitTest, poll_timeouted_is_offer_value_when_not_empty) { - size_t capacity = 1; - int timeout = 11; - auto conditionVar = new MockConditionVar(); - PIBlockingDequeue dequeue(capacity, conditionVar); - dequeue.offer(111); - ASSERT_EQ(dequeue.poll(timeout, -1), 111); -} - -TEST(BlockingDequeueUnitTest, poll_timeouted_is_last) { - size_t capacity = 10; - auto conditionVar = new MockConditionVar(); - PIBlockingDequeue dequeue(capacity, conditionVar); - dequeue.offer(111); - dequeue.offer(222); - ASSERT_EQ(dequeue.poll(10, -1), 111); - ASSERT_EQ(dequeue.poll(10, -1), 222); -} - -TEST(BlockingDequeueUnitTest, capacity_is_eq_constructor_capacity) { - size_t capacity = 10; - PIBlockingDequeue dequeue(capacity); - ASSERT_EQ(dequeue.capacity(), capacity); -} - -TEST(BlockingDequeueUnitTest, remainingCapacity_is_dif_of_capacity_and_size) { - size_t capacity = 2; - PIBlockingDequeue dequeue(capacity); - ASSERT_EQ(dequeue.remainingCapacity(), capacity); - dequeue.offer(111); - ASSERT_EQ(dequeue.remainingCapacity(), capacity - 1); -} - -TEST(BlockingDequeueUnitTest, remainingCapacity_is_zero_when_capacity_reach) { - size_t capacity = 1; - PIBlockingDequeue dequeue(capacity); - dequeue.offer(111); - dequeue.offer(111); - ASSERT_EQ(dequeue.remainingCapacity(), 0); -} - -TEST(BlockingDequeueUnitTest, size_is_eq_to_num_of_elements) { - size_t capacity = 1; - PIBlockingDequeue dequeue(capacity); - ASSERT_EQ(dequeue.size(), 0); - dequeue.offer(111); - ASSERT_EQ(dequeue.size(), 1); -} - -TEST(BlockingDequeueUnitTest, size_is_eq_to_capacity_when_capacity_reach) { - size_t capacity = 1; - PIBlockingDequeue dequeue(capacity); - dequeue.offer(111); - dequeue.offer(111); - ASSERT_EQ(dequeue.size(), capacity); -} - -TEST(BlockingDequeueUnitTest, drainTo_is_elements_moved) { - size_t capacity = 10; - PIDeque refDeque; - for (size_t i = 0; i < capacity / 2; ++i) refDeque.push_back(i * 10); - PIBlockingDequeue blockingDequeue(refDeque); - PIDeque deque; - blockingDequeue.drainTo(deque); - ASSERT_EQ(blockingDequeue.size(), 0); - ASSERT_TRUE(deque == refDeque); -} - -TEST(BlockingDequeueUnitTest, drainTo_is_ret_eq_to_size_when_all_moved) { - size_t capacity = 10; - PIDeque refDeque; - for (size_t i = 0; i < capacity / 2; ++i) refDeque.push_back(i * 10); - PIBlockingDequeue blockingDequeue(refDeque); - PIDeque deque; - ASSERT_EQ(blockingDequeue.drainTo(deque), refDeque.size()); -} - -TEST(BlockingDequeueUnitTest, drainTo_is_ret_eq_to_maxCount) { - size_t capacity = 10; - PIDeque refDeque; - for (size_t i = 0; i < capacity / 2; ++i) refDeque.push_back(i * 10); - PIBlockingDequeue blockingDequeue(refDeque); - PIDeque deque; - ASSERT_EQ(blockingDequeue.drainTo(deque, refDeque.size() - 1), refDeque.size() - 1); -} +#include "gtest/gtest.h" +#include "piblockingdequeue.h" + +class MockConditionVar: public PIConditionVariable { +public: + bool isWaitCalled = false; + bool isWaitForCalled = false; + bool isTrueCondition = false; + int timeout = -1; + + void wait(PIMutex& lk) override { + isWaitCalled = true; + } + + void wait(PIMutex& lk, const std::function& condition) override { + isWaitCalled = true; + lk.lock(); + isTrueCondition = condition(); + lk.unlock(); + } + + bool waitFor(PIMutex& lk, int timeoutMs) override { + isWaitForCalled = true; + timeout = timeoutMs; + return false; + } + + bool waitFor(PIMutex& lk, int timeoutMs, const std::function& condition) override { + isWaitForCalled = true; + lk.lock(); + isTrueCondition = condition(); + timeout = timeoutMs; + lk.unlock(); + return isTrueCondition; + } +}; + +TEST(BlockingDequeueUnitTest, put_is_block_when_capacity_reach) { + size_t capacity = 0; + auto conditionVarAdd = new MockConditionVar(); + auto conditionVarRem = new MockConditionVar(); + PIBlockingDequeue dequeue(capacity, conditionVarAdd, conditionVarRem); + dequeue.put(11); + ASSERT_TRUE(conditionVarRem->isWaitCalled); + ASSERT_FALSE(conditionVarRem->isTrueCondition); +} + +TEST(BlockingDequeueUnitTest, offer_timedout_is_false_when_capacity_reach) { + size_t capacity = 0; + int timeout = 11; + auto conditionVarAdd = new MockConditionVar(); + auto conditionVarRem = new MockConditionVar(); + PIBlockingDequeue dequeue(capacity, conditionVarAdd, conditionVarRem); + ASSERT_FALSE(dequeue.offer(11, timeout)); +} + +TEST(BlockingDequeueUnitTest, offer_timedout_is_block_when_capacity_reach) { + size_t capacity = 0; + int timeout = 11; + auto conditionVarAdd = new MockConditionVar(); + auto conditionVarRem = new MockConditionVar(); + PIBlockingDequeue dequeue(capacity, conditionVarAdd, conditionVarRem); + dequeue.offer(11, timeout); + EXPECT_TRUE(conditionVarRem->isWaitForCalled); + EXPECT_EQ(timeout, conditionVarRem->timeout); + ASSERT_FALSE(conditionVarRem->isTrueCondition); +} + +TEST(BlockingDequeueUnitTest, offer_is_true_before_capacity_reach) { + size_t capacity = 1; + PIBlockingDequeue dequeue(capacity); + ASSERT_TRUE(dequeue.offer(10)); +} + +TEST(BlockingDequeueUnitTest, offer_is_false_when_capacity_reach) { + size_t capacity = 1; + PIBlockingDequeue dequeue(capacity); + dequeue.offer(11); + ASSERT_FALSE(dequeue.offer(10)); +} + +// TODO change take_is_block_when_empty to prevent segfault +TEST(DISABLED_BlockingDequeueUnitTest, take_is_block_when_empty) { + size_t capacity = 1; + auto conditionVar = new MockConditionVar(); + PIBlockingDequeue dequeue(capacity, conditionVar); + // May cause segfault because take front of empty queue + dequeue.take(); + EXPECT_TRUE(conditionVar->isWaitCalled); + ASSERT_FALSE(conditionVar->isTrueCondition); +} + +TEST(BlockingDequeueUnitTest, take_is_not_block_when_not_empty) { + size_t capacity = 1; + auto conditionVar = new MockConditionVar(); + PIBlockingDequeue dequeue(capacity, conditionVar); + dequeue.offer(111); + dequeue.take(); + + EXPECT_TRUE(conditionVar->isWaitCalled); + ASSERT_TRUE(conditionVar->isTrueCondition); +} + +TEST(BlockingDequeueUnitTest, take_is_value_eq_to_offer_value) { + size_t capacity = 1; + auto conditionVar = new MockConditionVar(); + PIBlockingDequeue dequeue(capacity, conditionVar); + + dequeue.offer(111); + ASSERT_EQ(dequeue.take(), 111); +} + +TEST(BlockingDequeueUnitTest, take_is_last) { + size_t capacity = 10; + auto conditionVar = new MockConditionVar(); + PIBlockingDequeue dequeue(capacity, conditionVar); + EXPECT_TRUE(dequeue.offer(111)); + EXPECT_TRUE(dequeue.offer(222)); + ASSERT_EQ(dequeue.take(), 111); + ASSERT_EQ(dequeue.take(), 222); +} + +TEST(BlockingDequeueUnitTest, poll_is_not_block_when_empty) { + size_t capacity = 1; + bool isOk; + auto conditionVar = new MockConditionVar(); + PIBlockingDequeue dequeue(capacity, conditionVar); + dequeue.poll(111, &isOk); + EXPECT_FALSE(conditionVar->isWaitForCalled); +} + +TEST(BlockingDequeueUnitTest, poll_is_default_value_when_empty) { + size_t capacity = 1; + bool isOk; + auto conditionVar = new MockConditionVar(); + PIBlockingDequeue dequeue(capacity, conditionVar); + ASSERT_EQ(dequeue.poll(111, &isOk), 111); +} + +TEST(BlockingDequeueUnitTest, poll_is_offer_value_when_not_empty) { + size_t capacity = 1; + bool isOk; + auto conditionVar = new MockConditionVar(); + PIBlockingDequeue dequeue(capacity, conditionVar); + dequeue.offer(111); + ASSERT_EQ(dequeue.poll(-1, &isOk), 111); +} + +TEST(BlockingDequeueUnitTest, poll_timeouted_is_block_when_empty) { + size_t capacity = 1; + int timeout = 11; + auto conditionVar = new MockConditionVar(); + PIBlockingDequeue dequeue(capacity, conditionVar); + dequeue.poll(timeout, 111); + EXPECT_TRUE(conditionVar->isWaitForCalled); + EXPECT_EQ(timeout, conditionVar->timeout); + ASSERT_FALSE(conditionVar->isTrueCondition); +} + +TEST(BlockingDequeueUnitTest, poll_timeouted_is_default_value_when_empty) { + size_t capacity = 1; + int timeout = 11; + auto conditionVar = new MockConditionVar(); + PIBlockingDequeue dequeue(capacity, conditionVar); + ASSERT_EQ(dequeue.poll(timeout, 111), 111); +} + +TEST(BlockingDequeueUnitTest, poll_timeouted_is_not_block_when_not_empty) { + size_t capacity = 1; + int timeout = 11; + auto conditionVar = new MockConditionVar(); + PIBlockingDequeue dequeue(capacity, conditionVar); + dequeue.offer(111); + dequeue.poll(timeout, -1); + + EXPECT_TRUE(conditionVar->isWaitForCalled); + ASSERT_TRUE(conditionVar->isTrueCondition); +} + +TEST(BlockingDequeueUnitTest, poll_timeouted_is_offer_value_when_not_empty) { + size_t capacity = 1; + int timeout = 11; + auto conditionVar = new MockConditionVar(); + PIBlockingDequeue dequeue(capacity, conditionVar); + dequeue.offer(111); + ASSERT_EQ(dequeue.poll(timeout, -1), 111); +} + +TEST(BlockingDequeueUnitTest, poll_timeouted_is_last) { + size_t capacity = 10; + auto conditionVar = new MockConditionVar(); + PIBlockingDequeue dequeue(capacity, conditionVar); + dequeue.offer(111); + dequeue.offer(222); + ASSERT_EQ(dequeue.poll(10, -1), 111); + ASSERT_EQ(dequeue.poll(10, -1), 222); +} + +TEST(BlockingDequeueUnitTest, capacity_is_eq_constructor_capacity) { + size_t capacity = 10; + PIBlockingDequeue dequeue(capacity); + ASSERT_EQ(dequeue.capacity(), capacity); +} + +TEST(BlockingDequeueUnitTest, remainingCapacity_is_dif_of_capacity_and_size) { + size_t capacity = 2; + PIBlockingDequeue dequeue(capacity); + ASSERT_EQ(dequeue.remainingCapacity(), capacity); + dequeue.offer(111); + ASSERT_EQ(dequeue.remainingCapacity(), capacity - 1); +} + +TEST(BlockingDequeueUnitTest, remainingCapacity_is_zero_when_capacity_reach) { + size_t capacity = 1; + PIBlockingDequeue dequeue(capacity); + dequeue.offer(111); + dequeue.offer(111); + ASSERT_EQ(dequeue.remainingCapacity(), 0); +} + +TEST(BlockingDequeueUnitTest, size_is_eq_to_num_of_elements) { + size_t capacity = 1; + PIBlockingDequeue dequeue(capacity); + ASSERT_EQ(dequeue.size(), 0); + dequeue.offer(111); + ASSERT_EQ(dequeue.size(), 1); +} + +TEST(BlockingDequeueUnitTest, size_is_eq_to_capacity_when_capacity_reach) { + size_t capacity = 1; + PIBlockingDequeue dequeue(capacity); + dequeue.offer(111); + dequeue.offer(111); + ASSERT_EQ(dequeue.size(), capacity); +} + +TEST(BlockingDequeueUnitTest, drainTo_is_elements_moved) { + size_t capacity = 10; + PIDeque refDeque; + for (size_t i = 0; i < capacity / 2; ++i) refDeque.push_back(i * 10); + PIBlockingDequeue blockingDequeue(refDeque); + PIDeque deque; + blockingDequeue.drainTo(deque); + ASSERT_EQ(blockingDequeue.size(), 0); + ASSERT_TRUE(deque == refDeque); +} + +TEST(BlockingDequeueUnitTest, drainTo_is_ret_eq_to_size_when_all_moved) { + size_t capacity = 10; + PIDeque refDeque; + for (size_t i = 0; i < capacity / 2; ++i) refDeque.push_back(i * 10); + PIBlockingDequeue blockingDequeue(refDeque); + PIDeque deque; + ASSERT_EQ(blockingDequeue.drainTo(deque), refDeque.size()); +} + +TEST(BlockingDequeueUnitTest, drainTo_is_ret_eq_to_maxCount) { + size_t capacity = 10; + PIDeque refDeque; + for (size_t i = 0; i < capacity / 2; ++i) refDeque.push_back(i * 10); + PIBlockingDequeue blockingDequeue(refDeque); + PIDeque deque; + ASSERT_EQ(blockingDequeue.drainTo(deque, refDeque.size() - 1), refDeque.size() - 1); +} diff --git a/lib/concurrent/test/ConditionLockIntegrationTest.cpp b/tests/concurrent/ConditionLockIntegrationTest.cpp similarity index 95% rename from lib/concurrent/test/ConditionLockIntegrationTest.cpp rename to tests/concurrent/ConditionLockIntegrationTest.cpp index 13a6c6f6..e7f211ae 100644 --- a/lib/concurrent/test/ConditionLockIntegrationTest.cpp +++ b/tests/concurrent/ConditionLockIntegrationTest.cpp @@ -1,53 +1,53 @@ -#include "gtest/gtest.h" -#include "gmock/gmock.h" - -#include "piconditionvar.h" -#include "pithread.h" -#include "testutil.h" - -class ConditionLock : public ::testing::Test, public TestUtil { -public: - PIMutex* m = new PIMutex(); -}; - -TEST_F(ConditionLock, lock_is_protect) { - m->lock(); - bool* isProtect = new bool(true); - - createThread([&](){ - m->lock(); - *isProtect = false; - }); - EXPECT_FALSE(thread->waitForFinish(WAIT_THREAD_TIME_MS)); - ASSERT_TRUE(*isProtect); -} - -TEST_F(ConditionLock, unlock_is_release) { - m->lock(); - bool* isReleased = new bool(false); - m->unlock(); - - createThread([&](){ - m->lock(); - *isReleased = true; - m->unlock(); - }); - ASSERT_TRUE(*isReleased); -} - -TEST_F(ConditionLock, tryLock_is_false_when_locked) { - createThread([&](){ - m->lock(); - piMSleep(WAIT_THREAD_TIME_MS); - }); - ASSERT_FALSE(m->tryLock()); -} - -TEST_F(ConditionLock, tryLock_is_true_when_unlocked) { - ASSERT_TRUE(m->tryLock()); -} - -TEST_F(ConditionLock, tryLock_is_recursive_lock_enable) { - m->lock(); - ASSERT_TRUE(m->tryLock()); -} +#include "gtest/gtest.h" +#include "gmock/gmock.h" + +#include "piconditionvar.h" +#include "pithread.h" +#include "testutil.h" + +class ConditionLock : public ::testing::Test, public TestUtil { +public: + PIMutex* m = new PIMutex(); +}; + +TEST_F(ConditionLock, lock_is_protect) { + m->lock(); + bool* isProtect = new bool(true); + + createThread([&](){ + m->lock(); + *isProtect = false; + }); + EXPECT_FALSE(thread->waitForFinish(WAIT_THREAD_TIME_MS)); + ASSERT_TRUE(*isProtect); +} + +TEST_F(ConditionLock, unlock_is_release) { + m->lock(); + bool* isReleased = new bool(false); + m->unlock(); + + createThread([&](){ + m->lock(); + *isReleased = true; + m->unlock(); + }); + ASSERT_TRUE(*isReleased); +} + +TEST_F(ConditionLock, tryLock_is_false_when_locked) { + createThread([&](){ + m->lock(); + piMSleep(WAIT_THREAD_TIME_MS); + }); + ASSERT_FALSE(m->tryLock()); +} + +TEST_F(ConditionLock, tryLock_is_true_when_unlocked) { + ASSERT_TRUE(m->tryLock()); +} + +TEST_F(ConditionLock, tryLock_is_recursive_lock_enable) { + m->lock(); + ASSERT_TRUE(m->tryLock()); +} diff --git a/lib/concurrent/test/ConditionVariableIntegrationTest.cpp b/tests/concurrent/ConditionVariableIntegrationTest.cpp similarity index 96% rename from lib/concurrent/test/ConditionVariableIntegrationTest.cpp rename to tests/concurrent/ConditionVariableIntegrationTest.cpp index a9d26cec..b8d82a92 100644 --- a/lib/concurrent/test/ConditionVariableIntegrationTest.cpp +++ b/tests/concurrent/ConditionVariableIntegrationTest.cpp @@ -1,200 +1,200 @@ -#include "gtest/gtest.h" -#include "piconditionvar.h" -#include "pithread.h" -#include "testutil.h" - -class ConditionVariable : public ::testing::Test, public TestUtil { -public: - PIMutex m; - PIConditionVariable* variable; - -protected: - void SetUp() override { - variable = new PIConditionVariable(); - adapterFunctionDefault = [&](){ - m.lock(); - variable->wait(m); - m.unlock(); - }; - } -}; - -TEST_F(ConditionVariable, wait_is_block) { - createThread(); - ASSERT_FALSE(thread->waitForFinish(WAIT_THREAD_TIME_MS)); -} - -TEST_F(ConditionVariable, wait_is_block_when_notifyOne_before_wait) { - variable->notifyOne(); - createThread(); - ASSERT_FALSE(thread->waitForFinish(WAIT_THREAD_TIME_MS)); -} - -TEST_F(ConditionVariable, wait_is_block_when_notifyAll_before_wait) { - variable->notifyAll(); - createThread(); - ASSERT_FALSE(thread->waitForFinish(WAIT_THREAD_TIME_MS)); -} - -TEST_F(ConditionVariable, wait_is_unblock_when_notifyOne_after_wait) { - createThread(); - variable->notifyOne(); - ASSERT_TRUE(thread->waitForFinish(WAIT_THREAD_TIME_MS)); -} - -TEST_F(ConditionVariable, wait_is_unblock_when_notifyAll_after_wait) { - PIVector threads; - - for (int i = 0; i < THREAD_COUNT; ++i) { - threads.push_back(new PIThread([=](){ adapterFunctionDefault(); })); - } - - piForeach(PIThread* thread, threads) thread->startOnce(); - piMSleep(WAIT_THREAD_TIME_MS * THREAD_COUNT); - variable->notifyAll(); - PITimeMeasurer measurer; - piForeach(PIThread* thread, threads) { - int timeout = WAIT_THREAD_TIME_MS * THREAD_COUNT - (int)measurer.elapsed_m(); - thread->waitForFinish(timeout > 0 ? timeout : 0); - } - for (size_t i = 0; i < threads.size(); ++i) EXPECT_FALSE(threads[i]->isRunning()) << "Thread " << i << " still running"; - piForeach(PIThread* thread, threads) delete thread; -} - -TEST_F(ConditionVariable, wait_is_one_unblock_when_notifyOne) { - PIVector threads; - - for (int i = 0; i < THREAD_COUNT; ++i) { - threads.push_back(new PIThread(adapterFunctionDefault)); - } - - piForeach(PIThread* thread, threads) thread->startOnce(); - piMSleep(WAIT_THREAD_TIME_MS * THREAD_COUNT); - variable->notifyOne(); - piMSleep(WAIT_THREAD_TIME_MS * THREAD_COUNT); - int runningThreadCount = 0; - piForeach(PIThread* thread, threads) if (thread->isRunning()) runningThreadCount++; - ASSERT_EQ(runningThreadCount, THREAD_COUNT - 1); -} - -TEST_F(ConditionVariable, wait_is_protected_unblock_when_notifyOne) { - createThread([&](){ - m.lock(); - variable->wait(m); - piMSleep(2 * WAIT_THREAD_TIME_MS); - // Missing unlock - }); - variable->notifyOne(); - msleep(WAIT_THREAD_TIME_MS); - ASSERT_FALSE(m.tryLock()); -} - -TEST_F(ConditionVariable, wait_condition_is_block) { - createThread([&](){ - m.lock(); - variable->wait(m, [](){ return false; }); - m.unlock(); - }); - ASSERT_FALSE(thread->waitForFinish(WAIT_THREAD_TIME_MS)); -} - -TEST_F(ConditionVariable, wait_condition_is_check_condition_before_block) { - bool isConditionChecked = false; - createThread([&](){ - m.lock(); - variable->wait(m, [&](){ - isConditionChecked = true; - return false; - }); - m.unlock(); - }); - m.lock(); - ASSERT_TRUE(isConditionChecked); - m.unlock(); -} - -TEST_F(ConditionVariable, wait_condition_is_check_condition_when_notifyOne) { - bool isConditionChecked; - createThread([&](){ - m.lock(); - variable->wait(m, [&](){ - isConditionChecked = true; - return false; - }); - m.unlock(); - }); - m.lock(); - isConditionChecked = false; - m.unlock(); - variable->notifyOne(); - msleep(threadStartTime + 1); - m.lock(); - ASSERT_TRUE(isConditionChecked); - m.unlock(); -} - -TEST_F(ConditionVariable, wait_condition_is_unblock_when_condition_and_notifyOne) { - bool condition = false; - createThread([&](){ - m.lock(); - variable->wait(m, [&](){ return condition; }); - m.unlock(); - }); - m.lock(); - condition = true; - m.unlock(); - variable->notifyOne(); - ASSERT_TRUE(thread->waitForFinish(WAIT_THREAD_TIME_MS)); -} - -TEST_F(ConditionVariable, DISABLED_waitFor_is_block_before_timeout) { - createThread([&](){ - PITimeMeasurer measurer; - m.lock(); - variable->waitFor(m, WAIT_THREAD_TIME_MS * 2); - m.unlock(); - // Not reliable because spurious wakeup may happen - ASSERT_GE(measurer.elapsed_m(), WAIT_THREAD_TIME_MS); - }); - EXPECT_TRUE(thread->waitForFinish(WAIT_THREAD_TIME_MS * 3)); -} - -TEST_F(ConditionVariable, waitFor_is_unblock_when_timeout) { - std::atomic_bool isUnblock(false); - createThread([&](){ - m.lock(); - variable->waitFor(m, WAIT_THREAD_TIME_MS); - isUnblock = true; - m.unlock(); - }); - // Test failed if suspend forever - EXPECT_TRUE(thread->waitForFinish(2 * WAIT_THREAD_TIME_MS)); - ASSERT_TRUE(isUnblock); -} - -TEST_F(ConditionVariable, waitFor_is_false_when_timeout) { - bool waitRet = true; - createThread([&](){ - m.lock(); - waitRet = variable->waitFor(m, WAIT_THREAD_TIME_MS); - m.unlock(); - }); - EXPECT_TRUE(thread->waitForFinish(2 * WAIT_THREAD_TIME_MS)); - ASSERT_FALSE(waitRet); -} - -TEST_F(ConditionVariable, waitFor_is_unblock_when_condition_and_notifyOne) { - bool condition = false; - createThread([&](){ - m.lock(); - variable->waitFor(m, 3 * WAIT_THREAD_TIME_MS, [&](){ return condition; }); - m.unlock(); - }); - EXPECT_TRUE(thread->isRunning()); - m.lock(); - condition = true; - m.unlock(); - variable->notifyOne(); - msleep(WAIT_THREAD_TIME_MS); - ASSERT_FALSE(thread->isRunning()); -} +#include "gtest/gtest.h" +#include "piconditionvar.h" +#include "pithread.h" +#include "testutil.h" + +class ConditionVariable : public ::testing::Test, public TestUtil { +public: + PIMutex m; + PIConditionVariable* variable; + +protected: + void SetUp() override { + variable = new PIConditionVariable(); + adapterFunctionDefault = [&](){ + m.lock(); + variable->wait(m); + m.unlock(); + }; + } +}; + +TEST_F(ConditionVariable, wait_is_block) { + createThread(); + ASSERT_FALSE(thread->waitForFinish(WAIT_THREAD_TIME_MS)); +} + +TEST_F(ConditionVariable, wait_is_block_when_notifyOne_before_wait) { + variable->notifyOne(); + createThread(); + ASSERT_FALSE(thread->waitForFinish(WAIT_THREAD_TIME_MS)); +} + +TEST_F(ConditionVariable, wait_is_block_when_notifyAll_before_wait) { + variable->notifyAll(); + createThread(); + ASSERT_FALSE(thread->waitForFinish(WAIT_THREAD_TIME_MS)); +} + +TEST_F(ConditionVariable, wait_is_unblock_when_notifyOne_after_wait) { + createThread(); + variable->notifyOne(); + ASSERT_TRUE(thread->waitForFinish(WAIT_THREAD_TIME_MS)); +} + +TEST_F(ConditionVariable, wait_is_unblock_when_notifyAll_after_wait) { + PIVector threads; + + for (int i = 0; i < THREAD_COUNT; ++i) { + threads.push_back(new PIThread([=](){ adapterFunctionDefault(); })); + } + + piForeach(PIThread* thread, threads) thread->startOnce(); + piMSleep(WAIT_THREAD_TIME_MS * THREAD_COUNT); + variable->notifyAll(); + PITimeMeasurer measurer; + piForeach(PIThread* thread, threads) { + int timeout = WAIT_THREAD_TIME_MS * THREAD_COUNT - (int)measurer.elapsed_m(); + thread->waitForFinish(timeout > 0 ? timeout : 0); + } + for (size_t i = 0; i < threads.size(); ++i) EXPECT_FALSE(threads[i]->isRunning()) << "Thread " << i << " still running"; + piForeach(PIThread* thread, threads) delete thread; +} + +TEST_F(ConditionVariable, wait_is_one_unblock_when_notifyOne) { + PIVector threads; + + for (int i = 0; i < THREAD_COUNT; ++i) { + threads.push_back(new PIThread(adapterFunctionDefault)); + } + + piForeach(PIThread* thread, threads) thread->startOnce(); + piMSleep(WAIT_THREAD_TIME_MS * THREAD_COUNT); + variable->notifyOne(); + piMSleep(WAIT_THREAD_TIME_MS * THREAD_COUNT); + int runningThreadCount = 0; + piForeach(PIThread* thread, threads) if (thread->isRunning()) runningThreadCount++; + ASSERT_EQ(runningThreadCount, THREAD_COUNT - 1); +} + +TEST_F(ConditionVariable, wait_is_protected_unblock_when_notifyOne) { + createThread([&](){ + m.lock(); + variable->wait(m); + piMSleep(2 * WAIT_THREAD_TIME_MS); + // Missing unlock + }); + variable->notifyOne(); + msleep(WAIT_THREAD_TIME_MS); + ASSERT_FALSE(m.tryLock()); +} + +TEST_F(ConditionVariable, wait_condition_is_block) { + createThread([&](){ + m.lock(); + variable->wait(m, [](){ return false; }); + m.unlock(); + }); + ASSERT_FALSE(thread->waitForFinish(WAIT_THREAD_TIME_MS)); +} + +TEST_F(ConditionVariable, wait_condition_is_check_condition_before_block) { + bool isConditionChecked = false; + createThread([&](){ + m.lock(); + variable->wait(m, [&](){ + isConditionChecked = true; + return false; + }); + m.unlock(); + }); + m.lock(); + ASSERT_TRUE(isConditionChecked); + m.unlock(); +} + +TEST_F(ConditionVariable, wait_condition_is_check_condition_when_notifyOne) { + bool isConditionChecked; + createThread([&](){ + m.lock(); + variable->wait(m, [&](){ + isConditionChecked = true; + return false; + }); + m.unlock(); + }); + m.lock(); + isConditionChecked = false; + m.unlock(); + variable->notifyOne(); + msleep(threadStartTime + 1); + m.lock(); + ASSERT_TRUE(isConditionChecked); + m.unlock(); +} + +TEST_F(ConditionVariable, wait_condition_is_unblock_when_condition_and_notifyOne) { + bool condition = false; + createThread([&](){ + m.lock(); + variable->wait(m, [&](){ return condition; }); + m.unlock(); + }); + m.lock(); + condition = true; + m.unlock(); + variable->notifyOne(); + ASSERT_TRUE(thread->waitForFinish(WAIT_THREAD_TIME_MS)); +} + +TEST_F(ConditionVariable, DISABLED_waitFor_is_block_before_timeout) { + createThread([&](){ + PITimeMeasurer measurer; + m.lock(); + variable->waitFor(m, WAIT_THREAD_TIME_MS * 2); + m.unlock(); + // Not reliable because spurious wakeup may happen + ASSERT_GE(measurer.elapsed_m(), WAIT_THREAD_TIME_MS); + }); + EXPECT_TRUE(thread->waitForFinish(WAIT_THREAD_TIME_MS * 3)); +} + +TEST_F(ConditionVariable, waitFor_is_unblock_when_timeout) { + std::atomic_bool isUnblock(false); + createThread([&](){ + m.lock(); + variable->waitFor(m, WAIT_THREAD_TIME_MS); + isUnblock = true; + m.unlock(); + }); + // Test failed if suspend forever + EXPECT_TRUE(thread->waitForFinish(2 * WAIT_THREAD_TIME_MS)); + ASSERT_TRUE(isUnblock); +} + +TEST_F(ConditionVariable, waitFor_is_false_when_timeout) { + bool waitRet = true; + createThread([&](){ + m.lock(); + waitRet = variable->waitFor(m, WAIT_THREAD_TIME_MS); + m.unlock(); + }); + EXPECT_TRUE(thread->waitForFinish(2 * WAIT_THREAD_TIME_MS)); + ASSERT_FALSE(waitRet); +} + +TEST_F(ConditionVariable, waitFor_is_unblock_when_condition_and_notifyOne) { + bool condition = false; + createThread([&](){ + m.lock(); + variable->waitFor(m, 3 * WAIT_THREAD_TIME_MS, [&](){ return condition; }); + m.unlock(); + }); + EXPECT_TRUE(thread->isRunning()); + m.lock(); + condition = true; + m.unlock(); + variable->notifyOne(); + msleep(WAIT_THREAD_TIME_MS); + ASSERT_FALSE(thread->isRunning()); +} diff --git a/lib/concurrent/test/ExecutorIntegrationTest.cpp b/tests/concurrent/ExecutorIntegrationTest.cpp similarity index 96% rename from lib/concurrent/test/ExecutorIntegrationTest.cpp rename to tests/concurrent/ExecutorIntegrationTest.cpp index 8e58a48c..0dacc5c4 100644 --- a/lib/concurrent/test/ExecutorIntegrationTest.cpp +++ b/tests/concurrent/ExecutorIntegrationTest.cpp @@ -1,54 +1,54 @@ -#include "gtest/gtest.h" -#include "pithreadpoolexecutor.h" -#include "pimutex.h" - -const int WAIT_THREAD_TIME_MS = 30; - -TEST(ExcutorIntegrationTest, execute_is_runnable_invoke) { - PIMutex m; - int invokedRunnables = 0; - PIThreadPoolExecutor executorService(1); - executorService.execute([&]() { - m.lock(); - invokedRunnables++; - m.unlock(); - }); - piMSleep(WAIT_THREAD_TIME_MS); - ASSERT_EQ(invokedRunnables, 1); -} - -TEST(ExcutorIntegrationTest, execute_is_not_execute_after_shutdown) { - bool isRunnableInvoke = false; - PIThreadPoolExecutor executorService(1); - executorService.shutdown(); - executorService.execute([&]() { - isRunnableInvoke = true; - }); - piMSleep(WAIT_THREAD_TIME_MS); - ASSERT_FALSE(isRunnableInvoke); -} - -TEST(ExcutorIntegrationTest, execute_is_execute_before_shutdown) { - bool isRunnableInvoke = false; - PIThreadPoolExecutor executorService(1); - executorService.execute([&]() { - piMSleep(WAIT_THREAD_TIME_MS); - isRunnableInvoke = true; - }); - executorService.shutdown(); - piMSleep(2 * WAIT_THREAD_TIME_MS); - ASSERT_TRUE(isRunnableInvoke); -} - -TEST(ExcutorIntegrationTest, execute_is_awaitTermination_wait) { - PIThreadPoolExecutor executorService(1); - executorService.execute([&]() { - piMSleep(2 * WAIT_THREAD_TIME_MS); - }); - executorService.shutdown(); - PITimeMeasurer measurer; - ASSERT_TRUE(executorService.awaitTermination(3 * WAIT_THREAD_TIME_MS)); - double waitTime = measurer.elapsed_m(); - ASSERT_GE(waitTime, WAIT_THREAD_TIME_MS); - ASSERT_LE(waitTime, 4 * WAIT_THREAD_TIME_MS); -} +#include "gtest/gtest.h" +#include "pithreadpoolexecutor.h" +#include "pimutex.h" + +const int WAIT_THREAD_TIME_MS = 30; + +TEST(ExcutorIntegrationTest, execute_is_runnable_invoke) { + PIMutex m; + int invokedRunnables = 0; + PIThreadPoolExecutor executorService(1); + executorService.execute([&]() { + m.lock(); + invokedRunnables++; + m.unlock(); + }); + piMSleep(WAIT_THREAD_TIME_MS); + ASSERT_EQ(invokedRunnables, 1); +} + +TEST(ExcutorIntegrationTest, execute_is_not_execute_after_shutdown) { + bool isRunnableInvoke = false; + PIThreadPoolExecutor executorService(1); + executorService.shutdown(); + executorService.execute([&]() { + isRunnableInvoke = true; + }); + piMSleep(WAIT_THREAD_TIME_MS); + ASSERT_FALSE(isRunnableInvoke); +} + +TEST(ExcutorIntegrationTest, execute_is_execute_before_shutdown) { + bool isRunnableInvoke = false; + PIThreadPoolExecutor executorService(1); + executorService.execute([&]() { + piMSleep(WAIT_THREAD_TIME_MS); + isRunnableInvoke = true; + }); + executorService.shutdown(); + piMSleep(2 * WAIT_THREAD_TIME_MS); + ASSERT_TRUE(isRunnableInvoke); +} + +TEST(ExcutorIntegrationTest, execute_is_awaitTermination_wait) { + PIThreadPoolExecutor executorService(1); + executorService.execute([&]() { + piMSleep(2 * WAIT_THREAD_TIME_MS); + }); + executorService.shutdown(); + PITimeMeasurer measurer; + ASSERT_TRUE(executorService.awaitTermination(3 * WAIT_THREAD_TIME_MS)); + double waitTime = measurer.elapsed_m(); + ASSERT_GE(waitTime, WAIT_THREAD_TIME_MS); + ASSERT_LE(waitTime, 4 * WAIT_THREAD_TIME_MS); +} diff --git a/lib/concurrent/test/testutil.h b/tests/concurrent/testutil.h similarity index 96% rename from lib/concurrent/test/testutil.h rename to tests/concurrent/testutil.h index 063f6622..7c3c15c7 100644 --- a/lib/concurrent/test/testutil.h +++ b/tests/concurrent/testutil.h @@ -1,60 +1,60 @@ -#ifndef AWRCANFLASHER_TESTUTIL_H -#define AWRCANFLASHER_TESTUTIL_H - -#include "pithread.h" -#include - -/** - * Minimum wait thread start, switch context or another interthread communication action time. Increase it if tests - * write "Start thread timeout reach!" message. You can reduce it if you want increase test performance. - */ -const int WAIT_THREAD_TIME_MS = 40; - -const int THREAD_COUNT = 5; - -class TestUtil: public PIObject { -PIOBJECT(TestUtil) -public: - double threadStartTime; - PIThread* thread = new PIThread(); - std::atomic_bool isRunning; - std::function adapterFunctionDefault; - - TestUtil() : isRunning(false) {} - - bool createThread(const std::function& fun = nullptr, PIThread* thread_ = nullptr) { - std::function actualFun = fun == nullptr ? adapterFunctionDefault : fun; - if (thread_ == nullptr) thread_ = thread; - thread_->startOnce([=](void*){ - isRunning = true; - actualFun(); - }); - return waitThread(thread_); - } - - bool waitThread(PIThread* thread_, bool runningStatus = true) { - PITimeMeasurer measurer; - bool isTimeout = !thread_->waitForStart(WAIT_THREAD_TIME_MS); - while (!isRunning) { - isTimeout = WAIT_THREAD_TIME_MS <= measurer.elapsed_m(); - if (isTimeout) break; - piUSleep(100); - } - - threadStartTime = measurer.elapsed_m(); - - if (isTimeout) piCout << "Start thread timeout reach!"; - - if (threadStartTime > 1) { - piCout << "Start time" << threadStartTime << "ms"; - } else if (threadStartTime > 0.001) { - piCout << "Start time" << threadStartTime * 1000 << "mcs"; - } else { - piCout << "Start time" << threadStartTime * 1000 * 1000 << "ns"; - } - - return !isTimeout; - } -}; - -#endif //AWRCANFLASHER_TESTUTIL_H +#ifndef AWRCANFLASHER_TESTUTIL_H +#define AWRCANFLASHER_TESTUTIL_H + +#include "pithread.h" +#include + +/** + * Minimum wait thread start, switch context or another interthread communication action time. Increase it if tests + * write "Start thread timeout reach!" message. You can reduce it if you want increase test performance. + */ +const int WAIT_THREAD_TIME_MS = 40; + +const int THREAD_COUNT = 5; + +class TestUtil: public PIObject { +PIOBJECT(TestUtil) +public: + double threadStartTime; + PIThread* thread = new PIThread(); + std::atomic_bool isRunning; + std::function adapterFunctionDefault; + + TestUtil() : isRunning(false) {} + + bool createThread(const std::function& fun = nullptr, PIThread* thread_ = nullptr) { + std::function actualFun = fun == nullptr ? adapterFunctionDefault : fun; + if (thread_ == nullptr) thread_ = thread; + thread_->startOnce([=](void*){ + isRunning = true; + actualFun(); + }); + return waitThread(thread_); + } + + bool waitThread(PIThread* thread_, bool runningStatus = true) { + PITimeMeasurer measurer; + bool isTimeout = !thread_->waitForStart(WAIT_THREAD_TIME_MS); + while (!isRunning) { + isTimeout = WAIT_THREAD_TIME_MS <= measurer.elapsed_m(); + if (isTimeout) break; + piUSleep(100); + } + + threadStartTime = measurer.elapsed_m(); + + if (isTimeout) piCout << "Start thread timeout reach!"; + + if (threadStartTime > 1) { + piCout << "Start time" << threadStartTime << "ms"; + } else if (threadStartTime > 0.001) { + piCout << "Start time" << threadStartTime * 1000 << "mcs"; + } else { + piCout << "Start time" << threadStartTime * 1000 * 1000 << "ns"; + } + + return !isTimeout; + } +}; + +#endif //AWRCANFLASHER_TESTUTIL_H