Removed hard unit tests for executor && fixed another tests
git-svn-id: svn://db.shs.com.ru/pip@890 12ceb7fc-bf1f-11e4-8940-5bc7170c53b5
This commit is contained in:
@@ -10,56 +10,48 @@
|
|||||||
#include "testutil.h"
|
#include "testutil.h"
|
||||||
|
|
||||||
class ConditionLock : public ::testing::Test, public TestUtil {
|
class ConditionLock : public ::testing::Test, public TestUtil {
|
||||||
protected:
|
public:
|
||||||
void TearDown() override {
|
PIConditionLock* m = new PIConditionLock();
|
||||||
if (adapter != nullptr) delete adapter;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(ConditionLock, lock_is_protect) {
|
TEST_F(ConditionLock, lock_is_protect) {
|
||||||
PIConditionLock m;
|
m->lock();
|
||||||
m.lock();
|
|
||||||
bool isProtect = true;
|
bool isProtect = true;
|
||||||
|
|
||||||
createThread([&](){
|
createThread([&](){
|
||||||
m.lock();
|
m->lock();
|
||||||
isProtect = false;
|
isProtect = false;
|
||||||
});
|
});
|
||||||
ASSERT_TRUE(isProtect);
|
ASSERT_TRUE(isProtect);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ConditionLock, unlock_is_release) {
|
TEST_F(ConditionLock, unlock_is_release) {
|
||||||
PIConditionLock m;
|
m->lock();
|
||||||
m.lock();
|
|
||||||
volatile bool isReleased = false;
|
volatile bool isReleased = false;
|
||||||
m.unlock();
|
m->unlock();
|
||||||
|
|
||||||
createThread([&](){
|
createThread([&](){
|
||||||
m.lock();
|
m->lock();
|
||||||
isReleased = true;
|
isReleased = true;
|
||||||
m.unlock();
|
m->unlock();
|
||||||
});
|
});
|
||||||
EXPECT_TRUE(thread->waitForFinish(WAIT_THREAD_TIME_MS));
|
EXPECT_TRUE(thread->waitForFinish(WAIT_THREAD_TIME_MS));
|
||||||
ASSERT_TRUE(isReleased);
|
ASSERT_TRUE(isReleased);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ConditionLock, tryLock_is_false_when_locked) {
|
TEST_F(ConditionLock, tryLock_is_false_when_locked) {
|
||||||
PIConditionLock m;
|
|
||||||
|
|
||||||
createThread([&](){
|
createThread([&](){
|
||||||
m.lock();
|
m->lock();
|
||||||
piMSleep(WAIT_THREAD_TIME_MS);
|
piMSleep(WAIT_THREAD_TIME_MS);
|
||||||
});
|
});
|
||||||
ASSERT_FALSE(m.tryLock());
|
ASSERT_FALSE(m->tryLock());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ConditionLock, tryLock_is_true_when_unlocked) {
|
TEST_F(ConditionLock, tryLock_is_true_when_unlocked) {
|
||||||
PIConditionLock m;
|
ASSERT_TRUE(m->tryLock());
|
||||||
ASSERT_TRUE(m.tryLock());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ConditionLock, tryLock_is_recursive_lock_enable) {
|
TEST_F(ConditionLock, tryLock_is_recursive_lock_enable) {
|
||||||
PIConditionLock m;
|
m->lock();
|
||||||
m.lock();
|
ASSERT_TRUE(m->tryLock());
|
||||||
ASSERT_TRUE(m.tryLock());
|
|
||||||
}
|
}
|
||||||
@@ -23,21 +23,8 @@ protected:
|
|||||||
m.unlock();
|
m.unlock();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void TearDown() override {
|
|
||||||
if (adapter != nullptr) delete adapter;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST(ThreadFuncAdapter, registerToInvoke_is_stdFun_invoke) {
|
|
||||||
bool isInvoke = false;
|
|
||||||
StdFunctionThreadFuncAdapter adapter([&](){
|
|
||||||
isInvoke = true;
|
|
||||||
});
|
|
||||||
adapter.threadFunc()(adapter.data());
|
|
||||||
ASSERT_TRUE(isInvoke);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ConditionVariable, wait_is_block) {
|
TEST_F(ConditionVariable, wait_is_block) {
|
||||||
createThread();
|
createThread();
|
||||||
ASSERT_FALSE(thread->waitForFinish(WAIT_THREAD_TIME_MS));
|
ASSERT_FALSE(thread->waitForFinish(WAIT_THREAD_TIME_MS));
|
||||||
@@ -62,12 +49,10 @@ TEST_F(ConditionVariable, wait_is_unblock_when_notifyOne_after_wait) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ConditionVariable, wait_is_unblock_when_notifyAll_after_wait) {
|
TEST_F(ConditionVariable, wait_is_unblock_when_notifyAll_after_wait) {
|
||||||
PIVector<StdFunctionThreadFuncAdapter*> adapters;
|
|
||||||
PIVector<PIThread*> threads;
|
PIVector<PIThread*> threads;
|
||||||
|
|
||||||
for (int i = 0; i < THREAD_COUNT; ++i) {
|
for (int i = 0; i < THREAD_COUNT; ++i) {
|
||||||
adapters.push_back(new StdFunctionThreadFuncAdapter(adapterFunctionDefault));
|
threads.push_back(new PIThread([=](){ adapterFunctionDefault(); }));
|
||||||
threads.push_back(new PIThread(adapters.back()->data(), adapters.back()->threadFunc()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
piForeach(PIThread* thread, threads) thread->startOnce();
|
piForeach(PIThread* thread, threads) thread->startOnce();
|
||||||
@@ -80,16 +65,13 @@ TEST_F(ConditionVariable, wait_is_unblock_when_notifyAll_after_wait) {
|
|||||||
}
|
}
|
||||||
for (size_t i = 0; i < threads.size(); ++i) EXPECT_FALSE(threads[i]->isRunning()) << "Thread " << i << " still running";
|
for (size_t i = 0; i < threads.size(); ++i) EXPECT_FALSE(threads[i]->isRunning()) << "Thread " << i << " still running";
|
||||||
piForeach(PIThread* thread, threads) delete thread;
|
piForeach(PIThread* thread, threads) delete thread;
|
||||||
piForeach(StdFunctionThreadFuncAdapter* adapter, adapters) delete adapter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ConditionVariable, wait_is_one_unblock_when_notifyOne) {
|
TEST_F(ConditionVariable, wait_is_one_unblock_when_notifyOne) {
|
||||||
PIVector<StdFunctionThreadFuncAdapter*> adapters;
|
|
||||||
PIVector<PIThread*> threads;
|
PIVector<PIThread*> threads;
|
||||||
|
|
||||||
for (int i = 0; i < THREAD_COUNT; ++i) {
|
for (int i = 0; i < THREAD_COUNT; ++i) {
|
||||||
adapters.push_back(new StdFunctionThreadFuncAdapter(adapterFunctionDefault));
|
threads.push_back(new PIThread(adapterFunctionDefault));
|
||||||
threads.push_back(new PIThread(adapters.back()->data(), adapters.back()->threadFunc()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
piForeach(PIThread* thread, threads) thread->startOnce();
|
piForeach(PIThread* thread, threads) thread->startOnce();
|
||||||
|
|||||||
@@ -1,127 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by fomenko on 23.09.2019.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "executor.h"
|
|
||||||
#include "gtest/gtest.h"
|
|
||||||
#include "gmock/gmock.h"
|
|
||||||
|
|
||||||
using ::testing::_;
|
|
||||||
using ::testing::SetArgReferee;
|
|
||||||
using ::testing::DoAll;
|
|
||||||
using ::testing::DeleteArg;
|
|
||||||
using ::testing::Return;
|
|
||||||
using ::testing::AtLeast;
|
|
||||||
using ::testing::ByRef;
|
|
||||||
using ::testing::Eq;
|
|
||||||
|
|
||||||
typedef std::function<void()> VoidFunc;
|
|
||||||
|
|
||||||
namespace std {
|
|
||||||
inline bool operator ==(const VoidFunc& s, const VoidFunc& v) {
|
|
||||||
// TODO VoidFunc operator ==
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const int THREAD_COUNT = 2;
|
|
||||||
|
|
||||||
class MockThread : public AbstractThread {
|
|
||||||
public:
|
|
||||||
MOCK_METHOD0(start, bool());
|
|
||||||
MOCK_METHOD0(stop, void());
|
|
||||||
MOCK_METHOD1(waitForStart, bool(int timeout_msecs));
|
|
||||||
MOCK_METHOD1(waitForFinish, bool(int timeout_msecs));
|
|
||||||
};
|
|
||||||
|
|
||||||
class MockDeque : public PIBlockingDequeue<VoidFunc> {
|
|
||||||
public:
|
|
||||||
MOCK_METHOD1(offer, bool(const VoidFunc&));
|
|
||||||
MOCK_METHOD0(take, VoidFunc());
|
|
||||||
MOCK_METHOD2(poll, VoidFunc(int timeoutMs, const VoidFunc& defaultVal));
|
|
||||||
MOCK_METHOD0(capacity, size_t());
|
|
||||||
MOCK_METHOD0(remainingCapacity, size_t());
|
|
||||||
};
|
|
||||||
|
|
||||||
class MockThreadFactory : public PIThreadFactory {
|
|
||||||
public:
|
|
||||||
int callCount = 0;
|
|
||||||
PIVector<MockThread*> threads;
|
|
||||||
std::function<void(MockThread*)> checkThreadExpectations = [](MockThread* thread){
|
|
||||||
EXPECT_CALL(*thread, start())
|
|
||||||
.WillOnce(Return(true));
|
|
||||||
EXPECT_CALL(*thread, stop())
|
|
||||||
.WillOnce(Return());
|
|
||||||
};
|
|
||||||
|
|
||||||
std::function<void(const VoidFunc& fun)> checkThreadFunc = [](const VoidFunc& fun) { };
|
|
||||||
|
|
||||||
AbstractThread* newThread(const VoidFunc& fun) override {
|
|
||||||
callCount++;
|
|
||||||
auto* thread = new MockThread();
|
|
||||||
threads.push_back(thread);
|
|
||||||
checkThreadExpectations(thread);
|
|
||||||
checkThreadFunc(fun);
|
|
||||||
return threads.back();
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST(ExecutorUnitTest, is_corePool_created) {
|
|
||||||
auto* deque = new MockDeque();
|
|
||||||
auto* threadFactory = new MockThreadFactory();
|
|
||||||
PIThreadPoolExecutor executor(THREAD_COUNT, deque, threadFactory);
|
|
||||||
ASSERT_EQ(THREAD_COUNT, threadFactory->callCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(ExecutorUnitTest, is_corePool_started) {
|
|
||||||
auto* deque = new MockDeque();
|
|
||||||
auto* threadFactory = new MockThreadFactory();
|
|
||||||
PIThreadPoolExecutor executor(THREAD_COUNT, deque, threadFactory);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(ExecutorUnitTest, execute_is_added_to_taskQueue) {
|
|
||||||
VoidFunc voidFunc = [](){};
|
|
||||||
auto* deque = new MockDeque();
|
|
||||||
EXPECT_CALL(*deque, offer(Eq(voidFunc)))
|
|
||||||
.WillOnce(Return(true));
|
|
||||||
|
|
||||||
auto* threadFactory = new MockThreadFactory();
|
|
||||||
PIThreadPoolExecutor executor(THREAD_COUNT, deque, threadFactory);
|
|
||||||
executor.execute([]() {});
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(ExecutorUnitTest, is_corePool_execute_queue_elements) {
|
|
||||||
auto* deque = new MockDeque();
|
|
||||||
auto* threadFactory = new MockThreadFactory();
|
|
||||||
threadFactory->checkThreadFunc = [](const VoidFunc& fun) {
|
|
||||||
fun();
|
|
||||||
};
|
|
||||||
ON_CALL(*deque, take())
|
|
||||||
.WillByDefault(Return([](){}));
|
|
||||||
EXPECT_CALL(*deque, poll(_, _))
|
|
||||||
.Times(THREAD_COUNT)
|
|
||||||
.WillRepeatedly(Return([](){}));
|
|
||||||
PIThreadPoolExecutor executor(THREAD_COUNT, deque, threadFactory);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(ExecutorUnitTest, shutdown_is_stop_threads) {
|
|
||||||
auto* deque = new MockDeque();
|
|
||||||
auto* threadFactory = new MockThreadFactory();
|
|
||||||
PIVector<VoidFunc> threadFuncs;
|
|
||||||
threadFactory->checkThreadExpectations = [](MockThread* thread) {
|
|
||||||
EXPECT_CALL(*thread, start())
|
|
||||||
.WillOnce(Return(true));
|
|
||||||
EXPECT_CALL(*thread, stop())
|
|
||||||
.WillRepeatedly(Return());
|
|
||||||
};
|
|
||||||
threadFactory->checkThreadFunc = [&](const VoidFunc& threadFunc) { threadFuncs.push_back(threadFunc); };
|
|
||||||
ON_CALL(*deque, take())
|
|
||||||
.WillByDefault(Return(VoidFunc()));
|
|
||||||
EXPECT_CALL(*deque, poll(_, _))
|
|
||||||
.Times(THREAD_COUNT)
|
|
||||||
.WillRepeatedly(Return(VoidFunc()));
|
|
||||||
PIThreadPoolExecutor executor(THREAD_COUNT, deque, threadFactory);
|
|
||||||
executor.shutdown();
|
|
||||||
piForeachC(VoidFunc& threadFunc, threadFuncs) threadFunc();
|
|
||||||
}
|
|
||||||
@@ -20,15 +20,13 @@ PIOBJECT(TestUtil)
|
|||||||
public:
|
public:
|
||||||
double threadStartTime;
|
double threadStartTime;
|
||||||
PIThread* thread = new PIThread();
|
PIThread* thread = new PIThread();
|
||||||
StdFunctionThreadFuncAdapter* adapter = nullptr;
|
|
||||||
volatile bool isRunning;
|
volatile bool isRunning;
|
||||||
std::function<void()> adapterFunctionDefault;
|
std::function<void()> adapterFunctionDefault;
|
||||||
|
|
||||||
bool createThread(const std::function<void()>& fun = nullptr, PIThread* thread_ = nullptr) {
|
bool createThread(const std::function<void()>& fun = nullptr, PIThread* thread_ = nullptr) {
|
||||||
adapter = new StdFunctionThreadFuncAdapter(fun == nullptr ? adapterFunctionDefault : fun);
|
std::function<void()> actualFun = fun == nullptr ? adapterFunctionDefault : fun;
|
||||||
if (thread_ == nullptr) thread_ = thread;
|
if (thread_ == nullptr) thread_ = thread;
|
||||||
adapter->registerToInvoke(thread_);
|
thread_->startOnce([=](void*){ actualFun(); });
|
||||||
thread_->startOnce();
|
|
||||||
return waitThread(thread_);
|
return waitThread(thread_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user