blob: 268112cda55ace37ddaba1a7497b3d239aa717b6 [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"
henrike@webrtc.orgfded02c2014-09-19 13:10:10 +000018#include "webrtc/test/testsupport/gtest_disable.h"
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000019
20// Duplicated from base/threading/thread_checker.h so that we can be
21// good citizens there and undef the macro.
22#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
23#define ENABLE_THREAD_CHECKER 1
24#else
25#define ENABLE_THREAD_CHECKER 0
26#endif
27
28namespace rtc {
29
30namespace {
31
32// Simple class to exercise the basics of ThreadChecker.
33// Both the destructor and DoStuff should verify that they were
34// called on the same thread as the constructor.
35class ThreadCheckerClass : public ThreadChecker {
36 public:
37 ThreadCheckerClass() {}
38
39 // Verifies that it was called on the same thread as the constructor.
40 void DoStuff() {
henrik.lundin@webrtc.org18617cf2014-09-15 11:19:35 +000041 DCHECK(CalledOnValidThread());
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000042 }
43
44 void DetachFromThread() {
45 ThreadChecker::DetachFromThread();
46 }
47
48 static void MethodOnDifferentThreadImpl();
49 static void DetachThenCallFromDifferentThreadImpl();
50
51 private:
52 DISALLOW_COPY_AND_ASSIGN(ThreadCheckerClass);
53};
54
55// Calls ThreadCheckerClass::DoStuff on another thread.
56class CallDoStuffOnThread : public Thread {
57 public:
58 explicit CallDoStuffOnThread(ThreadCheckerClass* thread_checker_class)
59 : Thread(),
60 thread_checker_class_(thread_checker_class) {
61 SetName("call_do_stuff_on_thread", NULL);
62 }
63
64 virtual void Run() OVERRIDE {
65 thread_checker_class_->DoStuff();
66 }
67
68 // New method. Needed since Thread::Join is protected, and it is called by
69 // the TEST.
70 void Join() {
71 Thread::Join();
72 }
73
74 private:
75 ThreadCheckerClass* thread_checker_class_;
76
77 DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread);
78};
79
80// Deletes ThreadCheckerClass on a different thread.
81class DeleteThreadCheckerClassOnThread : public Thread {
82 public:
83 explicit DeleteThreadCheckerClassOnThread(
84 ThreadCheckerClass* thread_checker_class)
85 : Thread(),
86 thread_checker_class_(thread_checker_class) {
87 SetName("delete_thread_checker_class_on_thread", NULL);
88 }
89
90 virtual void Run() OVERRIDE {
91 thread_checker_class_.reset();
92 }
93
94 // New method. Needed since Thread::Join is protected, and it is called by
95 // the TEST.
96 void Join() {
97 Thread::Join();
98 }
99
100 private:
101 scoped_ptr<ThreadCheckerClass> thread_checker_class_;
102
103 DISALLOW_COPY_AND_ASSIGN(DeleteThreadCheckerClassOnThread);
104};
105
106} // namespace
107
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000108TEST(ThreadCheckerTest, CallsAllowedOnSameThread) {
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000109 scoped_ptr<ThreadCheckerClass> thread_checker_class(
110 new ThreadCheckerClass);
111
112 // Verify that DoStuff doesn't assert.
113 thread_checker_class->DoStuff();
114
115 // Verify that the destructor doesn't assert.
116 thread_checker_class.reset();
117}
118
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000119TEST(ThreadCheckerTest, DestructorAllowedOnDifferentThread) {
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000120 scoped_ptr<ThreadCheckerClass> thread_checker_class(
121 new ThreadCheckerClass);
122
123 // Verify that the destructor doesn't assert
124 // when called on a different thread.
125 DeleteThreadCheckerClassOnThread delete_on_thread(
126 thread_checker_class.release());
127
128 delete_on_thread.Start();
129 delete_on_thread.Join();
130}
131
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000132TEST(ThreadCheckerTest, DetachFromThread) {
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000133 scoped_ptr<ThreadCheckerClass> thread_checker_class(
134 new ThreadCheckerClass);
135
136 // Verify that DoStuff doesn't assert when called on a different thread after
137 // a call to DetachFromThread.
138 thread_checker_class->DetachFromThread();
139 CallDoStuffOnThread call_on_thread(thread_checker_class.get());
140
141 call_on_thread.Start();
142 call_on_thread.Join();
143}
144
145#if GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER
146
147void ThreadCheckerClass::MethodOnDifferentThreadImpl() {
148 scoped_ptr<ThreadCheckerClass> thread_checker_class(
149 new ThreadCheckerClass);
150
151 // DoStuff should assert in debug builds only when called on a
152 // different thread.
153 CallDoStuffOnThread call_on_thread(thread_checker_class.get());
154
155 call_on_thread.Start();
156 call_on_thread.Join();
157}
158
159#if ENABLE_THREAD_CHECKER
henrike@webrtc.org78b2d562014-09-12 15:57:08 +0000160TEST(ThreadCheckerDeathTest,
161 DISABLED_MethodNotAllowedOnDifferentThreadInDebug) {
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000162 ASSERT_DEATH({
163 ThreadCheckerClass::MethodOnDifferentThreadImpl();
164 }, "");
165}
166#else
167TEST(ThreadCheckerTest, MethodAllowedOnDifferentThreadInRelease) {
168 ThreadCheckerClass::MethodOnDifferentThreadImpl();
169}
170#endif // ENABLE_THREAD_CHECKER
171
172void ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl() {
173 scoped_ptr<ThreadCheckerClass> thread_checker_class(
174 new ThreadCheckerClass);
175
176 // DoStuff doesn't assert when called on a different thread
177 // after a call to DetachFromThread.
178 thread_checker_class->DetachFromThread();
179 CallDoStuffOnThread call_on_thread(thread_checker_class.get());
180
181 call_on_thread.Start();
182 call_on_thread.Join();
183
184 // DoStuff should assert in debug builds only after moving to
185 // another thread.
186 thread_checker_class->DoStuff();
187}
188
189#if ENABLE_THREAD_CHECKER
190TEST(ThreadCheckerDeathTest, DetachFromThreadInDebug) {
191 ASSERT_DEATH({
192 ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
193 }, "");
194}
195#else
196TEST(ThreadCheckerTest, DetachFromThreadInRelease) {
197 ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
198}
199#endif // ENABLE_THREAD_CHECKER
200
201#endif // GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER
202
203// Just in case we ever get lumped together with other compilation units.
204#undef ENABLE_THREAD_CHECKER
205
206} // namespace rtc