Home | History | Annotate | Download | only in base
      1 /*
      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 
     13 #include "testing/gtest/include/gtest/gtest.h"
     14 #include "webrtc/base/checks.h"
     15 #include "webrtc/base/thread.h"
     16 #include "webrtc/base/thread_checker.h"
     17 #include "webrtc/base/scoped_ptr.h"
     18 #include "webrtc/test/testsupport/gtest_disable.h"
     19 
     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 
     28 namespace rtc {
     29 
     30 namespace {
     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.
     35 class ThreadCheckerClass : public ThreadChecker {
     36  public:
     37   ThreadCheckerClass() {}
     38 
     39   // Verifies that it was called on the same thread as the constructor.
     40   void DoStuff() {
     41     DCHECK(CalledOnValidThread());
     42   }
     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.
     56 class 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.
     81 class 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 
    108 TEST(ThreadCheckerTest, DISABLED_ON_MAC(CallsAllowedOnSameThread)) {
    109   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 
    119 TEST(ThreadCheckerTest, DISABLED_ON_MAC(DestructorAllowedOnDifferentThread)) {
    120   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 
    132 TEST(ThreadCheckerTest, DISABLED_ON_MAC(DetachFromThread)) {
    133   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 
    147 void 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
    160 TEST(ThreadCheckerDeathTest,
    161      DISABLED_MethodNotAllowedOnDifferentThreadInDebug) {
    162   ASSERT_DEATH({
    163       ThreadCheckerClass::MethodOnDifferentThreadImpl();
    164     }, "");
    165 }
    166 #else
    167 TEST(ThreadCheckerTest, MethodAllowedOnDifferentThreadInRelease) {
    168   ThreadCheckerClass::MethodOnDifferentThreadImpl();
    169 }
    170 #endif  // ENABLE_THREAD_CHECKER
    171 
    172 void 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
    190 TEST(ThreadCheckerDeathTest, DetachFromThreadInDebug) {
    191   ASSERT_DEATH({
    192     ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
    193     }, "");
    194 }
    195 #else
    196 TEST(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
    207