blob: 338190093d04464ecf908685f5a11487c32652ac [file] [log] [blame]
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +00001/*
2 * Copyright (c) 2014 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
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000013#include "testing/gtest/include/gtest/gtest.h"
henrik.lundin@webrtc.org18617cf2014-09-15 11:19:35 +000014#include "webrtc/base/checks.h"
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000015#include "webrtc/base/thread.h"
16#include "webrtc/base/thread_checker.h"
17#include "webrtc/base/scoped_ptr.h"
18
19// Duplicated from base/threading/thread_checker.h so that we can be
20// good citizens there and undef the macro.
21#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
22#define ENABLE_THREAD_CHECKER 1
23#else
24#define ENABLE_THREAD_CHECKER 0
25#endif
26
27namespace rtc {
28
29namespace {
30
31// Simple class to exercise the basics of ThreadChecker.
32// Both the destructor and DoStuff should verify that they were
33// called on the same thread as the constructor.
34class ThreadCheckerClass : public ThreadChecker {
35 public:
36 ThreadCheckerClass() {}
37
38 // Verifies that it was called on the same thread as the constructor.
henrikg91d6ede2015-09-17 00:24:34 -070039 void DoStuff() { RTC_DCHECK(CalledOnValidThread()); }
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000040
41 void DetachFromThread() {
42 ThreadChecker::DetachFromThread();
43 }
44
45 static void MethodOnDifferentThreadImpl();
46 static void DetachThenCallFromDifferentThreadImpl();
47
48 private:
henrikg3c089d72015-09-16 05:37:44 -070049 RTC_DISALLOW_COPY_AND_ASSIGN(ThreadCheckerClass);
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000050};
51
52// Calls ThreadCheckerClass::DoStuff on another thread.
53class CallDoStuffOnThread : public Thread {
54 public:
55 explicit CallDoStuffOnThread(ThreadCheckerClass* thread_checker_class)
56 : Thread(),
57 thread_checker_class_(thread_checker_class) {
58 SetName("call_do_stuff_on_thread", NULL);
59 }
60
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +000061 void Run() override { thread_checker_class_->DoStuff(); }
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000062
63 // New method. Needed since Thread::Join is protected, and it is called by
64 // the TEST.
65 void Join() {
66 Thread::Join();
67 }
68
69 private:
70 ThreadCheckerClass* thread_checker_class_;
71
henrikg3c089d72015-09-16 05:37:44 -070072 RTC_DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread);
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000073};
74
75// Deletes ThreadCheckerClass on a different thread.
76class DeleteThreadCheckerClassOnThread : public Thread {
77 public:
78 explicit DeleteThreadCheckerClassOnThread(
79 ThreadCheckerClass* thread_checker_class)
80 : Thread(),
81 thread_checker_class_(thread_checker_class) {
82 SetName("delete_thread_checker_class_on_thread", NULL);
83 }
84
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +000085 void Run() override { thread_checker_class_.reset(); }
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000086
87 // New method. Needed since Thread::Join is protected, and it is called by
88 // the TEST.
89 void Join() {
90 Thread::Join();
91 }
92
93 private:
94 scoped_ptr<ThreadCheckerClass> thread_checker_class_;
95
henrikg3c089d72015-09-16 05:37:44 -070096 RTC_DISALLOW_COPY_AND_ASSIGN(DeleteThreadCheckerClassOnThread);
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000097};
98
99} // namespace
100
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000101TEST(ThreadCheckerTest, CallsAllowedOnSameThread) {
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000102 scoped_ptr<ThreadCheckerClass> thread_checker_class(
103 new ThreadCheckerClass);
104
105 // Verify that DoStuff doesn't assert.
106 thread_checker_class->DoStuff();
107
108 // Verify that the destructor doesn't assert.
109 thread_checker_class.reset();
110}
111
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000112TEST(ThreadCheckerTest, DestructorAllowedOnDifferentThread) {
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000113 scoped_ptr<ThreadCheckerClass> thread_checker_class(
114 new ThreadCheckerClass);
115
116 // Verify that the destructor doesn't assert
117 // when called on a different thread.
118 DeleteThreadCheckerClassOnThread delete_on_thread(
119 thread_checker_class.release());
120
121 delete_on_thread.Start();
122 delete_on_thread.Join();
123}
124
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000125TEST(ThreadCheckerTest, DetachFromThread) {
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000126 scoped_ptr<ThreadCheckerClass> thread_checker_class(
127 new ThreadCheckerClass);
128
129 // Verify that DoStuff doesn't assert when called on a different thread after
130 // a call to DetachFromThread.
131 thread_checker_class->DetachFromThread();
132 CallDoStuffOnThread call_on_thread(thread_checker_class.get());
133
134 call_on_thread.Start();
135 call_on_thread.Join();
136}
137
138#if GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER
139
140void ThreadCheckerClass::MethodOnDifferentThreadImpl() {
141 scoped_ptr<ThreadCheckerClass> thread_checker_class(
142 new ThreadCheckerClass);
143
144 // DoStuff should assert in debug builds only when called on a
145 // different thread.
146 CallDoStuffOnThread call_on_thread(thread_checker_class.get());
147
148 call_on_thread.Start();
149 call_on_thread.Join();
150}
151
152#if ENABLE_THREAD_CHECKER
tommi@webrtc.org2eb16602015-02-07 19:17:47 +0000153TEST(ThreadCheckerDeathTest, MethodNotAllowedOnDifferentThreadInDebug) {
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000154 ASSERT_DEATH({
155 ThreadCheckerClass::MethodOnDifferentThreadImpl();
156 }, "");
157}
158#else
159TEST(ThreadCheckerTest, MethodAllowedOnDifferentThreadInRelease) {
160 ThreadCheckerClass::MethodOnDifferentThreadImpl();
161}
162#endif // ENABLE_THREAD_CHECKER
163
164void ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl() {
165 scoped_ptr<ThreadCheckerClass> thread_checker_class(
166 new ThreadCheckerClass);
167
168 // DoStuff doesn't assert when called on a different thread
169 // after a call to DetachFromThread.
170 thread_checker_class->DetachFromThread();
171 CallDoStuffOnThread call_on_thread(thread_checker_class.get());
172
173 call_on_thread.Start();
174 call_on_thread.Join();
175
176 // DoStuff should assert in debug builds only after moving to
177 // another thread.
178 thread_checker_class->DoStuff();
179}
180
181#if ENABLE_THREAD_CHECKER
tommi@webrtc.org2eb16602015-02-07 19:17:47 +0000182TEST(ThreadCheckerDeathTest, DetachFromThreadInDebug) {
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000183 ASSERT_DEATH({
184 ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
185 }, "");
186}
187#else
188TEST(ThreadCheckerTest, DetachFromThreadInRelease) {
189 ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
190}
191#endif // ENABLE_THREAD_CHECKER
192
193#endif // GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER
194
195// Just in case we ever get lumped together with other compilation units.
196#undef ENABLE_THREAD_CHECKER
197
198} // namespace rtc