QuotaManagerDependencyFixture.h (10240B)
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 #ifndef DOM_QUOTA_TEST_GTEST_QUOTAMANAGERDEPENDENCYFIXTURE_H_ 8 #define DOM_QUOTA_TEST_GTEST_QUOTAMANAGERDEPENDENCYFIXTURE_H_ 9 10 #include "gtest/gtest.h" 11 #include "mozilla/MozPromise.h" 12 #include "mozilla/SpinEventLoopUntil.h" 13 #include "mozilla/dom/quota/ClientDirectoryLock.h" 14 #include "mozilla/dom/quota/ClientDirectoryLockHandle.h" 15 #include "mozilla/dom/quota/DirectoryLock.h" 16 #include "mozilla/dom/quota/DirectoryLockInlines.h" 17 #include "mozilla/dom/quota/ForwardDecls.h" 18 #include "mozilla/dom/quota/QuotaManager.h" 19 20 // ENSURE_NO_FATAL_FAILURE is useful in non-void functions where 21 // ASSERT_NO_FATAL_FAILURE can't be used. 22 #define ENSURE_NO_FATAL_FAILURE(expr, ret) \ 23 (expr); \ 24 if (HasFatalFailure()) { \ 25 return ret; \ 26 } 27 28 #define QM_TEST_FAIL [](nsresult) { FAIL(); } 29 30 namespace mozilla::dom::quota::test { 31 32 class QuotaManagerDependencyFixture : public testing::Test { 33 public: 34 static void InitializeFixture(); 35 static void ShutdownFixture(); 36 37 static void InitializeStorage(); 38 static void StorageInitialized(bool* aResult); 39 static void AssertStorageInitialized(); 40 static void AssertStorageNotInitialized(); 41 static void ClearStorage(); 42 static void ShutdownStorage(); 43 44 static void InitializeTemporaryStorage(); 45 static void TemporaryStorageInitialized(bool* aResult); 46 static void AssertTemporaryStorageInitialized(); 47 static void AssertTemporaryStorageNotInitialized(); 48 static void ShutdownTemporaryStorage(); 49 50 static void InitializeTemporaryOrigin(const OriginMetadata& aOriginMetadata, 51 bool aCreateIfNonExistent = true); 52 static void TemporaryOriginInitialized(const OriginMetadata& aOriginMetadata, 53 bool* aResult); 54 static void AssertTemporaryOriginInitialized( 55 const OriginMetadata& aOriginMetadata); 56 static void AssertTemporaryOriginNotInitialized( 57 const OriginMetadata& aOriginMetadata); 58 59 // For more complex testing, use of this helper is optional. 60 static void SaveOriginAccessTime(const OriginMetadata& aOriginMetadata); 61 62 static void GetOriginUsage(const OriginMetadata& aOriginMetadata, 63 UsageInfo* aResult); 64 static void GetCachedOriginUsage(const OriginMetadata& aOriginMetadata, 65 UsageInfo* aResult); 66 static void ClearStoragesForOrigin(const OriginMetadata& aOriginMetadata); 67 68 static void InitializePersistentClient(const ClientMetadata& aClientMetadata); 69 static void InitializeTemporaryClient(const ClientMetadata& aClientMetadata, 70 bool aCreateIfNonExistent = true); 71 72 static CStringArray ListOrigins(); 73 static CStringArray ListCachedOrigins(); 74 75 static void ClearStoragesForOriginAttributesPattern( 76 const nsAString& aPattern); 77 78 static void ProcessPendingNormalOriginOperations(); 79 80 static Maybe<OriginStateMetadata> GetOriginStateMetadata( 81 const OriginMetadata& aOriginMetadata); 82 83 static Maybe<OriginStateMetadata> LoadDirectoryMetadataHeader( 84 const OriginMetadata& aOriginMetadata); 85 86 static uint64_t TotalDirectoryIterations(); 87 88 static uint64_t SaveOriginAccessTimeCount(); 89 static uint64_t SaveOriginAccessTimeCountInternal(); 90 91 /* Convenience method for tasks which must be called on PBackground thread */ 92 template <class Invokable, class... Args> 93 static auto PerformOnBackgroundThread(Invokable&& aInvokable, Args&&... aArgs) 94 -> std::invoke_result_t<Invokable, Args...> { 95 return PerformOnThread(BackgroundTargetStrongRef(), 96 std::forward<Invokable>(aInvokable), 97 std::forward<Args>(aArgs)...); 98 } 99 100 /* Convenience method for tasks which must be executed on IO thread */ 101 template <class Invokable, class... Args> 102 static auto PerformOnIOThread(Invokable&& aInvokable, Args&&... aArgs) 103 -> std::invoke_result_t<Invokable, Args...> { 104 QuotaManager* quotaManager = QuotaManager::Get(); 105 MOZ_RELEASE_ASSERT(quotaManager); 106 107 return PerformOnThread(quotaManager->IOThread(), 108 std::forward<Invokable>(aInvokable), 109 std::forward<Args>(aArgs)...); 110 } 111 112 template <class Invokable, class... Args, 113 bool ReturnTypeIsVoid = 114 std::is_same_v<std::invoke_result_t<Invokable, Args...>, void>> 115 static auto PerformOnThread(nsISerialEventTarget* aTarget, 116 Invokable&& aInvokable, Args&&... aArgs) 117 -> std::invoke_result_t<Invokable, Args...> { 118 using ReturnType = 119 std::conditional_t<ReturnTypeIsVoid, bool, 120 std::invoke_result_t<Invokable, Args...>>; 121 122 bool done = false; 123 auto boundTask = 124 // For c++17, bind is cleaner than tuple for parameter pack forwarding 125 // NOLINTNEXTLINE(modernize-avoid-bind) 126 std::bind(std::forward<Invokable>(aInvokable), 127 std::forward<Args>(aArgs)...); 128 Maybe<ReturnType> maybeReturnValue; 129 InvokeAsync( 130 aTarget, __func__, 131 [boundTask = std::move(boundTask), &maybeReturnValue]() mutable { 132 if constexpr (ReturnTypeIsVoid) { 133 boundTask(); 134 (void)maybeReturnValue; 135 } else { 136 maybeReturnValue.emplace(boundTask()); 137 } 138 return BoolPromise::CreateAndResolve(true, __func__); 139 }) 140 ->Then(GetCurrentSerialEventTarget(), __func__, 141 [&done](const BoolPromise::ResolveOrRejectValue& /* aValue */) { 142 done = true; 143 }); 144 145 SpinEventLoopUntil("Promise is fulfilled"_ns, [&done]() { return done; }); 146 147 if constexpr (!ReturnTypeIsVoid) { 148 return maybeReturnValue.extract(); 149 } 150 } 151 152 // Acquire and await a client directory lock and pass it to the given task. 153 template <class Task> 154 static void PerformClientDirectoryLockTest( 155 const ClientMetadata& aClientMetadata, Task&& aTask) { 156 PerformOnBackgroundThread( 157 [clientMetadata = aClientMetadata, task = std::forward<Task>(aTask)]() { 158 QuotaManager* quotaManager = QuotaManager::Get(); 159 ASSERT_TRUE(quotaManager); 160 161 RefPtr<ClientDirectoryLock> directoryLock = 162 quotaManager->CreateDirectoryLock(clientMetadata, 163 /* aExclusive */ false); 164 165 auto value = Await(directoryLock->Acquire()); 166 ASSERT_TRUE(value.IsResolve()); 167 168 task(std::move(directoryLock)); 169 }); 170 } 171 172 template <class Task> 173 static void PerformClientDirectoryTest(const ClientMetadata& aClientMetadata, 174 Task&& aTask) { 175 PerformOnBackgroundThread([clientMetadata = aClientMetadata, 176 task = std::forward<Task>(aTask)]() mutable { 177 ClientDirectoryLockHandle directoryLockHandle; 178 179 QuotaManager* quotaManager = QuotaManager::Get(); 180 ASSERT_TRUE(quotaManager); 181 182 bool done = false; 183 184 quotaManager->OpenClientDirectory(clientMetadata) 185 ->Then( 186 GetCurrentSerialEventTarget(), __func__, 187 [&directoryLockHandle, 188 &done](ClientDirectoryLockHandle&& aResolveValue) { 189 directoryLockHandle = std::move(aResolveValue); 190 191 done = true; 192 }, 193 [&done](const nsresult aRejectValue) { 194 ASSERT_TRUE(false); 195 196 done = true; 197 }); 198 199 SpinEventLoopUntil("Promise is fulfilled"_ns, [&done]() { return done; }); 200 201 ASSERT_TRUE(directoryLockHandle); 202 203 PerformOnIOThread(std::move(task), directoryLockHandle->Id()); 204 205 { 206 auto destroyingDirectoryLockHandle = std::move(directoryLockHandle); 207 } 208 }); 209 } 210 211 /* Convenience method for defering execution of code until the promise has 212 * been resolved or rejected */ 213 template <typename ResolveValueT, typename RejectValueT, bool IsExclusive> 214 static typename MozPromise<ResolveValueT, RejectValueT, 215 IsExclusive>::ResolveOrRejectValue 216 Await(RefPtr<MozPromise<ResolveValueT, RejectValueT, IsExclusive>> aPromise) { 217 using PromiseType = MozPromise<ResolveValueT, RejectValueT, IsExclusive>; 218 using ResolveOrRejectValue = typename PromiseType::ResolveOrRejectValue; 219 220 ResolveOrRejectValue value; 221 222 bool done = false; 223 224 auto SelectResolveOrRejectCallback = [&value, &done]() { 225 if constexpr (IsExclusive) { 226 return [&value, &done](ResolveOrRejectValue&& aValue) { 227 value = std::move(aValue); 228 229 done = true; 230 }; 231 } else { 232 return [&value, &done](const ResolveOrRejectValue& aValue) { 233 value = aValue; 234 235 done = true; 236 }; 237 } 238 }; 239 240 aPromise->Then(GetCurrentSerialEventTarget(), __func__, 241 SelectResolveOrRejectCallback()); 242 243 SpinEventLoopUntil("Promise is fulfilled"_ns, [&done]() { return done; }); 244 245 return value; 246 } 247 248 static const nsCOMPtr<nsISerialEventTarget>& BackgroundTargetStrongRef() { 249 return sBackgroundTarget; 250 } 251 252 static PrincipalMetadata GetTestPrincipalMetadata(); 253 static OriginMetadata GetTestPersistentOriginMetadata(); 254 static ClientMetadata GetTestPersistentClientMetadata(); 255 static OriginMetadata GetTestOriginMetadata(); 256 static ClientMetadata GetTestClientMetadata(); 257 static OriginMetadata GetTestPrivateOriginMetadata(); 258 static ClientMetadata GetTestPrivateClientMetadata(); 259 260 static PrincipalMetadata GetOtherTestPrincipalMetadata(); 261 static OriginMetadata GetOtherTestOriginMetadata(); 262 static ClientMetadata GetOtherTestClientMetadata(); 263 264 private: 265 static void EnsureQuotaManager(); 266 267 static nsCOMPtr<nsISerialEventTarget> sBackgroundTarget; 268 }; 269 270 } // namespace mozilla::dom::quota::test 271 272 #endif // DOM_QUOTA_TEST_GTEST_QUOTAMANAGERDEPENDENCYFIXTURE_H_