1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <stdint.h>
6
7 #include <map>
8 #include <memory>
9 #include <utility>
10
11 #include "base/bind.h"
12 #include "base/files/file_path.h"
13 #include "base/files/file_util.h"
14 #include "base/files/scoped_temp_dir.h"
15 #include "base/macros.h"
16 #include "base/memory/scoped_refptr.h"
17 #include "base/run_loop.h"
18 #include "base/test/bind_test_util.h"
19 #include "base/test/task_environment.h"
20 #include "base/threading/sequenced_task_runner_handle.h"
21 #include "base/threading/thread.h"
22 #include "base/threading/thread_task_runner_handle.h"
23 #include "base/time/default_clock.h"
24 #include "content/browser/indexed_db/indexed_db_context_impl.h"
25 #include "content/browser/indexed_db/indexed_db_quota_client.h"
26 #include "storage/browser/test/mock_quota_manager.h"
27 #include "testing/gtest/include/gtest/gtest.h"
28
29 using blink::mojom::StorageType;
30
31 // Declared to shorten the line lengths.
32 static const StorageType kTemp = StorageType::kTemporary;
33 static const StorageType kPerm = StorageType::kPersistent;
34 static const StorageType kSync = StorageType::kSyncable;
35
36 namespace content {
37
38 // Base class for our test fixtures.
39 class IndexedDBQuotaClientTest : public testing::Test {
40 public:
41 const url::Origin kOriginA;
42 const url::Origin kOriginB;
43 const url::Origin kOriginOther;
44
IndexedDBQuotaClientTest()45 IndexedDBQuotaClientTest()
46 : kOriginA(url::Origin::Create(GURL("http://host"))),
47 kOriginB(url::Origin::Create(GURL("http://host:8000"))),
48 kOriginOther(url::Origin::Create(GURL("http://other"))),
49 usage_(0) {
50 CreateTempDir();
51 auto quota_manager = base::MakeRefCounted<storage::MockQuotaManager>(
52 /*in_memory=*/false, temp_dir_.GetPath(),
53 base::ThreadTaskRunnerHandle::Get(), nullptr);
54
55 idb_context_ = base::MakeRefCounted<IndexedDBContextImpl>(
56 temp_dir_.GetPath(), nullptr, quota_manager->proxy(),
57 base::DefaultClock::GetInstance(),
58 /*blob_storage_context=*/mojo::NullRemote(),
59 /*native_file_system_context=*/mojo::NullRemote(),
60 base::SequencedTaskRunnerHandle::Get(),
61 base::SequencedTaskRunnerHandle::Get());
62 base::RunLoop().RunUntilIdle();
63 SetupTempDir();
64 }
65
CreateTempDir()66 void CreateTempDir() { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); }
67
SetupTempDir()68 void SetupTempDir() {
69 base::FilePath indexeddb_dir =
70 temp_dir_.GetPath().Append(IndexedDBContextImpl::kIndexedDBDirectory);
71 ASSERT_TRUE(base::CreateDirectory(indexeddb_dir));
72 idb_context()->set_data_path_for_testing(indexeddb_dir);
73 }
74
~IndexedDBQuotaClientTest()75 ~IndexedDBQuotaClientTest() override {
76 base::RunLoop().RunUntilIdle();
77 idb_context_ = nullptr;
78 base::RunLoop().RunUntilIdle();
79 }
80
GetOriginUsage(scoped_refptr<storage::QuotaClient> client,const url::Origin & origin,StorageType type)81 int64_t GetOriginUsage(scoped_refptr<storage::QuotaClient> client,
82 const url::Origin& origin,
83 StorageType type) {
84 usage_ = -1;
85 base::RunLoop loop;
86 client->GetOriginUsage(origin, type,
87 base::BindLambdaForTesting([&](int64_t usage) {
88 usage_ = usage;
89 loop.Quit();
90 }));
91 loop.Run();
92 EXPECT_GT(usage_, -1);
93 return usage_;
94 }
95
GetOriginsForType(scoped_refptr<storage::QuotaClient> client,StorageType type)96 const std::set<url::Origin>& GetOriginsForType(
97 scoped_refptr<storage::QuotaClient> client,
98 StorageType type) {
99 origins_.clear();
100 base::RunLoop loop;
101 client->GetOriginsForType(
102 type,
103 base::BindLambdaForTesting([&](const std::set<url::Origin>& origins) {
104 origins_ = origins;
105 loop.Quit();
106 }));
107 loop.Run();
108 return origins_;
109 }
110
GetOriginsForHost(scoped_refptr<storage::QuotaClient> client,StorageType type,const std::string & host)111 const std::set<url::Origin>& GetOriginsForHost(
112 scoped_refptr<storage::QuotaClient> client,
113 StorageType type,
114 const std::string& host) {
115 origins_.clear();
116 base::RunLoop loop;
117 client->GetOriginsForHost(
118 type, host,
119 base::BindLambdaForTesting([&](const std::set<url::Origin>& origins) {
120 origins_ = origins;
121 loop.Quit();
122 }));
123 loop.Run();
124 return origins_;
125 }
126
DeleteOrigin(scoped_refptr<storage::QuotaClient> client,const url::Origin & origin,StorageType type)127 blink::mojom::QuotaStatusCode DeleteOrigin(
128 scoped_refptr<storage::QuotaClient> client,
129 const url::Origin& origin,
130 StorageType type) {
131 delete_status_ = blink::mojom::QuotaStatusCode::kUnknown;
132 base::RunLoop loop;
133 client->DeleteOriginData(
134 origin, type,
135 base::BindLambdaForTesting([&](blink::mojom::QuotaStatusCode code) {
136 delete_status_ = code;
137 loop.Quit();
138 }));
139 loop.Run();
140 return delete_status_;
141 }
142
idb_context()143 IndexedDBContextImpl* idb_context() { return idb_context_.get(); }
144
SetFileSizeTo(const base::FilePath & path,int size)145 void SetFileSizeTo(const base::FilePath& path, int size) {
146 std::string junk(size, 'a');
147 ASSERT_EQ(size, base::WriteFile(path, junk.c_str(), size));
148 }
149
AddFakeIndexedDB(const url::Origin & origin,int size)150 void AddFakeIndexedDB(const url::Origin& origin, int size) {
151 base::FilePath file_path_origin;
152 {
153 base::RunLoop run_loop;
154 idb_context()->GetFilePathForTesting(
155 origin, base::BindLambdaForTesting([&](const base::FilePath& path) {
156 file_path_origin = path;
157 run_loop.Quit();
158 }));
159 run_loop.Run();
160 }
161 if (!base::CreateDirectory(file_path_origin)) {
162 LOG(ERROR) << "failed to base::CreateDirectory "
163 << file_path_origin.value();
164 }
165 file_path_origin = file_path_origin.Append(FILE_PATH_LITERAL("fake_file"));
166 SetFileSizeTo(file_path_origin, size);
167
168 {
169 base::RunLoop run_loop;
170 idb_context()->ResetCachesForTesting(run_loop.QuitClosure());
171 run_loop.Run();
172 }
173 }
174
175 private:
176 base::test::TaskEnvironment task_environment_;
177 base::ScopedTempDir temp_dir_;
178 int64_t usage_;
179 std::set<url::Origin> origins_;
180 scoped_refptr<IndexedDBContextImpl> idb_context_;
181 blink::mojom::QuotaStatusCode delete_status_;
182 base::WeakPtrFactory<IndexedDBQuotaClientTest> weak_factory_{this};
183
184 DISALLOW_COPY_AND_ASSIGN(IndexedDBQuotaClientTest);
185 };
186
TEST_F(IndexedDBQuotaClientTest,GetOriginUsage)187 TEST_F(IndexedDBQuotaClientTest, GetOriginUsage) {
188 auto client = base::MakeRefCounted<IndexedDBQuotaClient>(idb_context());
189
190 AddFakeIndexedDB(kOriginA, 6);
191 AddFakeIndexedDB(kOriginB, 3);
192 EXPECT_EQ(6, GetOriginUsage(client, kOriginA, kTemp));
193 EXPECT_EQ(0, GetOriginUsage(client, kOriginA, kPerm));
194 EXPECT_EQ(3, GetOriginUsage(client, kOriginB, kTemp));
195 EXPECT_EQ(0, GetOriginUsage(client, kOriginB, kPerm));
196
197 AddFakeIndexedDB(kOriginA, 1000);
198 EXPECT_EQ(1000, GetOriginUsage(client, kOriginA, kTemp));
199 EXPECT_EQ(0, GetOriginUsage(client, kOriginA, kPerm));
200 EXPECT_EQ(3, GetOriginUsage(client, kOriginB, kTemp));
201 EXPECT_EQ(0, GetOriginUsage(client, kOriginB, kPerm));
202 }
203
TEST_F(IndexedDBQuotaClientTest,GetOriginsForHost)204 TEST_F(IndexedDBQuotaClientTest, GetOriginsForHost) {
205 auto client = base::MakeRefCounted<IndexedDBQuotaClient>(idb_context());
206
207 EXPECT_EQ(kOriginA.host(), kOriginB.host());
208 EXPECT_NE(kOriginA.host(), kOriginOther.host());
209
210 std::set<url::Origin> origins =
211 GetOriginsForHost(client, kTemp, kOriginA.host());
212 EXPECT_TRUE(origins.empty());
213
214 AddFakeIndexedDB(kOriginA, 1000);
215 origins = GetOriginsForHost(client, kTemp, kOriginA.host());
216 EXPECT_EQ(origins.size(), 1ul);
217 EXPECT_TRUE(origins.find(kOriginA) != origins.end());
218
219 AddFakeIndexedDB(kOriginB, 1000);
220 origins = GetOriginsForHost(client, kTemp, kOriginA.host());
221 EXPECT_EQ(origins.size(), 2ul);
222 EXPECT_TRUE(origins.find(kOriginA) != origins.end());
223 EXPECT_TRUE(origins.find(kOriginB) != origins.end());
224
225 EXPECT_TRUE(GetOriginsForHost(client, kPerm, kOriginA.host()).empty());
226 EXPECT_TRUE(GetOriginsForHost(client, kTemp, kOriginOther.host()).empty());
227 }
228
TEST_F(IndexedDBQuotaClientTest,GetOriginsForType)229 TEST_F(IndexedDBQuotaClientTest, GetOriginsForType) {
230 auto client = base::MakeRefCounted<IndexedDBQuotaClient>(idb_context());
231
232 EXPECT_TRUE(GetOriginsForType(client, kTemp).empty());
233 EXPECT_TRUE(GetOriginsForType(client, kPerm).empty());
234
235 AddFakeIndexedDB(kOriginA, 1000);
236 std::set<url::Origin> origins = GetOriginsForType(client, kTemp);
237 EXPECT_EQ(origins.size(), 1ul);
238 EXPECT_TRUE(origins.find(kOriginA) != origins.end());
239
240 EXPECT_TRUE(GetOriginsForType(client, kPerm).empty());
241 }
242
TEST_F(IndexedDBQuotaClientTest,DeleteOrigin)243 TEST_F(IndexedDBQuotaClientTest, DeleteOrigin) {
244 auto client = base::MakeRefCounted<IndexedDBQuotaClient>(idb_context());
245
246 AddFakeIndexedDB(kOriginA, 1000);
247 AddFakeIndexedDB(kOriginB, 50);
248 EXPECT_EQ(1000, GetOriginUsage(client, kOriginA, kTemp));
249 EXPECT_EQ(50, GetOriginUsage(client, kOriginB, kTemp));
250
251 blink::mojom::QuotaStatusCode delete_status =
252 DeleteOrigin(client, kOriginA, kTemp);
253 EXPECT_EQ(blink::mojom::QuotaStatusCode::kOk, delete_status);
254 EXPECT_EQ(0, GetOriginUsage(client, kOriginA, kTemp));
255 EXPECT_EQ(50, GetOriginUsage(client, kOriginB, kTemp));
256
257 // IndexedDB only supports temporary storage; requests to delete other types
258 // are no-ops, but should not fail.
259 delete_status = DeleteOrigin(client, kOriginA, kPerm);
260 EXPECT_EQ(blink::mojom::QuotaStatusCode::kOk, delete_status);
261
262 delete_status = DeleteOrigin(client, kOriginA, kSync);
263 EXPECT_EQ(blink::mojom::QuotaStatusCode::kOk, delete_status);
264 }
265
266 } // namespace content
267