blob: 4029b8c9a012ec1beac1dd556d62620e4f01952b [file] [log] [blame]
Sebastian Janssonb55015e2019-04-09 13:44:04 +02001/*
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
Artem Titovb586d822021-02-04 15:06:50 +010011#include "api/sequence_checker.h"
Sebastian Janssonb55015e2019-04-09 13:44:04 +020012
13#include <memory>
14#include <utility>
15
Sebastian Janssonb55015e2019-04-09 13:44:04 +020016#include "api/function_view.h"
17#include "rtc_base/event.h"
18#include "rtc_base/platform_thread.h"
19#include "rtc_base/task_queue_for_test.h"
Sebastian Janssonb55015e2019-04-09 13:44:04 +020020#include "test/gtest.h"
21
22namespace webrtc {
23namespace {
24
25// This class is dead code, but its purpose is to make sure that
26// SequenceChecker is compatible with the RTC_GUARDED_BY and RTC_RUN_ON
27// attributes that are checked at compile-time.
28class CompileTimeTestForGuardedBy {
29 public:
30 int CalledOnSequence() RTC_RUN_ON(sequence_checker_) { return guarded_; }
31
32 void CallMeFromSequence() {
Tomas Gunnarsson4d177eb2020-06-08 23:08:46 +020033 RTC_DCHECK_RUN_ON(&sequence_checker_);
Sebastian Janssonb55015e2019-04-09 13:44:04 +020034 guarded_ = 41;
35 }
36
37 private:
38 int guarded_ RTC_GUARDED_BY(sequence_checker_);
39 ::webrtc::SequenceChecker sequence_checker_;
40};
41
42void RunOnDifferentThread(rtc::FunctionView<void()> run) {
43 struct Object {
44 static void Run(void* obj) {
45 auto* me = static_cast<Object*>(obj);
46 me->run();
47 me->thread_has_run_event.Set();
48 }
49
50 rtc::FunctionView<void()> run;
51 rtc::Event thread_has_run_event;
52 } object{run};
53
54 rtc::PlatformThread thread(&Object::Run, &object, "thread");
55 thread.Start();
56 EXPECT_TRUE(object.thread_has_run_event.Wait(1000));
57 thread.Stop();
58}
59
60} // namespace
61
62TEST(SequenceCheckerTest, CallsAllowedOnSameThread) {
63 SequenceChecker sequence_checker;
64 EXPECT_TRUE(sequence_checker.IsCurrent());
65}
66
67TEST(SequenceCheckerTest, DestructorAllowedOnDifferentThread) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +020068 auto sequence_checker = std::make_unique<SequenceChecker>();
Sebastian Janssonb55015e2019-04-09 13:44:04 +020069 RunOnDifferentThread([&] {
70 // Verify that the destructor doesn't assert when called on a different
71 // thread.
72 sequence_checker.reset();
73 });
74}
75
76TEST(SequenceCheckerTest, Detach) {
77 SequenceChecker sequence_checker;
78 sequence_checker.Detach();
79 RunOnDifferentThread([&] { EXPECT_TRUE(sequence_checker.IsCurrent()); });
80}
81
82TEST(SequenceCheckerTest, DetachFromThreadAndUseOnTaskQueue) {
83 SequenceChecker sequence_checker;
84 sequence_checker.Detach();
85 TaskQueueForTest queue;
Danil Chapovaloveb90e6f2019-10-15 10:04:57 +020086 queue.SendTask([&] { EXPECT_TRUE(sequence_checker.IsCurrent()); },
87 RTC_FROM_HERE);
Sebastian Janssonb55015e2019-04-09 13:44:04 +020088}
89
90TEST(SequenceCheckerTest, DetachFromTaskQueueAndUseOnThread) {
91 TaskQueueForTest queue;
Danil Chapovaloveb90e6f2019-10-15 10:04:57 +020092 queue.SendTask(
93 [] {
94 SequenceChecker sequence_checker;
95 sequence_checker.Detach();
96 RunOnDifferentThread(
97 [&] { EXPECT_TRUE(sequence_checker.IsCurrent()); });
98 },
99 RTC_FROM_HERE);
Sebastian Janssonb55015e2019-04-09 13:44:04 +0200100}
101
102TEST(SequenceCheckerTest, MethodNotAllowedOnDifferentThreadInDebug) {
103 SequenceChecker sequence_checker;
104 RunOnDifferentThread(
105 [&] { EXPECT_EQ(sequence_checker.IsCurrent(), !RTC_DCHECK_IS_ON); });
106}
107
108TEST(SequenceCheckerTest, MethodNotAllowedOnDifferentTaskQueueInDebug) {
109 SequenceChecker sequence_checker;
110 TaskQueueForTest queue;
111 queue.SendTask(
Danil Chapovaloveb90e6f2019-10-15 10:04:57 +0200112 [&] { EXPECT_EQ(sequence_checker.IsCurrent(), !RTC_DCHECK_IS_ON); },
113 RTC_FROM_HERE);
Sebastian Janssonb55015e2019-04-09 13:44:04 +0200114}
115
116TEST(SequenceCheckerTest, DetachFromTaskQueueInDebug) {
117 SequenceChecker sequence_checker;
118 sequence_checker.Detach();
119
120 TaskQueueForTest queue1;
Danil Chapovaloveb90e6f2019-10-15 10:04:57 +0200121 queue1.SendTask([&] { EXPECT_TRUE(sequence_checker.IsCurrent()); },
122 RTC_FROM_HERE);
Sebastian Janssonb55015e2019-04-09 13:44:04 +0200123
124 // IsCurrent should return false in debug builds after moving to
125 // another task queue.
126 TaskQueueForTest queue2;
127 queue2.SendTask(
Danil Chapovaloveb90e6f2019-10-15 10:04:57 +0200128 [&] { EXPECT_EQ(sequence_checker.IsCurrent(), !RTC_DCHECK_IS_ON); },
129 RTC_FROM_HERE);
Sebastian Janssonb55015e2019-04-09 13:44:04 +0200130}
131
132class TestAnnotations {
133 public:
134 TestAnnotations() : test_var_(false) {}
135
136 void ModifyTestVar() {
137 RTC_DCHECK_RUN_ON(&checker_);
138 test_var_ = true;
139 }
140
141 private:
142 bool test_var_ RTC_GUARDED_BY(&checker_);
143 SequenceChecker checker_;
144};
145
146TEST(SequenceCheckerTest, TestAnnotations) {
147 TestAnnotations annotations;
148 annotations.ModifyTestVar();
149}
150
151#if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
152
153void TestAnnotationsOnWrongQueue() {
154 TestAnnotations annotations;
155 TaskQueueForTest queue;
Danil Chapovaloveb90e6f2019-10-15 10:04:57 +0200156 queue.SendTask([&] { annotations.ModifyTestVar(); }, RTC_FROM_HERE);
Sebastian Janssonb55015e2019-04-09 13:44:04 +0200157}
158
159#if RTC_DCHECK_IS_ON
Tommiec3ba732020-05-17 14:33:40 +0200160// Note: Ending the test suite name with 'DeathTest' is important as it causes
161// gtest to order this test before any other non-death-tests, to avoid potential
162// global process state pollution such as shared worker threads being started
163// (e.g. a side effect of calling InitCocoaMultiThreading() on Mac causes one or
164// two additional threads to be created).
165TEST(SequenceCheckerDeathTest, TestAnnotationsOnWrongQueueDebug) {
Sebastian Janssonb55015e2019-04-09 13:44:04 +0200166 ASSERT_DEATH({ TestAnnotationsOnWrongQueue(); }, "");
167}
168#else
169TEST(SequenceCheckerTest, TestAnnotationsOnWrongQueueRelease) {
170 TestAnnotationsOnWrongQueue();
171}
172#endif
173#endif // GTEST_HAS_DEATH_TEST
174} // namespace webrtc