xref: /aosp_15_r20/external/webrtc/api/sequence_checker_unittest.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "api/sequence_checker.h"
12 
13 #include <memory>
14 #include <utility>
15 
16 #include "api/function_view.h"
17 #include "api/units/time_delta.h"
18 #include "rtc_base/event.h"
19 #include "rtc_base/platform_thread.h"
20 #include "rtc_base/task_queue_for_test.h"
21 #include "test/gmock.h"
22 #include "test/gtest.h"
23 
24 using testing::HasSubstr;
25 
26 namespace webrtc {
27 namespace {
28 
29 // This class is dead code, but its purpose is to make sure that
30 // SequenceChecker is compatible with the RTC_GUARDED_BY and RTC_RUN_ON
31 // attributes that are checked at compile-time.
32 class CompileTimeTestForGuardedBy {
33  public:
CalledOnSequence()34   int CalledOnSequence() RTC_RUN_ON(sequence_checker_) { return guarded_; }
35 
CallMeFromSequence()36   void CallMeFromSequence() {
37     RTC_DCHECK_RUN_ON(&sequence_checker_);
38     guarded_ = 41;
39   }
40 
41  private:
42   int guarded_ RTC_GUARDED_BY(sequence_checker_);
43   ::webrtc::SequenceChecker sequence_checker_;
44 };
45 
RunOnDifferentThread(rtc::FunctionView<void ()> run)46 void RunOnDifferentThread(rtc::FunctionView<void()> run) {
47   rtc::Event thread_has_run_event;
48   rtc::PlatformThread::SpawnJoinable(
49       [&] {
50         run();
51         thread_has_run_event.Set();
52       },
53       "thread");
54   EXPECT_TRUE(thread_has_run_event.Wait(TimeDelta::Seconds(1)));
55 }
56 
57 }  // namespace
58 
TEST(SequenceCheckerTest,CallsAllowedOnSameThread)59 TEST(SequenceCheckerTest, CallsAllowedOnSameThread) {
60   SequenceChecker sequence_checker;
61   EXPECT_TRUE(sequence_checker.IsCurrent());
62 }
63 
TEST(SequenceCheckerTest,DestructorAllowedOnDifferentThread)64 TEST(SequenceCheckerTest, DestructorAllowedOnDifferentThread) {
65   auto sequence_checker = std::make_unique<SequenceChecker>();
66   RunOnDifferentThread([&] {
67     // Verify that the destructor doesn't assert when called on a different
68     // thread.
69     sequence_checker.reset();
70   });
71 }
72 
TEST(SequenceCheckerTest,Detach)73 TEST(SequenceCheckerTest, Detach) {
74   SequenceChecker sequence_checker;
75   sequence_checker.Detach();
76   RunOnDifferentThread([&] { EXPECT_TRUE(sequence_checker.IsCurrent()); });
77 }
78 
TEST(SequenceCheckerTest,DetachFromThreadAndUseOnTaskQueue)79 TEST(SequenceCheckerTest, DetachFromThreadAndUseOnTaskQueue) {
80   SequenceChecker sequence_checker;
81   sequence_checker.Detach();
82   TaskQueueForTest queue;
83   queue.SendTask([&] { EXPECT_TRUE(sequence_checker.IsCurrent()); });
84 }
85 
TEST(SequenceCheckerTest,DetachFromTaskQueueAndUseOnThread)86 TEST(SequenceCheckerTest, DetachFromTaskQueueAndUseOnThread) {
87   TaskQueueForTest queue;
88   queue.SendTask([] {
89     SequenceChecker sequence_checker;
90     sequence_checker.Detach();
91     RunOnDifferentThread([&] { EXPECT_TRUE(sequence_checker.IsCurrent()); });
92   });
93 }
94 
TEST(SequenceCheckerTest,MethodNotAllowedOnDifferentThreadInDebug)95 TEST(SequenceCheckerTest, MethodNotAllowedOnDifferentThreadInDebug) {
96   SequenceChecker sequence_checker;
97   RunOnDifferentThread(
98       [&] { EXPECT_EQ(sequence_checker.IsCurrent(), !RTC_DCHECK_IS_ON); });
99 }
100 
TEST(SequenceCheckerTest,MethodNotAllowedOnDifferentTaskQueueInDebug)101 TEST(SequenceCheckerTest, MethodNotAllowedOnDifferentTaskQueueInDebug) {
102   SequenceChecker sequence_checker;
103   TaskQueueForTest queue;
104   queue.SendTask(
105       [&] { EXPECT_EQ(sequence_checker.IsCurrent(), !RTC_DCHECK_IS_ON); });
106 }
107 
TEST(SequenceCheckerTest,DetachFromTaskQueueInDebug)108 TEST(SequenceCheckerTest, DetachFromTaskQueueInDebug) {
109   SequenceChecker sequence_checker;
110   sequence_checker.Detach();
111 
112   TaskQueueForTest queue1;
113   queue1.SendTask([&] { EXPECT_TRUE(sequence_checker.IsCurrent()); });
114 
115   // IsCurrent should return false in debug builds after moving to
116   // another task queue.
117   TaskQueueForTest queue2;
118   queue2.SendTask(
119       [&] { EXPECT_EQ(sequence_checker.IsCurrent(), !RTC_DCHECK_IS_ON); });
120 }
121 
TEST(SequenceCheckerTest,ExpectationToString)122 TEST(SequenceCheckerTest, ExpectationToString) {
123   TaskQueueForTest queue1;
124 
125   SequenceChecker sequence_checker;
126   sequence_checker.Detach();
127 
128   rtc::Event blocker;
129   queue1.PostTask([&blocker, &sequence_checker]() {
130     (void)sequence_checker.IsCurrent();
131     blocker.Set();
132   });
133 
134   blocker.Wait(rtc::Event::kForever);
135 
136 #if RTC_DCHECK_IS_ON
137 
138   EXPECT_THAT(ExpectationToString(&sequence_checker),
139               HasSubstr("# Expected: TQ:"));
140 
141   // Test for the base class
142   webrtc_sequence_checker_internal::SequenceCheckerImpl* sequence_checker_base =
143       &sequence_checker;
144   EXPECT_THAT(ExpectationToString(sequence_checker_base),
145               HasSubstr("# Expected: TQ:"));
146 
147 #else
148   GTEST_ASSERT_EQ(ExpectationToString(&sequence_checker), "");
149 #endif
150 }
151 
152 class TestAnnotations {
153  public:
TestAnnotations()154   TestAnnotations() : test_var_(false) {}
155 
ModifyTestVar()156   void ModifyTestVar() {
157     RTC_DCHECK_RUN_ON(&checker_);
158     test_var_ = true;
159   }
160 
161  private:
162   bool test_var_ RTC_GUARDED_BY(&checker_);
163   SequenceChecker checker_;
164 };
165 
TEST(SequenceCheckerTest,TestAnnotations)166 TEST(SequenceCheckerTest, TestAnnotations) {
167   TestAnnotations annotations;
168   annotations.ModifyTestVar();
169 }
170 
171 #if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
172 
TestAnnotationsOnWrongQueue()173 void TestAnnotationsOnWrongQueue() {
174   TestAnnotations annotations;
175   TaskQueueForTest queue;
176   queue.SendTask([&] { annotations.ModifyTestVar(); });
177 }
178 
179 #if RTC_DCHECK_IS_ON
180 // Note: Ending the test suite name with 'DeathTest' is important as it causes
181 // gtest to order this test before any other non-death-tests, to avoid potential
182 // global process state pollution such as shared worker threads being started
183 // (e.g. a side effect of calling InitCocoaMultiThreading() on Mac causes one or
184 // two additional threads to be created).
TEST(SequenceCheckerDeathTest,TestAnnotationsOnWrongQueueDebug)185 TEST(SequenceCheckerDeathTest, TestAnnotationsOnWrongQueueDebug) {
186   ASSERT_DEATH({ TestAnnotationsOnWrongQueue(); }, "");
187 }
188 #else
TEST(SequenceCheckerTest,TestAnnotationsOnWrongQueueRelease)189 TEST(SequenceCheckerTest, TestAnnotationsOnWrongQueueRelease) {
190   TestAnnotationsOnWrongQueue();
191 }
192 #endif
193 #endif  // GTEST_HAS_DEATH_TEST
194 }  // namespace webrtc
195