OLD | NEW |
| (Empty) |
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 "webrtc/base/checks.h" | |
12 #include "webrtc/base/constructormagic.h" | |
13 #include "webrtc/base/platform_thread.h" | |
14 #include "webrtc/base/sequenced_task_checker.h" | |
15 #include "webrtc/base/task_queue.h" | |
16 #include "webrtc/test/gtest.h" | |
17 | |
18 namespace rtc { | |
19 | |
20 namespace { | |
21 // Calls SequencedTaskChecker::CalledSequentially on another thread. | |
22 class 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: | |
38 static void Run(void* obj) { | |
39 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(); | |
45 } | |
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. | |
56 class 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 | |
88 void 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 | |
96 void 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 | |
113 void 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 | |
141 TEST(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 | |
151 TEST(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 | |
161 TEST(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 | |
170 TEST(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 | |
185 TEST(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 | |
200 #if RTC_DCHECK_IS_ON | |
201 TEST(SequencedTaskCheckerTest, MethodNotAllowedOnDifferentThreadInDebug) { | |
202 RunMethodOnDifferentThread(false); | |
203 } | |
204 #else | |
205 TEST(SequencedTaskCheckerTest, MethodAllowedOnDifferentThreadInRelease) { | |
206 RunMethodOnDifferentThread(true); | |
207 } | |
208 #endif | |
209 | |
210 #if RTC_DCHECK_IS_ON | |
211 TEST(SequencedTaskCheckerTest, MethodNotAllowedOnDifferentTaskQueueInDebug) { | |
212 RunMethodOnDifferentTaskQueue(false); | |
213 } | |
214 #else | |
215 TEST(SequencedTaskCheckerTest, MethodAllowedOnDifferentTaskQueueInRelease) { | |
216 RunMethodOnDifferentTaskQueue(true); | |
217 } | |
218 #endif | |
219 | |
220 #if RTC_DCHECK_IS_ON | |
221 TEST(SequencedTaskCheckerTest, DetachFromTaskQueueInDebug) { | |
222 DetachThenCallFromDifferentTaskQueue(false); | |
223 } | |
224 #else | |
225 TEST(SequencedTaskCheckerTest, DetachFromTaskQueueInRelease) { | |
226 DetachThenCallFromDifferentTaskQueue(true); | |
227 } | |
228 #endif | |
229 | |
230 class 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: | |
240 bool test_var_ GUARDED_BY(&checker_); | |
241 SequencedTaskChecker checker_; | |
242 }; | |
243 | |
244 TEST(SequencedTaskCheckerTest, TestAnnotations) { | |
245 TestAnnotations annotations; | |
246 annotations.ModifyTestVar(); | |
247 } | |
248 | |
249 #if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) | |
250 | |
251 void 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 | |
264 TEST(SequencedTaskCheckerTest, TestAnnotationsOnWrongQueueDebug) { | |
265 ASSERT_DEATH({ TestAnnotationsOnWrongQueue(); }, ""); | |
266 } | |
267 #else | |
268 TEST(SequencedTaskCheckerTest, TestAnnotationsOnWrongQueueRelease) { | |
269 TestAnnotationsOnWrongQueue(); | |
270 } | |
271 #endif | |
272 #endif // GTEST_HAS_DEATH_TEST | |
273 } // namespace rtc | |
OLD | NEW |