Chromium Code Reviews| Index: webrtc/base/thread_unittest.cc |
| diff --git a/webrtc/base/thread_unittest.cc b/webrtc/base/thread_unittest.cc |
| index 951a7e14f39670047cf12809d5cf9acef8b9d011..5f12a81553f6fcdf90848ea5509e03dbbb7770db 100644 |
| --- a/webrtc/base/thread_unittest.cc |
| +++ b/webrtc/base/thread_unittest.cc |
| @@ -518,6 +518,176 @@ TEST_F(AsyncInvokeTest, FlushWithIds) { |
| EXPECT_TRUE(flag2); |
| } |
| +class GuardedAsyncInvokeTest : public testing::Test { |
| + public: |
| + void IntCallback(int value) { |
| + EXPECT_EQ(expected_thread_, Thread::Current()); |
| + int_value_ = value; |
| + } |
| + void AsyncInvokeIntCallback(GuardedAsyncInvoker* invoker, Thread* thread) { |
| + expected_thread_ = thread; |
| + invoker->AsyncInvoke(FunctorC(), &GuardedAsyncInvokeTest::IntCallback, |
| + static_cast<GuardedAsyncInvokeTest*>(this)); |
| + invoke_started_.Set(); |
| + } |
| + void SetExpectedThreadForIntCallback(Thread* thread) { |
| + expected_thread_ = thread; |
| + } |
| + |
| + protected: |
| + enum { kWaitTimeout = 1000 }; |
|
tommi (sloooow) - chröme
2015/08/19 20:01:54
const static int
I think using enums this way is
magjed_webrtc
2015/08/20 10:28:33
Done.
|
| + GuardedAsyncInvokeTest() |
| + : int_value_(0), invoke_started_(true, false), expected_thread_(NULL) {} |
|
tommi (sloooow) - chröme
2015/08/19 20:01:54
nit: nullptr
magjed_webrtc
2015/08/20 10:28:33
Done.
|
| + |
| + int int_value_; |
| + Event invoke_started_; |
| + Thread* expected_thread_; |
| +}; |
| + |
| +struct CreateInvoker { |
| + CreateInvoker(scoped_ptr<GuardedAsyncInvoker>* invoker) : invoker_(invoker) {} |
| + void operator()() { invoker_->reset(new GuardedAsyncInvoker()); } |
| + scoped_ptr<GuardedAsyncInvoker>* invoker_; |
| +}; |
| + |
| +// Test that we can call AsyncInvoke<void>() after the thread died. |
| +TEST_F(GuardedAsyncInvokeTest, KillThreadFireAndForget) { |
| + // Create and start the thread. |
| + scoped_ptr<Thread> thread(new Thread()); |
| + thread->Start(); |
| + scoped_ptr<GuardedAsyncInvoker> invoker; |
| + // Create the invoker on |thread|. |
| + thread->Invoke<void>(CreateInvoker(&invoker)); |
| + // Kill |thread|. |
| + thread = nullptr; |
| + // Try calling functor. |
| + bool called = false; |
| + invoker->AsyncInvoke<void>(FunctorB(&called)); |
| + // With thread gone, nothing should happen. |
| + WAIT(called, kWaitTimeout); |
| + EXPECT_FALSE(called); |
| +} |
| + |
| +// Test that we can call AsyncInvoke with callback after the thread died. |
| +TEST_F(GuardedAsyncInvokeTest, KillThreadWithCallback) { |
| + // Create and start the thread. |
| + scoped_ptr<Thread> thread(new Thread()); |
| + thread->Start(); |
| + scoped_ptr<GuardedAsyncInvoker> invoker; |
| + // Create the invoker on |thread|. |
| + thread->Invoke<void>(CreateInvoker(&invoker)); |
| + // Kill |thread|. |
| + thread = nullptr; |
| + // Try calling functor. |
| + invoker->AsyncInvoke(FunctorC(), &GuardedAsyncInvokeTest::IntCallback, |
| + static_cast<GuardedAsyncInvokeTest*>(this)); |
| + // With thread gone, callback should be cancelled. |
| + Thread::Current()->ProcessMessages(kWaitTimeout); |
| + EXPECT_EQ(0, int_value_); |
| +} |
| + |
| +// The remaining tests check that GuardedAsyncInvoker behaves as AsyncInvoker |
| +// when Thread is still alive. |
| +TEST_F(GuardedAsyncInvokeTest, FireAndForget) { |
| + GuardedAsyncInvoker invoker; |
| + // Try calling functor. |
| + bool called = false; |
| + invoker.AsyncInvoke<void>(FunctorB(&called)); |
| + EXPECT_TRUE_WAIT(called, kWaitTimeout); |
| +} |
| + |
| +TEST_F(GuardedAsyncInvokeTest, WithCallback) { |
| + GuardedAsyncInvoker invoker; |
| + // Try calling functor. |
| + SetExpectedThreadForIntCallback(Thread::Current()); |
| + invoker.AsyncInvoke(FunctorA(), &GuardedAsyncInvokeTest::IntCallback, |
| + static_cast<GuardedAsyncInvokeTest*>(this)); |
| + EXPECT_EQ_WAIT(42, int_value_, kWaitTimeout); |
| +} |
| + |
| +TEST_F(GuardedAsyncInvokeTest, CancelInvoker) { |
| + // Try destroying invoker during call. |
| + { |
| + GuardedAsyncInvoker invoker; |
| + invoker.AsyncInvoke(FunctorC(), &GuardedAsyncInvokeTest::IntCallback, |
| + static_cast<GuardedAsyncInvokeTest*>(this)); |
| + } |
| + // With invoker gone, callback should be cancelled. |
| + Thread::Current()->ProcessMessages(kWaitTimeout); |
| + EXPECT_EQ(0, int_value_); |
| +} |
| + |
| +TEST_F(GuardedAsyncInvokeTest, CancelCallingThread) { |
| + GuardedAsyncInvoker invoker; |
| + // Try destroying calling thread during call. |
| + { |
| + Thread thread; |
| + thread.Start(); |
| + // Try calling functor. |
| + thread.Invoke<void>(Bind(&GuardedAsyncInvokeTest::AsyncInvokeIntCallback, |
| + static_cast<GuardedAsyncInvokeTest*>(this), |
| + &invoker, Thread::Current())); |
| + // Wait for the call to begin. |
| + ASSERT_TRUE(invoke_started_.Wait(kWaitTimeout)); |
| + } |
| + // Calling thread is gone. Return message shouldn't happen. |
| + Thread::Current()->ProcessMessages(kWaitTimeout); |
| + EXPECT_EQ(0, int_value_); |
| +} |
| + |
| +TEST_F(GuardedAsyncInvokeTest, KillInvokerBeforeExecute) { |
| + Thread thread; |
| + thread.Start(); |
| + { |
| + GuardedAsyncInvoker invoker; |
| + // Try calling functor. |
| + thread.Invoke<void>(Bind(&GuardedAsyncInvokeTest::AsyncInvokeIntCallback, |
| + static_cast<GuardedAsyncInvokeTest*>(this), |
| + &invoker, Thread::Current())); |
| + // Wait for the call to begin. |
| + ASSERT_TRUE(invoke_started_.Wait(kWaitTimeout)); |
| + } |
| + // Invoker is destroyed. Function should not execute. |
| + Thread::Current()->ProcessMessages(kWaitTimeout); |
| + EXPECT_EQ(0, int_value_); |
| +} |
| + |
| +TEST_F(GuardedAsyncInvokeTest, Flush) { |
| + GuardedAsyncInvoker invoker; |
| + bool flag1 = false; |
| + bool flag2 = false; |
| + // Queue two async calls to the current thread. |
| + invoker.AsyncInvoke<void>(FunctorB(&flag1)); |
| + invoker.AsyncInvoke<void>(FunctorB(&flag2)); |
| + // Because we haven't pumped messages, these should not have run yet. |
| + EXPECT_FALSE(flag1); |
| + EXPECT_FALSE(flag2); |
| + // Force them to run now. |
| + invoker.Flush(); |
| + EXPECT_TRUE(flag1); |
| + EXPECT_TRUE(flag2); |
| +} |
| + |
| +TEST_F(GuardedAsyncInvokeTest, FlushWithIds) { |
| + GuardedAsyncInvoker invoker; |
| + bool flag1 = false; |
| + bool flag2 = false; |
| + // Queue two async calls to the current thread, one with a message id. |
| + invoker.AsyncInvoke<void>(FunctorB(&flag1), 5); |
| + invoker.AsyncInvoke<void>(FunctorB(&flag2)); |
| + // Because we haven't pumped messages, these should not have run yet. |
| + EXPECT_FALSE(flag1); |
| + EXPECT_FALSE(flag2); |
| + // Execute pending calls with id == 5. |
| + invoker.Flush(5); |
| + EXPECT_TRUE(flag1); |
| + EXPECT_FALSE(flag2); |
| + flag1 = false; |
| + // Execute all pending calls. The id == 5 call should not execute again. |
| + invoker.Flush(); |
| + EXPECT_FALSE(flag1); |
| + EXPECT_TRUE(flag2); |
| +} |
| #if defined(WEBRTC_WIN) |
| class ComThreadTest : public testing::Test, public MessageHandler { |