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..5fe2a9e8f9949a441642b6b4f99ce2fdddec9104 |
| --- /dev/null |
| +++ b/webrtc/base/sequenced_task_checker_unittest.cc |
| @@ -0,0 +1,303 @@ |
| +/* |
| + * 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" |
| + |
| +// Duplicated from base/threading/sequenced_thread_checker.h so that we can be |
| +// good citizens there and undef the macro. |
| +#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) |
| +#define ENABLE_SEQUENCED_TASK_CHECKER 1 |
|
tommi
2016/07/08 13:15:15
this doesn't look like the right place to change t
perkj_webrtc
2016/07/11 08:38:01
Ok- These tests were a copy of the threadcheker un
|
| +#else |
| +#define ENABLE_SEQUENCED_TASK_CHECKER 0 |
| +#endif |
| + |
| +namespace rtc { |
| + |
| +namespace { |
| + |
| +// Simple class to exercise the basics of SequencedTaskChecker. |
| +class SequencedCheckerClass : public SequencedTaskChecker { |
| + public: |
| + SequencedCheckerClass() {} |
| + |
| + // Verifies that it was called on the same thread as the constructor. |
| + void DoStuff() { RTC_DCHECK(IsCurrent()); } |
|
tommi
2016/07/08 13:15:15
since this is a test, it's probably better to do E
perkj_webrtc
2016/07/11 08:38:01
Done. - No longer using death tests.
|
| + |
| + void DetachFromSequence() { SequencedTaskChecker::Detach(); } |
|
tommi
2016/07/08 13:15:16
Is this method needed or can the caller just call
perkj_webrtc
2016/07/11 08:38:01
Done.
|
| + |
| + static void MethodOnDifferentThreadImpl(); |
| + static void MethodOnDifferentTaskQueueImpl(); |
| + static void DetachThenCallFromDifferentThreadImpl(); |
| + static void DetachThenCallFromDifferentTaskQueueImpl(); |
| + |
| + private: |
| + RTC_DISALLOW_COPY_AND_ASSIGN(SequencedCheckerClass); |
| +}; |
| + |
| +// Calls SequencedCheckerClass::DoStuff on another thread. |
| +class CallDoStuffOnThread : public Thread { |
|
tommi
2016/07/08 13:15:15
instead of using rtc::Thread (which we're using le
perkj_webrtc
2016/07/11 08:38:01
Done.
|
| + public: |
| + explicit CallDoStuffOnThread(SequencedCheckerClass* sequence_checker_class) |
| + : Thread(), sequence_checker_class_(sequence_checker_class) { |
| + SetName("call_do_stuff_on_thread", NULL); |
| + } |
| + |
| + void Run() override { sequence_checker_class_->DoStuff(); } |
| + |
| + // New method. Needed since Thread::Join is protected, and it is called by |
| + // the TEST. |
| + void Join() { Thread::Join(); } |
|
tommi
2016/07/08 13:15:15
I think you can also do:
using Thread::Join;
perkj_webrtc
2016/07/11 08:38:01
Acknowledged.
|
| + |
| + private: |
| + SequencedCheckerClass* sequence_checker_class_; |
| + |
| + RTC_DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread); |
| +}; |
| + |
| +// Deletes SequencedCheckerClass on a different thread. |
| +class DeleteThreadCheckerClassOnThread : public Thread { |
| + public: |
| + explicit DeleteThreadCheckerClassOnThread( |
| + SequencedCheckerClass* sequence_checker_class) |
| + : Thread(), sequenced_checker_class_(sequence_checker_class) { |
| + SetName("delete_sequence_checker_class_on_thread", NULL); |
| + } |
| + |
| + void Run() override { sequenced_checker_class_.reset(); } |
| + |
| + // New method. Needed since Thread::Join is protected, and it is called by |
| + // the TEST. |
| + void Join() { Thread::Join(); } |
| + |
| + private: |
| + std::unique_ptr<SequencedCheckerClass> sequenced_checker_class_; |
| + |
| + RTC_DISALLOW_COPY_AND_ASSIGN(DeleteThreadCheckerClassOnThread); |
| +}; |
| + |
| +} // namespace |
| + |
| +TEST(SequencedTaskCheckerTest, CallsAllowedOnSameThread) { |
| + std::unique_ptr<SequencedCheckerClass> sequence_checker_class( |
| + new SequencedCheckerClass); |
|
tommi
2016/07/08 13:15:15
new SequencedCheckerClass()
perkj_webrtc
2016/07/11 08:38:01
Done.
|
| + |
| + // Verify that DoStuff doesn't assert. |
| + sequence_checker_class->DoStuff(); |
| + |
| + // Verify that the destructor doesn't assert. |
| + sequence_checker_class.reset(); |
| +} |
| + |
| +TEST(SequencedTaskCheckerTest, DestructorAllowedOnDifferentThread) { |
| + std::unique_ptr<SequencedCheckerClass> sequence_checker_class( |
| + new SequencedCheckerClass); |
| + |
| + // Verify that the destructor doesn't assert |
| + // when called on a different thread. |
| + DeleteThreadCheckerClassOnThread delete_on_thread( |
| + sequence_checker_class.release()); |
| + |
| + delete_on_thread.Start(); |
| + delete_on_thread.Join(); |
| +} |
| + |
| +TEST(SequencedTaskCheckerTest, DetachFromThread) { |
| + std::unique_ptr<SequencedCheckerClass> sequence_checker_class( |
| + new SequencedCheckerClass); |
| + |
| + // Verify that DoStuff doesn't assert when called on a different thread after |
| + // a call to DetachFromSequence. |
| + sequence_checker_class->DetachFromSequence(); |
| + CallDoStuffOnThread call_on_thread(sequence_checker_class.get()); |
| + |
| + call_on_thread.Start(); |
| + call_on_thread.Join(); |
| +} |
| + |
| +TEST(SequencedTaskCheckerTest, DetachFromThreadAndUseOnTaskQueue) { |
| + std::unique_ptr<SequencedCheckerClass> sequence_checker_class( |
| + new SequencedCheckerClass); |
| + |
| + // Verify that DoStuff doesn't assert when called on a different tq after |
| + // a call to DetachFromSequence. |
| + sequence_checker_class->DetachFromSequence(); |
| + static const char kQueueName[] = "DetachFromThreadAndUseOnTaskQueue"; |
| + TaskQueue queue(kQueueName); |
| + Event done_event(false, false); |
| + queue.PostTask([&sequence_checker_class, &done_event] { |
| + sequence_checker_class->DoStuff(); |
| + 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<SequencedCheckerClass> sequence_checker_class( |
| + new SequencedCheckerClass); |
| + |
| + // Verify that DoStuff doesn't assert when called on a different thread |
| + // after a call to DetachFromSequence. |
| + sequence_checker_class->DetachFromSequence(); |
| + CallDoStuffOnThread call_on_thread(sequence_checker_class.get()); |
| + |
| + call_on_thread.Start(); |
| + call_on_thread.Join(); |
| + |
| + done_event.Set(); |
| + }); |
| + EXPECT_TRUE(done_event.Wait(1000)); |
| +} |
| + |
| +#if GTEST_HAS_DEATH_TEST || !ENABLE_SEQUENCED_TASK_CHECKER |
|
tommi
2016/07/08 13:15:15
I'm having problems groking this check... can you
perkj_webrtc
2016/07/11 08:38:01
Refactored to no longer use death tests.
|
| + |
| +void SequencedCheckerClass::MethodOnDifferentThreadImpl() { |
| + std::unique_ptr<SequencedCheckerClass> sequence_checker_class( |
| + new SequencedCheckerClass); |
| + |
| + // DoStuff should assert in debug builds only when called on a |
| + // different thread. |
| + CallDoStuffOnThread call_on_thread(sequence_checker_class.get()); |
| + |
| + call_on_thread.Start(); |
| + call_on_thread.Join(); |
| +} |
| + |
| +#if ENABLE_SEQUENCED_TASK_CHECKER |
| +TEST(SequencedTaskCheckerDeathTest, MethodNotAllowedOnDifferentThreadInDebug) { |
| + ASSERT_DEATH({ SequencedCheckerClass::MethodOnDifferentThreadImpl(); }, ""); |
| +} |
| +#else |
| +TEST(SequencedTaskCheckerDeathTest, MethodAllowedOnDifferentThreadInRelease) { |
| + SequencedCheckerClass::MethodOnDifferentThreadImpl(); |
| +} |
| +#endif // ENABLE_SEQUENCED_TASK_CHECKER |
| + |
| +void SequencedCheckerClass::MethodOnDifferentTaskQueueImpl() { |
| + std::unique_ptr<SequencedCheckerClass> sequence_checker_class( |
| + new SequencedCheckerClass); |
| + |
| + // Verify that DoStuff assert when called on a tq. |
| + static const char kQueueName[] = "MethodNotAllowedOnDifferentTq"; |
| + TaskQueue queue(kQueueName); |
| + Event done_event(false, false); |
| + queue.PostTask([&sequence_checker_class, &done_event] { |
| + sequence_checker_class->DoStuff(); |
| + done_event.Set(); |
| + }); |
| + EXPECT_TRUE(done_event.Wait(1000)); |
| +} |
| + |
| +#if ENABLE_SEQUENCED_TASK_CHECKER |
| +TEST(SequencedTaskCheckerDeathTest, MethodNotAllowedOnDifferentTqInDebug) { |
| + ASSERT_DEATH({ SequencedCheckerClass::MethodOnDifferentTaskQueueImpl(); }, |
| + ""); |
| +} |
| +#else |
| +TEST(SequencedTaskCheckerDeathTest, MethodAllowedOnDifferentTqInRelease) { |
| + SequencedCheckerClass::MethodOnDifferentTaskQueueImpl(); |
| +} |
| +#endif // ENABLE_SEQUENCED_TASK_CHECKER |
| + |
| +void SequencedCheckerClass::DetachThenCallFromDifferentTaskQueueImpl() { |
| + std::unique_ptr<SequencedCheckerClass> sequence_checker_class( |
| + new SequencedCheckerClass); |
| + |
| + // DoStuff doesn't assert when called on a different task queue |
| + // after a call to DetachFromSequence. |
| + sequence_checker_class->DetachFromSequence(); |
| + |
| + Event done_event(false, false); |
| + TaskQueue queue1("DetachThenCallFromDifferentTaskQueueImpl1"); |
| + queue1.PostTask([&sequence_checker_class, &done_event] { |
| + sequence_checker_class->DoStuff(); |
| + done_event.Set(); |
| + }); |
| + EXPECT_TRUE(done_event.Wait(1000)); |
| + |
| + // DoStuff should assert in debug builds only after moving to |
| + // another task queue. |
| + TaskQueue queue2("DetachThenCallFromDifferentTaskQueueImpl2"); |
| + queue2.PostTask([&sequence_checker_class, &done_event] { |
| + sequence_checker_class->DoStuff(); |
| + done_event.Set(); |
| + }); |
| + done_event.Wait(1000); |
| +} |
| + |
| +#if ENABLE_SEQUENCED_TASK_CHECKER |
| +TEST(SequencedTaskCheckerDeathTest, DetachFromTaskQueueInDebug) { |
| + ASSERT_DEATH( |
| + { SequencedCheckerClass::DetachThenCallFromDifferentTaskQueueImpl(); }, |
| + ""); |
| +} |
| +#else |
| +TEST(SequencedTaskCheckerDeathTest, DetachFromThreadInRelease) { |
| + SequencedCheckerClass::DetachThenCallFromDifferentTaskQueueImpl(); |
| +} |
| +#endif // ENABLE_THREAD_CHECKER |
| + |
| +#endif // GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER |
| + |
| +class SequencedTaskCheckerAnnotateTest { |
| + public: |
| + // Next two function should create warnings when compile (e.g. if used with |
| + // specific T). |
| + // TODO(danilchap): Find a way to test they do not compile when thread |
| + // annotation checks enabled. |
| + template <typename T> |
| + void access_var_no_annotate() { |
|
tommi
2016/07/08 13:15:15
AccessVarNoAnnotate (since this isn't a getter)
perkj_webrtc
2016/07/11 08:38:01
removed all for now.
|
| + var_checker_ = 42; |
| + } |
| + |
| + template <typename T> |
| + void access_fun_no_annotate() { |
|
tommi
2016/07/08 13:15:15
AccessFunctionNoAnnotate etc
perkj_webrtc
2016/07/11 08:38:01
dito
|
| + function(); |
| + } |
| + |
| + // Function below should be able to compile. |
| + void access_var_annotate_checker() { |
| + RTC_DCHECK_RUN_ON(&checker_); |
| + var_checker_ = 44; |
| + } |
| + |
| + void access_fun_annotate() { |
| + RTC_DCHECK_RUN_ON(&checker_); |
| + function(); |
| + } |
| + |
| + private: |
| + void function() RUN_ON(checker_) {} |
| + |
| + rtc::SequencedTaskChecker checker_; |
| + |
| + int var_checker_ GUARDED_BY(checker_); |
| +}; |
| + |
| +TEST(SequencedTaskCheckerAnnotateTest, test) { |
| + SequencedTaskCheckerAnnotateTest tester; |
| + tester.access_var_annotate_checker(); |
| +} |
| + |
| +// Just in case we ever get lumped together with other compilation units. |
| +#undef ENABLE_SEQUENCED_TASK_CHECKER |
|
tommi
2016/07/08 13:15:15
this could only happen if another file #includes s
perkj_webrtc
2016/07/11 08:38:01
Acknowledged.
|
| + |
| +} // namespace rtc |