tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

sequence_checker_unittest.cc (6868B)


      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 "api/sequence_checker.h"
     12 
     13 #include <functional>
     14 #include <memory>
     15 
     16 #include "absl/functional/any_invocable.h"
     17 #include "api/function_view.h"
     18 #include "api/units/time_delta.h"
     19 #include "rtc_base/checks.h"
     20 #include "rtc_base/event.h"
     21 #include "rtc_base/platform_thread.h"
     22 #include "rtc_base/synchronization/sequence_checker_internal.h"
     23 #include "rtc_base/task_queue_for_test.h"
     24 #include "rtc_base/thread_annotations.h"
     25 #include "test/gmock.h"
     26 #include "test/gtest.h"
     27 
     28 using testing::HasSubstr;
     29 
     30 namespace webrtc {
     31 namespace {
     32 
     33 // This class is dead code, but its purpose is to make sure that
     34 // SequenceChecker is compatible with the RTC_GUARDED_BY and RTC_RUN_ON
     35 // attributes that are checked at compile-time.
     36 class CompileTimeTestForGuardedBy {
     37 public:
     38  int CalledOnSequence() RTC_RUN_ON(sequence_checker_) { return guarded_; }
     39 
     40  void CallMeFromSequence() {
     41    RTC_DCHECK_RUN_ON(&sequence_checker_);
     42    guarded_ = 41;
     43  }
     44 
     45 private:
     46  int guarded_ RTC_GUARDED_BY(sequence_checker_);
     47  SequenceChecker sequence_checker_;
     48 };
     49 
     50 void RunOnDifferentThread(FunctionView<void()> run) {
     51  Event thread_has_run_event;
     52  PlatformThread::SpawnJoinable(
     53      [&] {
     54        run();
     55        thread_has_run_event.Set();
     56      },
     57      "thread");
     58  EXPECT_TRUE(thread_has_run_event.Wait(TimeDelta::Seconds(1)));
     59 }
     60 
     61 }  // namespace
     62 
     63 TEST(SequenceCheckerTest, CallsAllowedOnSameThread) {
     64  SequenceChecker sequence_checker;
     65  EXPECT_TRUE(sequence_checker.IsCurrent());
     66 }
     67 
     68 TEST(SequenceCheckerTest, DestructorAllowedOnDifferentThread) {
     69  auto sequence_checker = std::make_unique<SequenceChecker>();
     70  RunOnDifferentThread([&] {
     71    // Verify that the destructor doesn't assert when called on a different
     72    // thread.
     73    sequence_checker.reset();
     74  });
     75 }
     76 
     77 TEST(SequenceCheckerTest, Detach) {
     78  SequenceChecker sequence_checker;
     79  sequence_checker.Detach();
     80  RunOnDifferentThread([&] { EXPECT_TRUE(sequence_checker.IsCurrent()); });
     81 }
     82 
     83 TEST(SequenceCheckerTest, DetachFromThreadAndUseOnTaskQueue) {
     84  SequenceChecker sequence_checker;
     85  sequence_checker.Detach();
     86  TaskQueueForTest queue;
     87  queue.SendTask([&] { EXPECT_TRUE(sequence_checker.IsCurrent()); });
     88 }
     89 
     90 TEST(SequenceCheckerTest, InitializeForDifferentTaskQueue) {
     91  TaskQueueForTest queue;
     92  SequenceChecker sequence_checker(queue.Get());
     93  EXPECT_EQ(sequence_checker.IsCurrent(), !RTC_DCHECK_IS_ON);
     94  queue.SendTask([&] { EXPECT_TRUE(sequence_checker.IsCurrent()); });
     95 }
     96 
     97 TEST(SequenceCheckerTest, DetachFromTaskQueueAndUseOnThread) {
     98  TaskQueueForTest queue;
     99  queue.SendTask([] {
    100    SequenceChecker sequence_checker;
    101    sequence_checker.Detach();
    102    RunOnDifferentThread([&] { EXPECT_TRUE(sequence_checker.IsCurrent()); });
    103  });
    104 }
    105 
    106 TEST(SequenceCheckerTest, MethodNotAllowedOnDifferentThreadInDebug) {
    107  SequenceChecker sequence_checker;
    108  RunOnDifferentThread(
    109      [&] { EXPECT_EQ(sequence_checker.IsCurrent(), !RTC_DCHECK_IS_ON); });
    110 }
    111 
    112 #if RTC_DCHECK_IS_ON
    113 TEST(SequenceCheckerTest, OnlyCurrentOnOneThread) {
    114  SequenceChecker sequence_checker(SequenceChecker::kDetached);
    115  RunOnDifferentThread([&] {
    116    EXPECT_TRUE(sequence_checker.IsCurrent());
    117    // Spawn a new thread from within the first one to guarantee that we have
    118    // two concurrently active threads (and that there's no chance of the
    119    // thread ref being reused).
    120    RunOnDifferentThread([&] { EXPECT_FALSE(sequence_checker.IsCurrent()); });
    121  });
    122 }
    123 #endif
    124 
    125 TEST(SequenceCheckerTest, MethodNotAllowedOnDifferentTaskQueueInDebug) {
    126  SequenceChecker sequence_checker;
    127  TaskQueueForTest queue;
    128  queue.SendTask(
    129      [&] { EXPECT_EQ(sequence_checker.IsCurrent(), !RTC_DCHECK_IS_ON); });
    130 }
    131 
    132 TEST(SequenceCheckerTest, DetachFromTaskQueueInDebug) {
    133  SequenceChecker sequence_checker;
    134  sequence_checker.Detach();
    135 
    136  TaskQueueForTest queue1;
    137  queue1.SendTask([&] { EXPECT_TRUE(sequence_checker.IsCurrent()); });
    138 
    139  // IsCurrent should return false in debug builds after moving to
    140  // another task queue.
    141  TaskQueueForTest queue2;
    142  queue2.SendTask(
    143      [&] { EXPECT_EQ(sequence_checker.IsCurrent(), !RTC_DCHECK_IS_ON); });
    144 }
    145 
    146 TEST(SequenceCheckerTest, ExpectationToString) {
    147  TaskQueueForTest queue1;
    148 
    149  SequenceChecker sequence_checker(SequenceChecker::kDetached);
    150 
    151  Event blocker;
    152  queue1.PostTask([&blocker, &sequence_checker]() {
    153    (void)sequence_checker.IsCurrent();
    154    blocker.Set();
    155  });
    156 
    157  blocker.Wait(Event::kForever);
    158 
    159 #if RTC_DCHECK_IS_ON
    160 
    161  EXPECT_THAT(ExpectationToString(&sequence_checker),
    162              HasSubstr("# Expected: TQ:"));
    163 
    164  // Test for the base class
    165  webrtc_sequence_checker_internal::SequenceCheckerImpl* sequence_checker_base =
    166      &sequence_checker;
    167  EXPECT_THAT(ExpectationToString(sequence_checker_base),
    168              HasSubstr("# Expected: TQ:"));
    169 
    170 #else
    171  GTEST_ASSERT_EQ(ExpectationToString(&sequence_checker), "");
    172 #endif
    173 }
    174 
    175 TEST(SequenceCheckerTest, InitiallyDetached) {
    176  TaskQueueForTest queue1;
    177 
    178  SequenceChecker sequence_checker(SequenceChecker::kDetached);
    179 
    180  Event blocker;
    181  queue1.PostTask([&blocker, &sequence_checker]() {
    182    EXPECT_TRUE(sequence_checker.IsCurrent());
    183    blocker.Set();
    184  });
    185 
    186  blocker.Wait(Event::kForever);
    187 
    188 #if RTC_DCHECK_IS_ON
    189  EXPECT_FALSE(sequence_checker.IsCurrent());
    190 #endif
    191 }
    192 
    193 class TestAnnotations {
    194 public:
    195  TestAnnotations() : test_var_(false) {}
    196 
    197  void ModifyTestVar() {
    198    RTC_DCHECK_RUN_ON(&checker_);
    199    test_var_ = true;
    200  }
    201 
    202 private:
    203  bool test_var_ RTC_GUARDED_BY(&checker_);
    204  SequenceChecker checker_;
    205 };
    206 
    207 TEST(SequenceCheckerTest, TestAnnotations) {
    208  TestAnnotations annotations;
    209  annotations.ModifyTestVar();
    210 }
    211 
    212 #if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
    213 
    214 void TestAnnotationsOnWrongQueue() {
    215  TestAnnotations annotations;
    216  TaskQueueForTest queue;
    217  queue.SendTask([&] { annotations.ModifyTestVar(); });
    218 }
    219 
    220 #if RTC_DCHECK_IS_ON
    221 // Note: Ending the test suite name with 'DeathTest' is important as it causes
    222 // gtest to order this test before any other non-death-tests, to avoid potential
    223 // global process state pollution such as shared worker threads being started
    224 // (e.g. a side effect of calling InitCocoaMultiThreading() on Mac causes one or
    225 // two additional threads to be created).
    226 TEST(SequenceCheckerDeathTest, TestAnnotationsOnWrongQueueDebug) {
    227  ASSERT_DEATH({ TestAnnotationsOnWrongQueue(); }, "");
    228 }
    229 #else
    230 TEST(SequenceCheckerTest, TestAnnotationsOnWrongQueueRelease) {
    231  TestAnnotationsOnWrongQueue();
    232 }
    233 #endif
    234 #endif  // GTEST_HAS_DEATH_TEST
    235 }  // namespace webrtc