TestThreadUtils.cpp (6056B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "QuotaManagerDependencyFixture.h" 8 #include "mozilla/dom/quota/QuotaManager.h" 9 #include "mozilla/dom/quota/ThreadUtils.h" 10 #include "mozilla/gtest/MozAssertions.h" 11 12 namespace mozilla::dom::quota::test { 13 14 namespace { 15 16 MozExternalRefCountType GetRefCount(nsISupports* aSupports) { 17 if (!aSupports) { 18 return 0; 19 } 20 aSupports->AddRef(); 21 return aSupports->Release(); 22 } 23 24 class OneTimeRunnable final : public Runnable { 25 public: 26 enum class State { None, Initial, Created, Destroyed }; 27 28 static void Init() { 29 ASSERT_TRUE(sState == State::None || sState == State::Destroyed); 30 ASSERT_FALSE(sCurrent); 31 32 sState = State::Initial; 33 } 34 35 static RefPtr<OneTimeRunnable> Create(std::function<void()>&& aTask) { 36 EXPECT_EQ(sState, State::Initial); 37 38 RefPtr<OneTimeRunnable> runnable = new OneTimeRunnable(std::move(aTask)); 39 return runnable; 40 } 41 42 static State GetState() { return sState; } 43 44 static OneTimeRunnable* GetCurrent() { return sCurrent; } 45 46 static MozExternalRefCountType GetCurrentRefCount() { 47 return GetRefCount(static_cast<nsIRunnable*>(sCurrent)); 48 } 49 50 NS_IMETHOD 51 Run() override { 52 auto task = std::move(mTask); 53 task(); 54 55 return NS_OK; 56 } 57 58 private: 59 explicit OneTimeRunnable(std::function<void()>&& aTask) 60 : Runnable("dom::quota::test::OneTimeRunnable"), mTask(std::move(aTask)) { 61 sCurrent = this; 62 sState = State::Created; 63 } 64 65 ~OneTimeRunnable() override { 66 sState = State::Destroyed; 67 sCurrent = nullptr; 68 } 69 70 static Atomic<State> sState; 71 static OneTimeRunnable* sCurrent; 72 73 std::function<void()> mTask; 74 }; 75 76 } // namespace 77 78 Atomic<OneTimeRunnable::State> OneTimeRunnable::sState( 79 OneTimeRunnable::State::None); 80 OneTimeRunnable* OneTimeRunnable::sCurrent(nullptr); 81 82 class TestThreadUtils : public QuotaManagerDependencyFixture { 83 public: 84 static void SetUpTestCase() { ASSERT_NO_FATAL_FAILURE(InitializeFixture()); } 85 86 static void TearDownTestCase() { ASSERT_NO_FATAL_FAILURE(ShutdownFixture()); } 87 }; 88 89 TEST_F(TestThreadUtils, RunAfterProcessingCurrentEvent_Release) { 90 bool runnableCalled = false; 91 bool callbackCalled = false; 92 93 QuotaManager* quotaManager = QuotaManager::Get(); 94 ASSERT_TRUE(quotaManager); 95 96 OneTimeRunnable::Init(); 97 98 auto runnable = OneTimeRunnable::Create([&runnableCalled, &callbackCalled]() { 99 runnableCalled = true; 100 101 EXPECT_EQ(OneTimeRunnable::GetState(), OneTimeRunnable::State::Created); 102 EXPECT_EQ(OneTimeRunnable::GetCurrentRefCount(), 2u); 103 104 RunAfterProcessingCurrentEvent([&callbackCalled]() { 105 callbackCalled = true; 106 107 // The runnable shouldn't be yet destroyed because we still have a strong 108 // reference to it in `runnable`. 109 EXPECT_EQ(OneTimeRunnable::GetState(), OneTimeRunnable::State::Created); 110 111 // The runnable should be released once (by the event queue processing 112 // code). 113 EXPECT_EQ(OneTimeRunnable::GetCurrentRefCount(), 1u); 114 }); 115 116 EXPECT_EQ(OneTimeRunnable::GetState(), OneTimeRunnable::State::Created); 117 EXPECT_EQ(OneTimeRunnable::GetCurrentRefCount(), 2u); 118 }); 119 120 ASSERT_FALSE(runnableCalled); 121 ASSERT_FALSE(callbackCalled); 122 123 // Note that we are keeping ownership of the runnable here. 124 ASSERT_EQ(NS_OK, 125 quotaManager->IOThread()->Dispatch(runnable, NS_DISPATCH_NORMAL)); 126 127 // Do a round-trip to the QM IO thread to ensure the test doesn't finish 128 // before the OneTimeRunnable is fully processed. 129 // 130 // Note: In theory, we would use SyncRunnable wrapper here, but the code 131 // reads better when both tests use the same way for blocking the current 132 // thread. 133 ASSERT_NO_FATAL_FAILURE(PerformOnIOThread([]() {})); 134 135 // Check that the runnable and the callback were actually called. 136 ASSERT_TRUE(runnableCalled); 137 ASSERT_TRUE(callbackCalled); 138 } 139 140 TEST_F(TestThreadUtils, RunAfterProcessingCurrentEvent_ReleaseAndDestory) { 141 bool runnableCalled = false; 142 bool callbackCalled = false; 143 144 QuotaManager* quotaManager = QuotaManager::Get(); 145 ASSERT_TRUE(quotaManager); 146 147 OneTimeRunnable::Init(); 148 149 auto runnable = OneTimeRunnable::Create([&runnableCalled, &callbackCalled]() { 150 runnableCalled = true; 151 152 EXPECT_EQ(OneTimeRunnable::GetState(), OneTimeRunnable::State::Created); 153 EXPECT_EQ(OneTimeRunnable::GetCurrentRefCount(), 1u); 154 155 RunAfterProcessingCurrentEvent([&callbackCalled]() { 156 callbackCalled = true; 157 158 // The runnable should be destroyed because we don't have any other strong 159 // references to it. 160 EXPECT_EQ(OneTimeRunnable::GetState(), OneTimeRunnable::State::Destroyed); 161 162 // The runnable should be released once (by the event queue processing 163 // code). 164 EXPECT_EQ(OneTimeRunnable::GetCurrentRefCount(), 0u); 165 }); 166 167 EXPECT_EQ(OneTimeRunnable::GetState(), OneTimeRunnable::State::Created); 168 EXPECT_EQ(OneTimeRunnable::GetCurrentRefCount(), 1u); 169 }); 170 171 ASSERT_FALSE(runnableCalled); 172 ASSERT_FALSE(callbackCalled); 173 174 // Note that we are tranferring ownership of the runnable here. 175 ASSERT_EQ(NS_OK, quotaManager->IOThread()->Dispatch(runnable.forget(), 176 NS_DISPATCH_NORMAL)); 177 178 // Do a round-trip to the QM IO thread to ensure the test doesn't finish 179 // before the OneTimeRunnable is fully processed. 180 // 181 // Note: SyncRunnable wrapper can't be used here because that would hold our 182 // runnable longer, and we couldn't test that our runnable is destroyed when 183 // the callback for RunAfterProcessingCurrentEvent is executed. 184 ASSERT_NO_FATAL_FAILURE(PerformOnIOThread([]() {})); 185 186 // Check that the runnable and the callback were actually called. 187 ASSERT_TRUE(runnableCalled); 188 ASSERT_TRUE(callbackCalled); 189 } 190 191 } // namespace mozilla::dom::quota::test