blob: d77546289dc98b526bbedd7eb044e603a5a16e31 [file] [log] [blame]
perkj9c16fe82016-07-12 15:04:07 -07001/*
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 */
kwibergac9f8762016-09-30 22:29:43 -070010
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "rtc_base/sequenced_task_checker.h"
12#include "rtc_base/checks.h"
13#include "rtc_base/constructormagic.h"
14#include "rtc_base/platform_thread.h"
15#include "rtc_base/task_queue.h"
16#include "test/gtest.h"
perkj9c16fe82016-07-12 15:04:07 -070017
18namespace rtc {
19
20namespace {
21// Calls SequencedTaskChecker::CalledSequentially on another thread.
22class CallCalledSequentiallyOnThread {
23 public:
24 CallCalledSequentiallyOnThread(bool expect_true,
25 SequencedTaskChecker* sequenced_task_checker)
26 : expect_true_(expect_true),
27 thread_has_run_event_(false, false),
28 thread_(&Run, this, "call_do_stuff_on_thread"),
29 sequenced_task_checker_(sequenced_task_checker) {
30 thread_.Start();
31 }
32 ~CallCalledSequentiallyOnThread() {
33 EXPECT_TRUE(thread_has_run_event_.Wait(1000));
34 thread_.Stop();
35 }
36
37 private:
tommi0f8b4032017-02-22 11:22:05 -080038 static void Run(void* obj) {
perkj9c16fe82016-07-12 15:04:07 -070039 CallCalledSequentiallyOnThread* call_stuff_on_thread =
40 static_cast<CallCalledSequentiallyOnThread*>(obj);
41 EXPECT_EQ(
42 call_stuff_on_thread->expect_true_,
43 call_stuff_on_thread->sequenced_task_checker_->CalledSequentially());
44 call_stuff_on_thread->thread_has_run_event_.Set();
perkj9c16fe82016-07-12 15:04:07 -070045 }
46
47 const bool expect_true_;
48 Event thread_has_run_event_;
49 PlatformThread thread_;
50 SequencedTaskChecker* const sequenced_task_checker_;
51
52 RTC_DISALLOW_COPY_AND_ASSIGN(CallCalledSequentiallyOnThread);
53};
54
55// Deletes SequencedTaskChecker on a different thread.
56class DeleteSequencedCheckerOnThread {
57 public:
58 explicit DeleteSequencedCheckerOnThread(
59 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker)
60 : thread_(&Run, this, "delete_sequenced_task_checker_on_thread"),
61 thread_has_run_event_(false, false),
62 sequenced_task_checker_(std::move(sequenced_task_checker)) {
63 thread_.Start();
64 }
65
66 ~DeleteSequencedCheckerOnThread() {
67 EXPECT_TRUE(thread_has_run_event_.Wait(1000));
68 thread_.Stop();
69 }
70
71 private:
72 static bool Run(void* obj) {
73 DeleteSequencedCheckerOnThread* instance =
74 static_cast<DeleteSequencedCheckerOnThread*>(obj);
75 instance->sequenced_task_checker_.reset();
76 instance->thread_has_run_event_.Set();
77 return false;
78 }
79
80 private:
81 PlatformThread thread_;
82 Event thread_has_run_event_;
83 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker_;
84
85 RTC_DISALLOW_COPY_AND_ASSIGN(DeleteSequencedCheckerOnThread);
86};
87
88void RunMethodOnDifferentThread(bool expect_true) {
89 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
90 new SequencedTaskChecker());
91
92 CallCalledSequentiallyOnThread call_on_thread(expect_true,
93 sequenced_task_checker.get());
94}
95
96void RunMethodOnDifferentTaskQueue(bool expect_true) {
97 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
98 new SequencedTaskChecker());
99
100 static const char kQueueName[] = "MethodNotAllowedOnDifferentTq";
101 TaskQueue queue(kQueueName);
102 Event done_event(false, false);
103 queue.PostTask([&sequenced_task_checker, &done_event, expect_true] {
104 if (expect_true)
105 EXPECT_TRUE(sequenced_task_checker->CalledSequentially());
106 else
107 EXPECT_FALSE(sequenced_task_checker->CalledSequentially());
108 done_event.Set();
109 });
110 EXPECT_TRUE(done_event.Wait(1000));
111}
112
113void DetachThenCallFromDifferentTaskQueue(bool expect_true) {
114 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
115 new SequencedTaskChecker());
116
117 sequenced_task_checker->Detach();
118
119 Event done_event(false, false);
120 TaskQueue queue1("DetachThenCallFromDifferentTaskQueueImpl1");
121 queue1.PostTask([&sequenced_task_checker, &done_event] {
122 EXPECT_TRUE(sequenced_task_checker->CalledSequentially());
123 done_event.Set();
124 });
125 EXPECT_TRUE(done_event.Wait(1000));
126
127 // CalledSequentially should return false in debug builds after moving to
128 // another task queue.
129 TaskQueue queue2("DetachThenCallFromDifferentTaskQueueImpl2");
130 queue2.PostTask([&sequenced_task_checker, &done_event, expect_true] {
131 if (expect_true)
132 EXPECT_TRUE(sequenced_task_checker->CalledSequentially());
133 else
134 EXPECT_FALSE(sequenced_task_checker->CalledSequentially());
135 done_event.Set();
136 });
137 EXPECT_TRUE(done_event.Wait(1000));
138}
139} // namespace
140
141TEST(SequencedTaskCheckerTest, CallsAllowedOnSameThread) {
142 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
143 new SequencedTaskChecker());
144
145 EXPECT_TRUE(sequenced_task_checker->CalledSequentially());
146
147 // Verify that the destructor doesn't assert.
148 sequenced_task_checker.reset();
149}
150
151TEST(SequencedTaskCheckerTest, DestructorAllowedOnDifferentThread) {
152 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
153 new SequencedTaskChecker());
154
155 // Verify that the destructor doesn't assert when called on a different
156 // thread.
157 DeleteSequencedCheckerOnThread delete_on_thread(
158 std::move(sequenced_task_checker));
159}
160
161TEST(SequencedTaskCheckerTest, DetachFromThread) {
162 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
163 new SequencedTaskChecker());
164
165 sequenced_task_checker->Detach();
166 CallCalledSequentiallyOnThread call_on_thread(true,
167 sequenced_task_checker.get());
168}
169
170TEST(SequencedTaskCheckerTest, DetachFromThreadAndUseOnTaskQueue) {
171 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
172 new SequencedTaskChecker());
173
174 sequenced_task_checker->Detach();
175 static const char kQueueName[] = "DetachFromThreadAndUseOnTaskQueue";
176 TaskQueue queue(kQueueName);
177 Event done_event(false, false);
178 queue.PostTask([&sequenced_task_checker, &done_event] {
179 EXPECT_TRUE(sequenced_task_checker->CalledSequentially());
180 done_event.Set();
181 });
182 EXPECT_TRUE(done_event.Wait(1000));
183}
184
185TEST(SequencedTaskCheckerTest, DetachFromTaskQueueAndUseOnThread) {
186 TaskQueue queue("DetachFromTaskQueueAndUseOnThread");
187 Event done_event(false, false);
188 queue.PostTask([&done_event] {
189 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
190 new SequencedTaskChecker());
191
192 sequenced_task_checker->Detach();
193 CallCalledSequentiallyOnThread call_on_thread(true,
194 sequenced_task_checker.get());
195 done_event.Set();
196 });
197 EXPECT_TRUE(done_event.Wait(1000));
198}
199
kwiberg5377bc72016-10-04 13:46:56 -0700200#if RTC_DCHECK_IS_ON
perkj9c16fe82016-07-12 15:04:07 -0700201TEST(SequencedTaskCheckerTest, MethodNotAllowedOnDifferentThreadInDebug) {
202 RunMethodOnDifferentThread(false);
203}
204#else
205TEST(SequencedTaskCheckerTest, MethodAllowedOnDifferentThreadInRelease) {
206 RunMethodOnDifferentThread(true);
207}
208#endif
209
kwiberg5377bc72016-10-04 13:46:56 -0700210#if RTC_DCHECK_IS_ON
perkj9c16fe82016-07-12 15:04:07 -0700211TEST(SequencedTaskCheckerTest, MethodNotAllowedOnDifferentTaskQueueInDebug) {
212 RunMethodOnDifferentTaskQueue(false);
213}
214#else
215TEST(SequencedTaskCheckerTest, MethodAllowedOnDifferentTaskQueueInRelease) {
216 RunMethodOnDifferentTaskQueue(true);
217}
218#endif
219
kwiberg5377bc72016-10-04 13:46:56 -0700220#if RTC_DCHECK_IS_ON
perkj9c16fe82016-07-12 15:04:07 -0700221TEST(SequencedTaskCheckerTest, DetachFromTaskQueueInDebug) {
222 DetachThenCallFromDifferentTaskQueue(false);
223}
224#else
225TEST(SequencedTaskCheckerTest, DetachFromTaskQueueInRelease) {
226 DetachThenCallFromDifferentTaskQueue(true);
227}
228#endif
229
230class TestAnnotations {
231 public:
232 TestAnnotations() : test_var_(false) {}
233
234 void ModifyTestVar() {
235 RTC_DCHECK_CALLED_SEQUENTIALLY(&checker_);
236 test_var_ = true;
237 }
238
239 private:
danilchap3c6abd22017-09-06 05:46:29 -0700240 bool test_var_ RTC_GUARDED_BY(&checker_);
perkj9c16fe82016-07-12 15:04:07 -0700241 SequencedTaskChecker checker_;
242};
243
244TEST(SequencedTaskCheckerTest, TestAnnotations) {
245 TestAnnotations annotations;
246 annotations.ModifyTestVar();
247}
248
249#if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
250
251void TestAnnotationsOnWrongQueue() {
252 TestAnnotations annotations;
253 static const char kQueueName[] = "TestAnnotationsOnWrongQueueDebug";
254 TaskQueue queue(kQueueName);
255 Event done_event(false, false);
256 queue.PostTask([&annotations, &done_event] {
257 annotations.ModifyTestVar();
258 done_event.Set();
259 });
260 EXPECT_TRUE(done_event.Wait(1000));
261}
262
263#if RTC_DCHECK_IS_ON
264TEST(SequencedTaskCheckerTest, TestAnnotationsOnWrongQueueDebug) {
265 ASSERT_DEATH({ TestAnnotationsOnWrongQueue(); }, "");
266}
267#else
268TEST(SequencedTaskCheckerTest, TestAnnotationsOnWrongQueueRelease) {
269 TestAnnotationsOnWrongQueue();
270}
271#endif
272#endif // GTEST_HAS_DEATH_TEST
273} // namespace rtc