blob: 93268b361aa418ab84f6cc369c54a68e2008f467 [file] [log] [blame]
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdint.h>
#include <memory>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/scoped_refptr.h"
#include "base/run_loop.h"
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "base/threading/thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/default_clock.h"
#include "content/browser/indexed_db/indexed_db_context_impl.h"
#include "content/browser/indexed_db/indexed_db_quota_client.h"
#include "storage/browser/test/mock_quota_manager.h"
#include "testing/gmock/include/gmock/gmock-matchers.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/storage_key/storage_key.h"
#include "third_party/blink/public/mojom/quota/quota_types.mojom.h"
#include "url/origin.h"
using ::blink::StorageKey;
using ::blink::mojom::StorageType;
// Declared to shorten the line lengths.
static const StorageType kTemp = StorageType::kTemporary;
namespace content {
// Base class for our test fixtures.
class IndexedDBQuotaClientTest : public testing::Test {
public:
const StorageKey kStorageKeyA;
const StorageKey kStorageKeyB;
const StorageKey kStorageKeyOther;
IndexedDBQuotaClientTest()
: kStorageKeyA(StorageKey::CreateFromStringForTesting("http://host")),
kStorageKeyB(
StorageKey::CreateFromStringForTesting("http://host:8000")),
kStorageKeyOther(
StorageKey::CreateFromStringForTesting("http://other")) {
CreateTempDir();
auto quota_manager = base::MakeRefCounted<storage::MockQuotaManager>(
/*in_memory=*/false, temp_dir_.GetPath(),
base::ThreadTaskRunnerHandle::Get(), nullptr);
idb_context_ = base::MakeRefCounted<IndexedDBContextImpl>(
temp_dir_.GetPath(), quota_manager->proxy(),
base::DefaultClock::GetInstance(),
/*blob_storage_context=*/mojo::NullRemote(),
/*file_system_access_context=*/mojo::NullRemote(),
base::SequencedTaskRunnerHandle::Get(),
base::SequencedTaskRunnerHandle::Get());
base::RunLoop().RunUntilIdle();
SetupTempDir();
}
void CreateTempDir() { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); }
void SetupTempDir() {
ASSERT_TRUE(base::CreateDirectory(idb_context_->data_path()));
}
IndexedDBQuotaClientTest(const IndexedDBQuotaClientTest&) = delete;
IndexedDBQuotaClientTest& operator=(const IndexedDBQuotaClientTest&) = delete;
~IndexedDBQuotaClientTest() override {
base::RunLoop().RunUntilIdle();
idb_context_ = nullptr;
base::RunLoop().RunUntilIdle();
}
static int64_t GetStorageKeyUsage(storage::mojom::QuotaClient& client,
const StorageKey& storage_key,
StorageType type) {
int result = -1;
base::RunLoop loop;
client.GetStorageKeyUsage(storage_key, type,
base::BindLambdaForTesting([&](int64_t usage) {
result = usage;
loop.Quit();
}));
loop.Run();
EXPECT_GT(result, -1);
return result;
}
static std::vector<StorageKey> GetStorageKeysForType(
storage::mojom::QuotaClient& client,
StorageType type) {
std::vector<StorageKey> result;
base::RunLoop loop;
client.GetStorageKeysForType(
type, base::BindLambdaForTesting(
[&](const std::vector<StorageKey>& storage_keys) {
result = storage_keys;
loop.Quit();
}));
loop.Run();
return result;
}
static std::vector<StorageKey> GetStorageKeysForHost(
storage::mojom::QuotaClient& client,
StorageType type,
const std::string& host) {
std::vector<StorageKey> result;
base::RunLoop loop;
client.GetStorageKeysForHost(
type, host,
base::BindLambdaForTesting(
[&](const std::vector<StorageKey>& storage_keys) {
result = storage_keys;
loop.Quit();
}));
loop.Run();
return result;
}
static blink::mojom::QuotaStatusCode DeleteStorageKeyData(
storage::mojom::QuotaClient& client,
const StorageKey& storage_key,
StorageType type) {
blink::mojom::QuotaStatusCode result =
blink::mojom::QuotaStatusCode::kUnknown;
base::RunLoop loop;
client.DeleteStorageKeyData(
storage_key, type,
base::BindLambdaForTesting([&](blink::mojom::QuotaStatusCode code) {
result = code;
loop.Quit();
}));
loop.Run();
return result;
}
IndexedDBContextImpl* idb_context() { return idb_context_.get(); }
void SetFileSizeTo(const base::FilePath& path, int size) {
std::string junk(size, 'a');
ASSERT_TRUE(base::WriteFile(path, junk));
}
void AddFakeIndexedDB(const StorageKey& storage_key, int size) {
base::FilePath file_path_storage_key;
{
base::RunLoop run_loop;
idb_context()->GetFilePathForTesting(
blink::StorageKey(storage_key),
base::BindLambdaForTesting([&](const base::FilePath& path) {
file_path_storage_key = path;
run_loop.Quit();
}));
run_loop.Run();
}
if (!base::CreateDirectory(file_path_storage_key)) {
LOG(ERROR) << "failed to base::CreateDirectory "
<< file_path_storage_key.value();
}
file_path_storage_key =
file_path_storage_key.Append(FILE_PATH_LITERAL("fake_file"));
SetFileSizeTo(file_path_storage_key, size);
{
base::RunLoop run_loop;
idb_context()->ResetCachesForTesting(run_loop.QuitClosure());
run_loop.Run();
}
}
private:
base::test::TaskEnvironment task_environment_;
base::ScopedTempDir temp_dir_;
scoped_refptr<IndexedDBContextImpl> idb_context_;
base::WeakPtrFactory<IndexedDBQuotaClientTest> weak_factory_{this};
};
TEST_F(IndexedDBQuotaClientTest, GetStorageKeyUsage) {
IndexedDBQuotaClient client(*idb_context());
AddFakeIndexedDB(kStorageKeyA, 6);
AddFakeIndexedDB(kStorageKeyB, 3);
EXPECT_EQ(6, GetStorageKeyUsage(client, kStorageKeyA, kTemp));
EXPECT_EQ(3, GetStorageKeyUsage(client, kStorageKeyB, kTemp));
AddFakeIndexedDB(kStorageKeyA, 1000);
EXPECT_EQ(1000, GetStorageKeyUsage(client, kStorageKeyA, kTemp));
EXPECT_EQ(3, GetStorageKeyUsage(client, kStorageKeyB, kTemp));
}
TEST_F(IndexedDBQuotaClientTest, GetStorageKeysForHost) {
IndexedDBQuotaClient client(*idb_context());
EXPECT_EQ(kStorageKeyA.origin().host(), kStorageKeyB.origin().host());
EXPECT_NE(kStorageKeyA.origin().host(), kStorageKeyOther.origin().host());
std::vector<StorageKey> storage_keys =
GetStorageKeysForHost(client, kTemp, kStorageKeyA.origin().host());
EXPECT_TRUE(storage_keys.empty());
AddFakeIndexedDB(kStorageKeyA, 1000);
storage_keys =
GetStorageKeysForHost(client, kTemp, kStorageKeyA.origin().host());
EXPECT_EQ(storage_keys.size(), 1ul);
EXPECT_THAT(storage_keys, testing::Contains(kStorageKeyA));
AddFakeIndexedDB(kStorageKeyB, 1000);
storage_keys =
GetStorageKeysForHost(client, kTemp, kStorageKeyA.origin().host());
EXPECT_EQ(storage_keys.size(), 2ul);
EXPECT_THAT(storage_keys, testing::Contains(kStorageKeyA));
EXPECT_THAT(storage_keys, testing::Contains(kStorageKeyB));
EXPECT_TRUE(
GetStorageKeysForHost(client, kTemp, kStorageKeyOther.origin().host())
.empty());
}
TEST_F(IndexedDBQuotaClientTest, GetStorageKeysForType) {
IndexedDBQuotaClient client(*idb_context());
EXPECT_TRUE(GetStorageKeysForType(client, kTemp).empty());
AddFakeIndexedDB(kStorageKeyA, 1000);
std::vector<StorageKey> storage_keys = GetStorageKeysForType(client, kTemp);
EXPECT_EQ(storage_keys.size(), 1ul);
EXPECT_THAT(storage_keys, testing::Contains(kStorageKeyA));
}
TEST_F(IndexedDBQuotaClientTest, DeleteStorageKey) {
IndexedDBQuotaClient client(*idb_context());
AddFakeIndexedDB(kStorageKeyA, 1000);
AddFakeIndexedDB(kStorageKeyB, 50);
EXPECT_EQ(1000, GetStorageKeyUsage(client, kStorageKeyA, kTemp));
EXPECT_EQ(50, GetStorageKeyUsage(client, kStorageKeyB, kTemp));
blink::mojom::QuotaStatusCode delete_status =
DeleteStorageKeyData(client, kStorageKeyA, kTemp);
EXPECT_EQ(blink::mojom::QuotaStatusCode::kOk, delete_status);
EXPECT_EQ(0, GetStorageKeyUsage(client, kStorageKeyA, kTemp));
EXPECT_EQ(50, GetStorageKeyUsage(client, kStorageKeyB, kTemp));
}
TEST_F(IndexedDBQuotaClientTest, IncognitoQuota) {
auto quota_manager = base::MakeRefCounted<storage::MockQuotaManager>(
/*in_memory=*/true, base::FilePath(), base::ThreadTaskRunnerHandle::Get(),
nullptr);
auto incognito_idb_context = base::MakeRefCounted<IndexedDBContextImpl>(
base::FilePath(), quota_manager->proxy(),
base::DefaultClock::GetInstance(),
/*blob_storage_context=*/mojo::NullRemote(),
/*file_system_access_context=*/mojo::NullRemote(),
base::SequencedTaskRunnerHandle::Get(),
base::SequencedTaskRunnerHandle::Get());
base::RunLoop().RunUntilIdle();
IndexedDBQuotaClient client(*incognito_idb_context.get());
// No FakeIndexDB is added.
EXPECT_TRUE(GetStorageKeysForType(client, kTemp).empty());
EXPECT_TRUE(GetStorageKeysForHost(client, kTemp, kStorageKeyA.origin().host())
.empty());
EXPECT_EQ(0, GetStorageKeyUsage(client, kStorageKeyA, kTemp));
}
} // namespace content