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 // Borrowed from Chromium's src/base/threading/thread_checker_unittest.cc. | |
12 | |
13 #include <memory> | |
14 | |
15 #include "testing/gtest/include/gtest/gtest.h" | |
16 #include "webrtc/base/checks.h" | |
17 #include "webrtc/base/constructormagic.h" | |
18 #include "webrtc/base/sequenced_task_checker.h" | |
19 #include "webrtc/base/task_queue.h" | |
20 #include "webrtc/base/thread.h" | |
21 | |
22 // Duplicated from base/threading/sequenced_thread_checker.h so that we can be | |
23 // good citizens there and undef the macro. | |
24 #if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) | |
25 #define ENABLE_SEQUENCED_TASK_CHECKER 1 | |
tommi
2016/07/08 13:15:15
this doesn't look like the right place to change t
perkj_webrtc
2016/07/11 08:38:01
Ok- These tests were a copy of the threadcheker un
| |
26 #else | |
27 #define ENABLE_SEQUENCED_TASK_CHECKER 0 | |
28 #endif | |
29 | |
30 namespace rtc { | |
31 | |
32 namespace { | |
33 | |
34 // Simple class to exercise the basics of SequencedTaskChecker. | |
35 class SequencedCheckerClass : public SequencedTaskChecker { | |
36 public: | |
37 SequencedCheckerClass() {} | |
38 | |
39 // Verifies that it was called on the same thread as the constructor. | |
40 void DoStuff() { RTC_DCHECK(IsCurrent()); } | |
tommi
2016/07/08 13:15:15
since this is a test, it's probably better to do E
perkj_webrtc
2016/07/11 08:38:01
Done. - No longer using death tests.
| |
41 | |
42 void DetachFromSequence() { SequencedTaskChecker::Detach(); } | |
tommi
2016/07/08 13:15:16
Is this method needed or can the caller just call
perkj_webrtc
2016/07/11 08:38:01
Done.
| |
43 | |
44 static void MethodOnDifferentThreadImpl(); | |
45 static void MethodOnDifferentTaskQueueImpl(); | |
46 static void DetachThenCallFromDifferentThreadImpl(); | |
47 static void DetachThenCallFromDifferentTaskQueueImpl(); | |
48 | |
49 private: | |
50 RTC_DISALLOW_COPY_AND_ASSIGN(SequencedCheckerClass); | |
51 }; | |
52 | |
53 // Calls SequencedCheckerClass::DoStuff on another thread. | |
54 class CallDoStuffOnThread : public Thread { | |
tommi
2016/07/08 13:15:15
instead of using rtc::Thread (which we're using le
perkj_webrtc
2016/07/11 08:38:01
Done.
| |
55 public: | |
56 explicit CallDoStuffOnThread(SequencedCheckerClass* sequence_checker_class) | |
57 : Thread(), sequence_checker_class_(sequence_checker_class) { | |
58 SetName("call_do_stuff_on_thread", NULL); | |
59 } | |
60 | |
61 void Run() override { sequence_checker_class_->DoStuff(); } | |
62 | |
63 // New method. Needed since Thread::Join is protected, and it is called by | |
64 // the TEST. | |
65 void Join() { Thread::Join(); } | |
tommi
2016/07/08 13:15:15
I think you can also do:
using Thread::Join;
perkj_webrtc
2016/07/11 08:38:01
Acknowledged.
| |
66 | |
67 private: | |
68 SequencedCheckerClass* sequence_checker_class_; | |
69 | |
70 RTC_DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread); | |
71 }; | |
72 | |
73 // Deletes SequencedCheckerClass on a different thread. | |
74 class DeleteThreadCheckerClassOnThread : public Thread { | |
75 public: | |
76 explicit DeleteThreadCheckerClassOnThread( | |
77 SequencedCheckerClass* sequence_checker_class) | |
78 : Thread(), sequenced_checker_class_(sequence_checker_class) { | |
79 SetName("delete_sequence_checker_class_on_thread", NULL); | |
80 } | |
81 | |
82 void Run() override { sequenced_checker_class_.reset(); } | |
83 | |
84 // New method. Needed since Thread::Join is protected, and it is called by | |
85 // the TEST. | |
86 void Join() { Thread::Join(); } | |
87 | |
88 private: | |
89 std::unique_ptr<SequencedCheckerClass> sequenced_checker_class_; | |
90 | |
91 RTC_DISALLOW_COPY_AND_ASSIGN(DeleteThreadCheckerClassOnThread); | |
92 }; | |
93 | |
94 } // namespace | |
95 | |
96 TEST(SequencedTaskCheckerTest, CallsAllowedOnSameThread) { | |
97 std::unique_ptr<SequencedCheckerClass> sequence_checker_class( | |
98 new SequencedCheckerClass); | |
tommi
2016/07/08 13:15:15
new SequencedCheckerClass()
perkj_webrtc
2016/07/11 08:38:01
Done.
| |
99 | |
100 // Verify that DoStuff doesn't assert. | |
101 sequence_checker_class->DoStuff(); | |
102 | |
103 // Verify that the destructor doesn't assert. | |
104 sequence_checker_class.reset(); | |
105 } | |
106 | |
107 TEST(SequencedTaskCheckerTest, DestructorAllowedOnDifferentThread) { | |
108 std::unique_ptr<SequencedCheckerClass> sequence_checker_class( | |
109 new SequencedCheckerClass); | |
110 | |
111 // Verify that the destructor doesn't assert | |
112 // when called on a different thread. | |
113 DeleteThreadCheckerClassOnThread delete_on_thread( | |
114 sequence_checker_class.release()); | |
115 | |
116 delete_on_thread.Start(); | |
117 delete_on_thread.Join(); | |
118 } | |
119 | |
120 TEST(SequencedTaskCheckerTest, DetachFromThread) { | |
121 std::unique_ptr<SequencedCheckerClass> sequence_checker_class( | |
122 new SequencedCheckerClass); | |
123 | |
124 // Verify that DoStuff doesn't assert when called on a different thread after | |
125 // a call to DetachFromSequence. | |
126 sequence_checker_class->DetachFromSequence(); | |
127 CallDoStuffOnThread call_on_thread(sequence_checker_class.get()); | |
128 | |
129 call_on_thread.Start(); | |
130 call_on_thread.Join(); | |
131 } | |
132 | |
133 TEST(SequencedTaskCheckerTest, DetachFromThreadAndUseOnTaskQueue) { | |
134 std::unique_ptr<SequencedCheckerClass> sequence_checker_class( | |
135 new SequencedCheckerClass); | |
136 | |
137 // Verify that DoStuff doesn't assert when called on a different tq after | |
138 // a call to DetachFromSequence. | |
139 sequence_checker_class->DetachFromSequence(); | |
140 static const char kQueueName[] = "DetachFromThreadAndUseOnTaskQueue"; | |
141 TaskQueue queue(kQueueName); | |
142 Event done_event(false, false); | |
143 queue.PostTask([&sequence_checker_class, &done_event] { | |
144 sequence_checker_class->DoStuff(); | |
145 done_event.Set(); | |
146 }); | |
147 EXPECT_TRUE(done_event.Wait(1000)); | |
148 } | |
149 | |
150 TEST(SequencedTaskCheckerTest, DetachFromTaskQueueAndUseOnThread) { | |
151 TaskQueue queue("DetachFromTaskQueueAndUseOnThread"); | |
152 Event done_event(false, false); | |
153 queue.PostTask([&done_event] { | |
154 std::unique_ptr<SequencedCheckerClass> sequence_checker_class( | |
155 new SequencedCheckerClass); | |
156 | |
157 // Verify that DoStuff doesn't assert when called on a different thread | |
158 // after a call to DetachFromSequence. | |
159 sequence_checker_class->DetachFromSequence(); | |
160 CallDoStuffOnThread call_on_thread(sequence_checker_class.get()); | |
161 | |
162 call_on_thread.Start(); | |
163 call_on_thread.Join(); | |
164 | |
165 done_event.Set(); | |
166 }); | |
167 EXPECT_TRUE(done_event.Wait(1000)); | |
168 } | |
169 | |
170 #if GTEST_HAS_DEATH_TEST || !ENABLE_SEQUENCED_TASK_CHECKER | |
tommi
2016/07/08 13:15:15
I'm having problems groking this check... can you
perkj_webrtc
2016/07/11 08:38:01
Refactored to no longer use death tests.
| |
171 | |
172 void SequencedCheckerClass::MethodOnDifferentThreadImpl() { | |
173 std::unique_ptr<SequencedCheckerClass> sequence_checker_class( | |
174 new SequencedCheckerClass); | |
175 | |
176 // DoStuff should assert in debug builds only when called on a | |
177 // different thread. | |
178 CallDoStuffOnThread call_on_thread(sequence_checker_class.get()); | |
179 | |
180 call_on_thread.Start(); | |
181 call_on_thread.Join(); | |
182 } | |
183 | |
184 #if ENABLE_SEQUENCED_TASK_CHECKER | |
185 TEST(SequencedTaskCheckerDeathTest, MethodNotAllowedOnDifferentThreadInDebug) { | |
186 ASSERT_DEATH({ SequencedCheckerClass::MethodOnDifferentThreadImpl(); }, ""); | |
187 } | |
188 #else | |
189 TEST(SequencedTaskCheckerDeathTest, MethodAllowedOnDifferentThreadInRelease) { | |
190 SequencedCheckerClass::MethodOnDifferentThreadImpl(); | |
191 } | |
192 #endif // ENABLE_SEQUENCED_TASK_CHECKER | |
193 | |
194 void SequencedCheckerClass::MethodOnDifferentTaskQueueImpl() { | |
195 std::unique_ptr<SequencedCheckerClass> sequence_checker_class( | |
196 new SequencedCheckerClass); | |
197 | |
198 // Verify that DoStuff assert when called on a tq. | |
199 static const char kQueueName[] = "MethodNotAllowedOnDifferentTq"; | |
200 TaskQueue queue(kQueueName); | |
201 Event done_event(false, false); | |
202 queue.PostTask([&sequence_checker_class, &done_event] { | |
203 sequence_checker_class->DoStuff(); | |
204 done_event.Set(); | |
205 }); | |
206 EXPECT_TRUE(done_event.Wait(1000)); | |
207 } | |
208 | |
209 #if ENABLE_SEQUENCED_TASK_CHECKER | |
210 TEST(SequencedTaskCheckerDeathTest, MethodNotAllowedOnDifferentTqInDebug) { | |
211 ASSERT_DEATH({ SequencedCheckerClass::MethodOnDifferentTaskQueueImpl(); }, | |
212 ""); | |
213 } | |
214 #else | |
215 TEST(SequencedTaskCheckerDeathTest, MethodAllowedOnDifferentTqInRelease) { | |
216 SequencedCheckerClass::MethodOnDifferentTaskQueueImpl(); | |
217 } | |
218 #endif // ENABLE_SEQUENCED_TASK_CHECKER | |
219 | |
220 void SequencedCheckerClass::DetachThenCallFromDifferentTaskQueueImpl() { | |
221 std::unique_ptr<SequencedCheckerClass> sequence_checker_class( | |
222 new SequencedCheckerClass); | |
223 | |
224 // DoStuff doesn't assert when called on a different task queue | |
225 // after a call to DetachFromSequence. | |
226 sequence_checker_class->DetachFromSequence(); | |
227 | |
228 Event done_event(false, false); | |
229 TaskQueue queue1("DetachThenCallFromDifferentTaskQueueImpl1"); | |
230 queue1.PostTask([&sequence_checker_class, &done_event] { | |
231 sequence_checker_class->DoStuff(); | |
232 done_event.Set(); | |
233 }); | |
234 EXPECT_TRUE(done_event.Wait(1000)); | |
235 | |
236 // DoStuff should assert in debug builds only after moving to | |
237 // another task queue. | |
238 TaskQueue queue2("DetachThenCallFromDifferentTaskQueueImpl2"); | |
239 queue2.PostTask([&sequence_checker_class, &done_event] { | |
240 sequence_checker_class->DoStuff(); | |
241 done_event.Set(); | |
242 }); | |
243 done_event.Wait(1000); | |
244 } | |
245 | |
246 #if ENABLE_SEQUENCED_TASK_CHECKER | |
247 TEST(SequencedTaskCheckerDeathTest, DetachFromTaskQueueInDebug) { | |
248 ASSERT_DEATH( | |
249 { SequencedCheckerClass::DetachThenCallFromDifferentTaskQueueImpl(); }, | |
250 ""); | |
251 } | |
252 #else | |
253 TEST(SequencedTaskCheckerDeathTest, DetachFromThreadInRelease) { | |
254 SequencedCheckerClass::DetachThenCallFromDifferentTaskQueueImpl(); | |
255 } | |
256 #endif // ENABLE_THREAD_CHECKER | |
257 | |
258 #endif // GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER | |
259 | |
260 class SequencedTaskCheckerAnnotateTest { | |
261 public: | |
262 // Next two function should create warnings when compile (e.g. if used with | |
263 // specific T). | |
264 // TODO(danilchap): Find a way to test they do not compile when thread | |
265 // annotation checks enabled. | |
266 template <typename T> | |
267 void access_var_no_annotate() { | |
tommi
2016/07/08 13:15:15
AccessVarNoAnnotate (since this isn't a getter)
perkj_webrtc
2016/07/11 08:38:01
removed all for now.
| |
268 var_checker_ = 42; | |
269 } | |
270 | |
271 template <typename T> | |
272 void access_fun_no_annotate() { | |
tommi
2016/07/08 13:15:15
AccessFunctionNoAnnotate etc
perkj_webrtc
2016/07/11 08:38:01
dito
| |
273 function(); | |
274 } | |
275 | |
276 // Function below should be able to compile. | |
277 void access_var_annotate_checker() { | |
278 RTC_DCHECK_RUN_ON(&checker_); | |
279 var_checker_ = 44; | |
280 } | |
281 | |
282 void access_fun_annotate() { | |
283 RTC_DCHECK_RUN_ON(&checker_); | |
284 function(); | |
285 } | |
286 | |
287 private: | |
288 void function() RUN_ON(checker_) {} | |
289 | |
290 rtc::SequencedTaskChecker checker_; | |
291 | |
292 int var_checker_ GUARDED_BY(checker_); | |
293 }; | |
294 | |
295 TEST(SequencedTaskCheckerAnnotateTest, test) { | |
296 SequencedTaskCheckerAnnotateTest tester; | |
297 tester.access_var_annotate_checker(); | |
298 } | |
299 | |
300 // Just in case we ever get lumped together with other compilation units. | |
301 #undef ENABLE_SEQUENCED_TASK_CHECKER | |
tommi
2016/07/08 13:15:15
this could only happen if another file #includes s
perkj_webrtc
2016/07/11 08:38:01
Acknowledged.
| |
302 | |
303 } // namespace rtc | |
OLD | NEW |