Files
tubestation/dom/quota/test/gtest/TestFileOutputStream.cpp
Jan Varga 7783acd7c8 Bug 1866402 - Make it possible to initialize temporary origins without ensuring origin directories; r=dom-storage-reviewers,jari
LSNG already uses some QuotaManager APIs to achieve that origin directories are
not created if they don't exist during datastore preparation, but the feature
is not easy to use and it's also not generalized enough for use in other quota
clients. Besides that, the way how it's currently done in LSNG complicates
removal of QuotaManager::EnsureTemporaryOriginIsInitializedInternal calls from
LSNG. This patch is about generalizing of the feature, making it available to
all quota clients.

Differential Revision: https://phabricator.services.mozilla.com/D195551
2024-10-12 20:58:36 +00:00

226 lines
7.0 KiB
C++

/* -*- 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 "mozilla/dom/quota/Client.h"
#include "mozilla/dom/quota/CommonMetadata.h"
#include "mozilla/dom/quota/DirectoryLock.h"
#include "mozilla/dom/quota/FileStreams.h"
#include "mozilla/dom/quota/QuotaManager.h"
#include "mozilla/gtest/MozAssertions.h"
#include "nsIPrefBranch.h"
#include "nsIPrefService.h"
#include "QuotaManagerDependencyFixture.h"
namespace mozilla::dom::quota::test {
quota::OriginMetadata GetOutputStreamTestOriginMetadata() {
return quota::OriginMetadata{""_ns,
"example.com"_ns,
"http://example.com"_ns,
"http://example.com"_ns,
/* aIsPrivate */ false,
quota::PERSISTENCE_TYPE_DEFAULT};
}
class TestFileOutputStream : public QuotaManagerDependencyFixture {
public:
static void SetUpTestCase() {
ASSERT_NO_FATAL_FAILURE(InitializeFixture());
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
prefs->SetIntPref("dom.quotaManager.temporaryStorage.fixedLimit",
mQuotaLimit);
}
static void TearDownTestCase() {
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
prefs->ClearUserPref("dom.quotaManager.temporaryStorage.fixedLimit");
EXPECT_NO_FATAL_FAILURE(
ClearStoragesForOrigin(GetOutputStreamTestOriginMetadata()));
ASSERT_NO_FATAL_FAILURE(ShutdownFixture());
}
static const int32_t mQuotaLimit = 8192;
};
TEST_F(TestFileOutputStream, extendFileStreamWithSetEOF) {
auto backgroundTask = []() {
auto ioTask = []() {
quota::QuotaManager* quotaManager = quota::QuotaManager::Get();
auto originMetadata = GetOutputStreamTestOriginMetadata();
{
auto res = quotaManager->EnsureTemporaryOriginIsInitializedInternal(
originMetadata, /* aCreateIfNonExistent */ true);
ASSERT_TRUE(res.isOk());
}
const int64_t groupLimit =
static_cast<int64_t>(quotaManager->GetGroupLimit());
ASSERT_TRUE(mQuotaLimit * 1024LL == groupLimit);
// We don't use the tested stream itself to check the file size as it
// may report values which have not been written to disk.
RefPtr<quota::FileOutputStream> check =
MakeRefPtr<quota::FileOutputStream>(quota::PERSISTENCE_TYPE_DEFAULT,
originMetadata,
quota::Client::Type::SDB);
RefPtr<quota::FileOutputStream> stream =
MakeRefPtr<quota::FileOutputStream>(quota::PERSISTENCE_TYPE_DEFAULT,
originMetadata,
quota::Client::Type::SDB);
{
auto testPathRes =
quotaManager->GetOrCreateTemporaryOriginDirectory(originMetadata);
ASSERT_TRUE(testPathRes.isOk());
nsCOMPtr<nsIFile> testPath = testPathRes.unwrap();
ASSERT_NS_SUCCEEDED(testPath->AppendRelativePath(u"sdb"_ns));
ASSERT_NS_SUCCEEDED(
testPath->AppendRelativePath(u"tTestFileOutputStream.txt"_ns));
bool exists = true;
ASSERT_NS_SUCCEEDED(testPath->Exists(&exists));
if (exists) {
ASSERT_NS_SUCCEEDED(testPath->Remove(/* recursive */ false));
}
ASSERT_NS_SUCCEEDED(testPath->Exists(&exists));
ASSERT_FALSE(exists);
ASSERT_NS_SUCCEEDED(testPath->Create(nsIFile::NORMAL_FILE_TYPE, 0666));
ASSERT_NS_SUCCEEDED(testPath->Exists(&exists));
ASSERT_TRUE(exists);
nsCOMPtr<nsIFile> checkPath;
ASSERT_NS_SUCCEEDED(testPath->Clone(getter_AddRefs(checkPath)));
const int32_t IOFlags = -1;
const int32_t perm = -1;
const int32_t behaviorFlags = 0;
ASSERT_NS_SUCCEEDED(
stream->Init(testPath, IOFlags, perm, behaviorFlags));
ASSERT_NS_SUCCEEDED(
check->Init(testPath, IOFlags, perm, behaviorFlags));
}
// Check that we start with an empty file
int64_t avail = 42;
ASSERT_NS_SUCCEEDED(check->GetSize(&avail));
ASSERT_TRUE(0 == avail);
// Enlarge the file
const int64_t toSize = groupLimit;
ASSERT_NS_SUCCEEDED(stream->Seek(nsISeekableStream::NS_SEEK_SET, toSize));
ASSERT_NS_SUCCEEDED(check->GetSize(&avail));
ASSERT_TRUE(0 == avail);
ASSERT_NS_SUCCEEDED(stream->SetEOF());
ASSERT_NS_SUCCEEDED(check->GetSize(&avail));
ASSERT_TRUE(toSize == avail);
// Try to enlarge the file past the limit
const int64_t overGroupLimit = groupLimit + 1;
// Seeking is allowed
ASSERT_NS_SUCCEEDED(
stream->Seek(nsISeekableStream::NS_SEEK_SET, overGroupLimit));
ASSERT_NS_SUCCEEDED(check->GetSize(&avail));
ASSERT_TRUE(toSize == avail);
// Setting file size to exceed quota should yield no device space error
ASSERT_TRUE(NS_ERROR_FILE_NO_DEVICE_SPACE == stream->SetEOF());
ASSERT_NS_SUCCEEDED(check->GetSize(&avail));
ASSERT_TRUE(toSize == avail);
// Shrink the file
const int64_t toHalfSize = toSize / 2;
ASSERT_NS_SUCCEEDED(
stream->Seek(nsISeekableStream::NS_SEEK_SET, toHalfSize));
ASSERT_NS_SUCCEEDED(check->GetSize(&avail));
ASSERT_TRUE(toSize == avail);
ASSERT_NS_SUCCEEDED(stream->SetEOF());
ASSERT_NS_SUCCEEDED(check->GetSize(&avail));
ASSERT_TRUE(toHalfSize == avail);
// Shrink the file back to nothing
ASSERT_NS_SUCCEEDED(stream->Seek(nsISeekableStream::NS_SEEK_SET, 0));
ASSERT_NS_SUCCEEDED(check->GetSize(&avail));
ASSERT_TRUE(toHalfSize == avail);
ASSERT_NS_SUCCEEDED(stream->SetEOF());
ASSERT_NS_SUCCEEDED(check->GetSize(&avail));
ASSERT_TRUE(0 == avail);
};
RefPtr<ClientDirectoryLock> directoryLock;
QuotaManager* quotaManager = QuotaManager::Get();
ASSERT_TRUE(quotaManager);
bool done = false;
quotaManager
->OpenClientDirectory(
{GetOutputStreamTestOriginMetadata(), Client::SDB})
->Then(
GetCurrentSerialEventTarget(), __func__,
[&directoryLock, &done](RefPtr<ClientDirectoryLock> aResolveValue) {
directoryLock = std::move(aResolveValue);
done = true;
},
[&done](const nsresult aRejectValue) {
ASSERT_TRUE(false);
done = true;
});
SpinEventLoopUntil("Promise is fulfilled"_ns, [&done]() { return done; });
ASSERT_TRUE(directoryLock);
PerformOnIOThread(std::move(ioTask));
DropDirectoryLock(directoryLock);
};
PerformOnBackgroundThread(std::move(backgroundTask));
}
} // namespace mozilla::dom::quota::test