summaryrefslogtreecommitdiffstats
path: root/dom/quota/test/gtest/TestStorageConnection.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/quota/test/gtest/TestStorageConnection.cpp')
-rw-r--r--dom/quota/test/gtest/TestStorageConnection.cpp283
1 files changed, 283 insertions, 0 deletions
diff --git a/dom/quota/test/gtest/TestStorageConnection.cpp b/dom/quota/test/gtest/TestStorageConnection.cpp
new file mode 100644
index 0000000000..9ff19ec44f
--- /dev/null
+++ b/dom/quota/test/gtest/TestStorageConnection.cpp
@@ -0,0 +1,283 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "QuotaManagerDependencyFixture.h"
+#include "mozIStorageConnection.h"
+#include "mozIStorageService.h"
+#include "mozStorageCID.h"
+#include "mozilla/dom/quota/IPCStreamCipherStrategy.h"
+#include "mozilla/dom/quota/QuotaCommon.h"
+#include "mozilla/dom/quota/QuotaManager.h"
+#include "mozilla/dom/quota/QuotaObject.h"
+#include "mozilla/dom/quota/ResultExtensions.h"
+#include "nsIFile.h"
+#include "nsIFileProtocolHandler.h"
+#include "nsIFileURL.h"
+#include "nsIURIMutator.h"
+#include "nss.h"
+
+namespace mozilla {
+
+struct NSSInitContextDeleter {
+ void operator()(NSSInitContext* p) { NSS_ShutdownContext(p); }
+};
+
+namespace dom::quota::test {
+
+namespace {
+
+void InitializeClientDirectory(const ClientMetadata& aClientMetadata) {
+ QuotaManager* quotaManager = QuotaManager::Get();
+
+ QM_TRY(MOZ_TO_RESULT(
+ quotaManager->EnsureTemporaryStorageIsInitializedInternal()),
+ QM_TEST_FAIL);
+
+ QM_TRY_INSPECT(const auto& directory,
+ quotaManager
+ ->EnsureTemporaryOriginIsInitialized(
+ aClientMetadata.mPersistenceType, aClientMetadata)
+ .map([](const auto& aPair) { return aPair.first; }),
+ QM_TEST_FAIL);
+
+ QM_TRY(MOZ_TO_RESULT(directory->Append(
+ Client::TypeToString(aClientMetadata.mClientType))),
+ QM_TEST_FAIL);
+
+ QM_TRY_INSPECT(const bool& exists,
+ MOZ_TO_RESULT_INVOKE_MEMBER(directory, Exists), QM_TEST_FAIL);
+
+ if (!exists) {
+ QM_TRY(MOZ_TO_RESULT(directory->Create(nsIFile::DIRECTORY_TYPE, 0755)),
+ QM_TEST_FAIL);
+ }
+}
+
+void CreateStorageConnection(
+ const ClientMetadata& aClientMetadata,
+ const Maybe<int64_t>& aMaybeDirectoryLockId,
+ const Maybe<IPCStreamCipherStrategy::KeyType>& aMaybeKey,
+ nsCOMPtr<mozIStorageConnection>& aConnection) {
+ QuotaManager* quotaManager = QuotaManager::Get();
+
+ QM_TRY_UNWRAP(auto databaseFile,
+ quotaManager->GetOriginDirectory(aClientMetadata),
+ QM_TEST_FAIL);
+
+ QM_TRY(MOZ_TO_RESULT(databaseFile->Append(
+ Client::TypeToString(aClientMetadata.mClientType))),
+ QM_TEST_FAIL);
+
+ QM_TRY(MOZ_TO_RESULT(databaseFile->Append(u"testdatabase.sqlite"_ns)),
+ QM_TEST_FAIL);
+
+ QM_TRY_INSPECT(
+ const auto& protocolHandler,
+ MOZ_TO_RESULT_GET_TYPED(nsCOMPtr<nsIProtocolHandler>,
+ MOZ_SELECT_OVERLOAD(do_GetService),
+ NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "file"),
+ QM_TEST_FAIL);
+
+ QM_TRY_INSPECT(const auto& fileHandler,
+ MOZ_TO_RESULT_GET_TYPED(nsCOMPtr<nsIFileProtocolHandler>,
+ MOZ_SELECT_OVERLOAD(do_QueryInterface),
+ protocolHandler),
+ QM_TEST_FAIL);
+
+ QM_TRY_INSPECT(
+ const auto& mutator,
+ MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsCOMPtr<nsIURIMutator>, fileHandler,
+ NewFileURIMutator, databaseFile),
+ QM_TEST_FAIL);
+
+ const auto directoryLockIdClause = [&aMaybeDirectoryLockId] {
+ nsAutoCString directoryLockIdClause;
+ if (aMaybeDirectoryLockId) {
+ directoryLockIdClause =
+ "&directoryLockId="_ns + IntToCString(*aMaybeDirectoryLockId);
+ }
+ return directoryLockIdClause;
+ }();
+
+ const auto keyClause = [&aMaybeKey] {
+ nsAutoCString keyClause;
+ if (aMaybeKey) {
+ keyClause.AssignLiteral("&key=");
+ for (uint8_t byte : IPCStreamCipherStrategy::SerializeKey(*aMaybeKey)) {
+ keyClause.AppendPrintf("%02x", byte);
+ }
+ }
+ return keyClause;
+ }();
+
+ QM_TRY_INSPECT(
+ const auto& fileURL,
+ ([&mutator, &directoryLockIdClause,
+ &keyClause]() -> Result<nsCOMPtr<nsIFileURL>, nsresult> {
+ nsCOMPtr<nsIFileURL> result;
+ QM_TRY(MOZ_TO_RESULT(NS_MutateURI(mutator)
+ .SetQuery("cache=private"_ns +
+ directoryLockIdClause + keyClause)
+ .Finalize(result)));
+ return result;
+ }()),
+ QM_TEST_FAIL);
+
+ QM_TRY_INSPECT(const auto& storageService,
+ MOZ_TO_RESULT_GET_TYPED(nsCOMPtr<mozIStorageService>,
+ MOZ_SELECT_OVERLOAD(do_GetService),
+ MOZ_STORAGE_SERVICE_CONTRACTID),
+ QM_TEST_FAIL);
+
+ QM_TRY_UNWRAP(auto connection,
+ MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(
+ nsCOMPtr<mozIStorageConnection>, storageService,
+ OpenDatabaseWithFileURL, fileURL, EmptyCString(),
+ mozIStorageService::CONNECTION_DEFAULT),
+ QM_TEST_FAIL);
+
+ QM_TRY(MOZ_TO_RESULT(
+ connection->ExecuteSimpleSQL("PRAGMA journal_mode = wal;"_ns)),
+ QM_TEST_FAIL);
+
+ // The connection needs to be re-created, otherwise GetQuotaObjects is not
+ // able to get the quota object for the journal file.
+
+ QM_TRY(MOZ_TO_RESULT(connection->Close()), QM_TEST_FAIL);
+
+ QM_TRY_UNWRAP(connection,
+ MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(
+ nsCOMPtr<mozIStorageConnection>, storageService,
+ OpenDatabaseWithFileURL, fileURL, EmptyCString(),
+ mozIStorageService::CONNECTION_DEFAULT),
+ QM_TEST_FAIL);
+
+ aConnection = std::move(connection);
+}
+
+} // namespace
+
+class TestStorageConnection : public QuotaManagerDependencyFixture {
+ public:
+ static void SetUpTestCase() {
+ // Do this only once, do not tear it down per test case.
+ if (!sNssContext) {
+ sNssContext.reset(
+ NSS_InitContext("", "", "", "", nullptr,
+ NSS_INIT_READONLY | NSS_INIT_NOCERTDB |
+ NSS_INIT_NOMODDB | NSS_INIT_FORCEOPEN |
+ NSS_INIT_OPTIMIZESPACE | NSS_INIT_NOROOTINIT));
+ }
+
+ ASSERT_NO_FATAL_FAILURE(InitializeFixture());
+ }
+
+ static void TearDownTestCase() {
+ ASSERT_NO_FATAL_FAILURE(ShutdownFixture());
+
+ sNssContext = nullptr;
+ }
+
+ void TearDown() override {
+ ASSERT_NO_FATAL_FAILURE(ClearStoragesForOrigin(GetTestOriginMetadata()));
+ }
+
+ private:
+ struct NSSInitContextDeleter {
+ void operator()(NSSInitContext* p) { NSS_ShutdownContext(p); }
+ };
+ inline static std::unique_ptr<NSSInitContext, NSSInitContextDeleter>
+ sNssContext;
+};
+
+TEST_F(TestStorageConnection, BaseVFS) {
+ // XXX This call can't be wrapped with ASSERT_NO_FATAL_FAILURE because
+ // base-toolchains builds fail with: error: duplicate label
+ // 'gtest_label_testnofatal_214'
+ PerformClientDirectoryTest(GetTestClientMetadata(), [](int64_t) {
+ ASSERT_NO_FATAL_FAILURE(InitializeClientDirectory(GetTestClientMetadata()));
+
+ nsCOMPtr<mozIStorageConnection> connection;
+ ASSERT_NO_FATAL_FAILURE(CreateStorageConnection(
+ GetTestClientMetadata(), Nothing(), Nothing(), connection));
+
+ RefPtr<QuotaObject> quotaObject;
+ RefPtr<QuotaObject> journalQuotaObject;
+
+ nsresult rv = connection->GetQuotaObjects(
+ getter_AddRefs(quotaObject), getter_AddRefs(journalQuotaObject));
+ ASSERT_EQ(rv, NS_ERROR_FAILURE);
+
+ ASSERT_FALSE(quotaObject);
+ ASSERT_FALSE(journalQuotaObject);
+
+ QM_TRY(MOZ_TO_RESULT(connection->Close()), QM_TEST_FAIL);
+ });
+}
+
+TEST_F(TestStorageConnection, QuotaVFS) {
+ // XXX This call can't be wrapped with ASSERT_NO_FATAL_FAILURE because
+ // base-toolchains builds fail with: error: duplicate label
+ // 'gtest_label_testnofatal_214'
+ PerformClientDirectoryTest(
+ GetTestClientMetadata(), [](int64_t aDirectoryLockId) {
+ ASSERT_NO_FATAL_FAILURE(
+ InitializeClientDirectory(GetTestClientMetadata()));
+
+ nsCOMPtr<mozIStorageConnection> connection;
+ ASSERT_NO_FATAL_FAILURE(CreateStorageConnection(GetTestClientMetadata(),
+ Some(aDirectoryLockId),
+ Nothing(), connection));
+
+ RefPtr<QuotaObject> quotaObject;
+ RefPtr<QuotaObject> journalQuotaObject;
+
+ QM_TRY(MOZ_TO_RESULT(connection->GetQuotaObjects(
+ getter_AddRefs(quotaObject),
+ getter_AddRefs(journalQuotaObject))),
+ QM_TEST_FAIL);
+
+ ASSERT_TRUE(quotaObject);
+ ASSERT_TRUE(journalQuotaObject);
+
+ QM_TRY(MOZ_TO_RESULT(connection->Close()), QM_TEST_FAIL);
+ });
+}
+
+TEST_F(TestStorageConnection, ObfuscatingVFS) {
+ // XXX This call can't be wrapped with ASSERT_NO_FATAL_FAILURE because
+ // base-toolchains builds fail with: error: duplicate label
+ // 'gtest_label_testnofatal_214'
+ PerformClientDirectoryTest(
+ GetTestClientMetadata(), [](int64_t aDirectoryLockId) {
+ ASSERT_NO_FATAL_FAILURE(
+ InitializeClientDirectory(GetTestClientMetadata()));
+
+ QM_TRY_INSPECT(const auto& key, IPCStreamCipherStrategy::GenerateKey(),
+ QM_TEST_FAIL);
+
+ nsCOMPtr<mozIStorageConnection> connection;
+ ASSERT_NO_FATAL_FAILURE(CreateStorageConnection(GetTestClientMetadata(),
+ Some(aDirectoryLockId),
+ Some(key), connection));
+
+ RefPtr<QuotaObject> quotaObject;
+ RefPtr<QuotaObject> journalQuotaObject;
+
+ QM_TRY(MOZ_TO_RESULT(connection->GetQuotaObjects(
+ getter_AddRefs(quotaObject),
+ getter_AddRefs(journalQuotaObject))),
+ QM_TEST_FAIL);
+
+ ASSERT_TRUE(quotaObject);
+ ASSERT_TRUE(journalQuotaObject);
+
+ QM_TRY(MOZ_TO_RESULT(connection->Close()), QM_TEST_FAIL);
+ });
+}
+
+} // namespace dom::quota::test
+} // namespace mozilla