176 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			176 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			C++
		
	
	
	
| /*
 | |
|  *  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.
 | |
|  */
 | |
| 
 | |
| #include "rtc_base/synchronization/sequence_checker.h"
 | |
| 
 | |
| #include <memory>
 | |
| #include <utility>
 | |
| 
 | |
| #include "api/function_view.h"
 | |
| #include "rtc_base/event.h"
 | |
| #include "rtc_base/platform_thread.h"
 | |
| #include "rtc_base/task_queue_for_test.h"
 | |
| #include "rtc_base/thread_checker.h"
 | |
| #include "test/gtest.h"
 | |
| 
 | |
| namespace webrtc {
 | |
| namespace {
 | |
| 
 | |
| // This class is dead code, but its purpose is to make sure that
 | |
| // SequenceChecker is compatible with the RTC_GUARDED_BY and RTC_RUN_ON
 | |
| // attributes that are checked at compile-time.
 | |
| class CompileTimeTestForGuardedBy {
 | |
|  public:
 | |
|   int CalledOnSequence() RTC_RUN_ON(sequence_checker_) { return guarded_; }
 | |
| 
 | |
|   void CallMeFromSequence() {
 | |
|     RTC_DCHECK_RUN_ON(&sequence_checker_);
 | |
|     guarded_ = 41;
 | |
|   }
 | |
| 
 | |
|  private:
 | |
|   int guarded_ RTC_GUARDED_BY(sequence_checker_);
 | |
|   ::webrtc::SequenceChecker sequence_checker_;
 | |
| };
 | |
| 
 | |
| void RunOnDifferentThread(rtc::FunctionView<void()> run) {
 | |
|   struct Object {
 | |
|     static void Run(void* obj) {
 | |
|       auto* me = static_cast<Object*>(obj);
 | |
|       me->run();
 | |
|       me->thread_has_run_event.Set();
 | |
|     }
 | |
| 
 | |
|     rtc::FunctionView<void()> run;
 | |
|     rtc::Event thread_has_run_event;
 | |
|   } object{run};
 | |
| 
 | |
|   rtc::PlatformThread thread(&Object::Run, &object, "thread");
 | |
|   thread.Start();
 | |
|   EXPECT_TRUE(object.thread_has_run_event.Wait(1000));
 | |
|   thread.Stop();
 | |
| }
 | |
| 
 | |
| }  // namespace
 | |
| 
 | |
| TEST(SequenceCheckerTest, CallsAllowedOnSameThread) {
 | |
|   SequenceChecker sequence_checker;
 | |
|   EXPECT_TRUE(sequence_checker.IsCurrent());
 | |
| }
 | |
| 
 | |
| TEST(SequenceCheckerTest, DestructorAllowedOnDifferentThread) {
 | |
|   auto sequence_checker = std::make_unique<SequenceChecker>();
 | |
|   RunOnDifferentThread([&] {
 | |
|     // Verify that the destructor doesn't assert when called on a different
 | |
|     // thread.
 | |
|     sequence_checker.reset();
 | |
|   });
 | |
| }
 | |
| 
 | |
| TEST(SequenceCheckerTest, Detach) {
 | |
|   SequenceChecker sequence_checker;
 | |
|   sequence_checker.Detach();
 | |
|   RunOnDifferentThread([&] { EXPECT_TRUE(sequence_checker.IsCurrent()); });
 | |
| }
 | |
| 
 | |
| TEST(SequenceCheckerTest, DetachFromThreadAndUseOnTaskQueue) {
 | |
|   SequenceChecker sequence_checker;
 | |
|   sequence_checker.Detach();
 | |
|   TaskQueueForTest queue;
 | |
|   queue.SendTask([&] { EXPECT_TRUE(sequence_checker.IsCurrent()); },
 | |
|                  RTC_FROM_HERE);
 | |
| }
 | |
| 
 | |
| TEST(SequenceCheckerTest, DetachFromTaskQueueAndUseOnThread) {
 | |
|   TaskQueueForTest queue;
 | |
|   queue.SendTask(
 | |
|       [] {
 | |
|         SequenceChecker sequence_checker;
 | |
|         sequence_checker.Detach();
 | |
|         RunOnDifferentThread(
 | |
|             [&] { EXPECT_TRUE(sequence_checker.IsCurrent()); });
 | |
|       },
 | |
|       RTC_FROM_HERE);
 | |
| }
 | |
| 
 | |
| TEST(SequenceCheckerTest, MethodNotAllowedOnDifferentThreadInDebug) {
 | |
|   SequenceChecker sequence_checker;
 | |
|   RunOnDifferentThread(
 | |
|       [&] { EXPECT_EQ(sequence_checker.IsCurrent(), !RTC_DCHECK_IS_ON); });
 | |
| }
 | |
| 
 | |
| TEST(SequenceCheckerTest, MethodNotAllowedOnDifferentTaskQueueInDebug) {
 | |
|   SequenceChecker sequence_checker;
 | |
|   TaskQueueForTest queue;
 | |
|   queue.SendTask(
 | |
|       [&] { EXPECT_EQ(sequence_checker.IsCurrent(), !RTC_DCHECK_IS_ON); },
 | |
|       RTC_FROM_HERE);
 | |
| }
 | |
| 
 | |
| TEST(SequenceCheckerTest, DetachFromTaskQueueInDebug) {
 | |
|   SequenceChecker sequence_checker;
 | |
|   sequence_checker.Detach();
 | |
| 
 | |
|   TaskQueueForTest queue1;
 | |
|   queue1.SendTask([&] { EXPECT_TRUE(sequence_checker.IsCurrent()); },
 | |
|                   RTC_FROM_HERE);
 | |
| 
 | |
|   // IsCurrent should return false in debug builds after moving to
 | |
|   // another task queue.
 | |
|   TaskQueueForTest queue2;
 | |
|   queue2.SendTask(
 | |
|       [&] { EXPECT_EQ(sequence_checker.IsCurrent(), !RTC_DCHECK_IS_ON); },
 | |
|       RTC_FROM_HERE);
 | |
| }
 | |
| 
 | |
| class TestAnnotations {
 | |
|  public:
 | |
|   TestAnnotations() : test_var_(false) {}
 | |
| 
 | |
|   void ModifyTestVar() {
 | |
|     RTC_DCHECK_RUN_ON(&checker_);
 | |
|     test_var_ = true;
 | |
|   }
 | |
| 
 | |
|  private:
 | |
|   bool test_var_ RTC_GUARDED_BY(&checker_);
 | |
|   SequenceChecker checker_;
 | |
| };
 | |
| 
 | |
| TEST(SequenceCheckerTest, TestAnnotations) {
 | |
|   TestAnnotations annotations;
 | |
|   annotations.ModifyTestVar();
 | |
| }
 | |
| 
 | |
| #if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
 | |
| 
 | |
| void TestAnnotationsOnWrongQueue() {
 | |
|   TestAnnotations annotations;
 | |
|   TaskQueueForTest queue;
 | |
|   queue.SendTask([&] { annotations.ModifyTestVar(); }, RTC_FROM_HERE);
 | |
| }
 | |
| 
 | |
| #if RTC_DCHECK_IS_ON
 | |
| // Note: Ending the test suite name with 'DeathTest' is important as it causes
 | |
| // gtest to order this test before any other non-death-tests, to avoid potential
 | |
| // global process state pollution such as shared worker threads being started
 | |
| // (e.g. a side effect of calling InitCocoaMultiThreading() on Mac causes one or
 | |
| // two additional threads to be created).
 | |
| TEST(SequenceCheckerDeathTest, TestAnnotationsOnWrongQueueDebug) {
 | |
|   ASSERT_DEATH({ TestAnnotationsOnWrongQueue(); }, "");
 | |
| }
 | |
| #else
 | |
| TEST(SequenceCheckerTest, TestAnnotationsOnWrongQueueRelease) {
 | |
|   TestAnnotationsOnWrongQueue();
 | |
| }
 | |
| #endif
 | |
| #endif  // GTEST_HAS_DEATH_TEST
 | |
| }  // namespace webrtc
 |