Chromium Code Reviews| Index: webrtc/base/sequenced_task_checker_unittest.cc |
| diff --git a/webrtc/base/sequenced_task_checker_unittest.cc b/webrtc/base/sequenced_task_checker_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..ad51603615eba2a81dab705c0f02eacbc9382990 |
| --- /dev/null |
| +++ b/webrtc/base/sequenced_task_checker_unittest.cc |
| @@ -0,0 +1,224 @@ |
| +/* |
| + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. |
| + * |
| + * Use of this source code is governed by a BSD-style license |
| + * that can be found in the LICENSE file in the root of the source |
| + * tree. An additional intellectual property rights grant can be found |
| + * in the file PATENTS. All contributing project authors may |
| + * be found in the AUTHORS file in the root of the source tree. |
| + */ |
| + |
| +// Borrowed from Chromium's src/base/threading/thread_checker_unittest.cc. |
| + |
| +#include <memory> |
| + |
| +#include "testing/gtest/include/gtest/gtest.h" |
| +#include "webrtc/base/checks.h" |
| +#include "webrtc/base/constructormagic.h" |
| +#include "webrtc/base/sequenced_task_checker.h" |
| +#include "webrtc/base/task_queue.h" |
| +#include "webrtc/base/thread.h" |
| + |
| +namespace rtc { |
| + |
| +namespace { |
| +// Calls SequencedCheckerClass::PlatformThread on another thread. |
| +class CallDoStuffOnThread : public PlatformThread { |
|
tommi
2016/07/12 13:08:56
instead of inheriting from PlatformThread, add a m
perkj_webrtc
2016/07/12 15:22:00
Done.
|
| + public: |
| + explicit CallDoStuffOnThread(bool expect_true, |
|
tommi
2016/07/12 13:08:56
no need for explicit (2 args)
perkj_webrtc
2016/07/12 15:22:00
Done.
|
| + SequencedTaskChecker* sequenced_task_checker) |
| + : PlatformThread(Run, this, "call_do_stuff_on_thread"), |
|
tommi
2016/07/12 13:08:56
&Run
perkj_webrtc
2016/07/12 15:22:00
Done.
|
| + expect_true_(expect_true), |
| + sequenced_task_checker_(sequenced_task_checker) {} |
| + |
| + static bool Run(void* obj) { |
|
tommi
2016/07/12 13:08:56
make private
perkj_webrtc
2016/07/12 15:22:00
Done.
|
| + CallDoStuffOnThread* call_stuff_on_thread = |
| + static_cast<CallDoStuffOnThread*>(obj); |
| + if (call_stuff_on_thread->expect_true_) |
|
tommi
2016/07/12 13:08:56
{}
perkj_webrtc
2016/07/12 15:22:00
Done.
|
| + EXPECT_TRUE( |
|
tommi
2016/07/12 13:08:56
could also do:
EXPECT_EQ(call_stuff_on_thread->ex
perkj_webrtc
2016/07/12 15:22:00
Done.
|
| + call_stuff_on_thread->sequenced_task_checker_->CalledSequentially()); |
| + else |
| + EXPECT_FALSE( |
| + call_stuff_on_thread->sequenced_task_checker_->CalledSequentially()); |
| + return false; |
| + } |
| + |
| + private: |
| + const bool expect_true_; |
| + SequencedTaskChecker* const sequenced_task_checker_; |
| + |
| + RTC_DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread); |
| +}; |
| + |
| +// Deletes SequencedTaskChecker on a different thread. |
| +class DeleteThreadCheckerOnThread : public PlatformThread { |
|
tommi
2016/07/12 13:08:56
Favor object composition over class inheritance.
(
perkj_webrtc
2016/07/12 15:22:00
Done.
|
| + public: |
| + explicit DeleteThreadCheckerOnThread( |
| + std::unique_ptr<SequencedTaskChecker> sequenced_task_checker) |
| + : PlatformThread(Run, this, "delete_sequenced_task_checker_on_thread"), |
|
tommi
2016/07/12 13:08:56
&Run
perkj_webrtc
2016/07/12 15:22:00
Done.
|
| + sequenced_task_checker_(std::move(sequenced_task_checker)) {} |
| + |
| + static bool Run(void* obj) { |
|
tommi
2016/07/12 13:08:56
private (etc)
perkj_webrtc
2016/07/12 15:22:00
Done.
|
| + static_cast<DeleteThreadCheckerOnThread*>(obj) |
| + ->sequenced_task_checker_.reset(); |
| + return false; |
| + } |
| + |
| + private: |
| + std::unique_ptr<SequencedTaskChecker> sequenced_task_checker_; |
| + |
| + RTC_DISALLOW_COPY_AND_ASSIGN(DeleteThreadCheckerOnThread); |
| +}; |
| + |
| +void RunMethodOnDifferentThread(bool expect_true) { |
| + std::unique_ptr<SequencedTaskChecker> sequenced_task_checker( |
| + new SequencedTaskChecker()); |
| + |
| + CallDoStuffOnThread call_on_thread(expect_true, sequenced_task_checker.get()); |
| + |
| + call_on_thread.Start(); |
|
tommi
2016/07/12 13:08:56
Start/Stop could occur implicitly in the ctor/dtor
perkj_webrtc
2016/07/12 15:22:00
Done.
|
| + call_on_thread.Stop(); |
| +} |
| + |
| +void RunMethodOnDifferentTaskQueue(bool expect_true) { |
| + std::unique_ptr<SequencedTaskChecker> sequenced_task_checker( |
| + new SequencedTaskChecker()); |
| + |
| + static const char kQueueName[] = "MethodNotAllowedOnDifferentTq"; |
| + TaskQueue queue(kQueueName); |
| + Event done_event(false, false); |
| + queue.PostTask([&sequenced_task_checker, &done_event, expect_true] { |
| + if (expect_true) |
| + EXPECT_TRUE(sequenced_task_checker->CalledSequentially()); |
| + else |
| + EXPECT_FALSE(sequenced_task_checker->CalledSequentially()); |
| + done_event.Set(); |
| + }); |
| + EXPECT_TRUE(done_event.Wait(1000)); |
| +} |
| + |
| +void DetachThenCallFromDifferentTaskQueue(bool expect_true) { |
| + std::unique_ptr<SequencedTaskChecker> sequenced_task_checker( |
| + new SequencedTaskChecker()); |
| + |
| + sequenced_task_checker->Detach(); |
| + |
| + Event done_event(false, false); |
| + TaskQueue queue1("DetachThenCallFromDifferentTaskQueueImpl1"); |
| + queue1.PostTask([&sequenced_task_checker, &done_event] { |
| + EXPECT_TRUE(sequenced_task_checker->CalledSequentially()); |
| + done_event.Set(); |
| + }); |
| + EXPECT_TRUE(done_event.Wait(1000)); |
| + |
| + // CalledSequentially should return false in debug builds after moving to |
| + // another task queue. |
| + TaskQueue queue2("DetachThenCallFromDifferentTaskQueueImpl2"); |
| + queue2.PostTask([&sequenced_task_checker, &done_event, expect_true] { |
| + if (expect_true) |
| + EXPECT_TRUE(sequenced_task_checker->CalledSequentially()); |
| + else |
| + EXPECT_FALSE(sequenced_task_checker->CalledSequentially()); |
| + done_event.Set(); |
| + }); |
| + done_event.Wait(1000); |
| +} |
| +} // namespace |
| + |
| +TEST(SequencedTaskCheckerTest, CallsAllowedOnSameThread) { |
| + std::unique_ptr<SequencedTaskChecker> sequenced_task_checker( |
| + new SequencedTaskChecker()); |
| + |
| + EXPECT_TRUE(sequenced_task_checker->CalledSequentially()); |
| + |
| + // Verify that the destructor doesn't assert. |
| + sequenced_task_checker.reset(); |
| +} |
| + |
| +TEST(SequencedTaskCheckerTest, DestructorAllowedOnDifferentThread) { |
| + std::unique_ptr<SequencedTaskChecker> sequenced_task_checker( |
| + new SequencedTaskChecker()); |
| + |
| + // Verify that the destructor doesn't assert when called on a different |
| + // thread. |
| + DeleteThreadCheckerOnThread delete_on_thread( |
| + std::move(sequenced_task_checker)); |
| + |
| + delete_on_thread.Start(); |
| + delete_on_thread.Stop(); |
| +} |
| + |
| +TEST(SequencedTaskCheckerTest, DetachFromThread) { |
| + std::unique_ptr<SequencedTaskChecker> sequenced_task_checker( |
| + new SequencedTaskChecker()); |
| + |
| + sequenced_task_checker->Detach(); |
| + CallDoStuffOnThread call_on_thread(true, sequenced_task_checker.get()); |
| + |
| + call_on_thread.Start(); |
| + call_on_thread.Stop(); |
| +} |
| + |
| +TEST(SequencedTaskCheckerTest, DetachFromThreadAndUseOnTaskQueue) { |
| + std::unique_ptr<SequencedTaskChecker> sequenced_task_checker( |
| + new SequencedTaskChecker()); |
| + |
| + sequenced_task_checker->Detach(); |
| + static const char kQueueName[] = "DetachFromThreadAndUseOnTaskQueue"; |
| + TaskQueue queue(kQueueName); |
| + Event done_event(false, false); |
| + queue.PostTask([&sequenced_task_checker, &done_event] { |
| + EXPECT_TRUE(sequenced_task_checker->CalledSequentially()); |
| + done_event.Set(); |
| + }); |
| + EXPECT_TRUE(done_event.Wait(1000)); |
| +} |
| + |
| +TEST(SequencedTaskCheckerTest, DetachFromTaskQueueAndUseOnThread) { |
| + TaskQueue queue("DetachFromTaskQueueAndUseOnThread"); |
| + Event done_event(false, false); |
| + queue.PostTask([&done_event] { |
| + std::unique_ptr<SequencedTaskChecker> sequenced_task_checker( |
| + new SequencedTaskChecker()); |
| + |
| + sequenced_task_checker->Detach(); |
| + CallDoStuffOnThread call_on_thread(true, sequenced_task_checker.get()); |
| + |
| + call_on_thread.Start(); |
| + call_on_thread.Stop(); |
| + |
| + done_event.Set(); |
| + }); |
| + EXPECT_TRUE(done_event.Wait(1000)); |
| +} |
| + |
| +#if !NDEBUG || DCHECK_ALWAYS_ON |
| +TEST(SequencedTaskCheckerTest, MethodNotAllowedOnDifferentThreadInDebug) { |
| + RunMethodOnDifferentThread(false); |
| +} |
| +#else |
| +TEST(SequencedTaskCheckerTest, MethodAllowedOnDifferentThreadInRelease) { |
| + RunMethodOnDifferentThread(true); |
| +} |
| +#endif |
| + |
| +#if !NDEBUG || DCHECK_ALWAYS_ON |
| +TEST(SequencedTaskCheckerTest, MethodNotAllowedOnDifferentTaskQueueInDebug) { |
| + RunMethodOnDifferentTaskQueue(false); |
| +} |
| +#else |
| +TEST(SequencedTaskCheckerTest, MethodAllowedOnDifferentTaskQueueInDebug) { |
| + RunMethodOnDifferentTaskQueue(true); |
| +} |
| +#endif |
| + |
| +#if !NDEBUG || DCHECK_ALWAYS_ON |
| +TEST(SequencedTaskCheckerTest, DetachFromTaskQueueInDebug) { |
| + DetachThenCallFromDifferentTaskQueue(false); |
| +} |
| +#else |
| +TEST(SequencedTaskCheckerTest, DetachFromTaskQueueInRelease) { |
| + DetachThenCallFromDifferentTaskQueue(true); |
| +} |
| +#endif |
| +} // namespace rtc |