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 <map>
6
7#include "base/bind.h"
8#include "base/files/file_path.h"
9#include "base/files/file_util.h"
10#include "base/files/scoped_temp_dir.h"
11#include "base/message_loop/message_loop.h"
12#include "base/test/test_simple_task_runner.h"
13#include "base/threading/thread.h"
14#include "content/browser/browser_thread_impl.h"
15#include "content/browser/indexed_db/indexed_db_context_impl.h"
16#include "content/browser/indexed_db/indexed_db_quota_client.h"
17#include "content/browser/quota/mock_quota_manager.h"
18#include "content/public/browser/storage_partition.h"
19#include "content/public/test/test_browser_context.h"
20#include "content/public/test/test_browser_thread_bundle.h"
21#include "storage/common/database/database_identifier.h"
22#include "testing/gtest/include/gtest/gtest.h"
23
24// Declared to shorten the line lengths.
25static const storage::StorageType kTemp = storage::kStorageTypeTemporary;
26static const storage::StorageType kPerm = storage::kStorageTypePersistent;
27
28namespace content {
29
30// Base class for our test fixtures.
31class IndexedDBQuotaClientTest : public testing::Test {
32 public:
33  const GURL kOriginA;
34  const GURL kOriginB;
35  const GURL kOriginOther;
36
37  IndexedDBQuotaClientTest()
38      : kOriginA("http://host"),
39        kOriginB("http://host:8000"),
40        kOriginOther("http://other"),
41        usage_(0),
42        task_runner_(new base::TestSimpleTaskRunner),
43        weak_factory_(this) {
44    browser_context_.reset(new TestBrowserContext());
45
46    scoped_refptr<storage::QuotaManager> quota_manager =
47        new MockQuotaManager(false /*in_memory*/,
48                             browser_context_->GetPath(),
49                             base::MessageLoop::current()->message_loop_proxy(),
50                             base::MessageLoop::current()->message_loop_proxy(),
51                             browser_context_->GetSpecialStoragePolicy());
52
53    idb_context_ =
54        new IndexedDBContextImpl(browser_context_->GetPath(),
55                                 browser_context_->GetSpecialStoragePolicy(),
56                                 quota_manager->proxy(),
57                                 task_runner_.get());
58    base::MessageLoop::current()->RunUntilIdle();
59    setup_temp_dir();
60  }
61
62  void FlushIndexedDBTaskRunner() { task_runner_->RunUntilIdle(); }
63
64  void setup_temp_dir() {
65    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
66    base::FilePath indexeddb_dir =
67        temp_dir_.path().Append(IndexedDBContextImpl::kIndexedDBDirectory);
68    ASSERT_TRUE(base::CreateDirectory(indexeddb_dir));
69    idb_context()->set_data_path_for_testing(indexeddb_dir);
70  }
71
72  virtual ~IndexedDBQuotaClientTest() {
73    FlushIndexedDBTaskRunner();
74    idb_context_ = NULL;
75    browser_context_.reset();
76    base::MessageLoop::current()->RunUntilIdle();
77  }
78
79  int64 GetOriginUsage(storage::QuotaClient* client,
80                       const GURL& origin,
81                       storage::StorageType type) {
82    usage_ = -1;
83    client->GetOriginUsage(
84        origin,
85        type,
86        base::Bind(&IndexedDBQuotaClientTest::OnGetOriginUsageComplete,
87                   weak_factory_.GetWeakPtr()));
88    FlushIndexedDBTaskRunner();
89    base::MessageLoop::current()->RunUntilIdle();
90    EXPECT_GT(usage_, -1);
91    return usage_;
92  }
93
94  const std::set<GURL>& GetOriginsForType(storage::QuotaClient* client,
95                                          storage::StorageType type) {
96    origins_.clear();
97    client->GetOriginsForType(
98        type,
99        base::Bind(&IndexedDBQuotaClientTest::OnGetOriginsComplete,
100                   weak_factory_.GetWeakPtr()));
101    FlushIndexedDBTaskRunner();
102    base::MessageLoop::current()->RunUntilIdle();
103    return origins_;
104  }
105
106  const std::set<GURL>& GetOriginsForHost(storage::QuotaClient* client,
107                                          storage::StorageType type,
108                                          const std::string& host) {
109    origins_.clear();
110    client->GetOriginsForHost(
111        type,
112        host,
113        base::Bind(&IndexedDBQuotaClientTest::OnGetOriginsComplete,
114                   weak_factory_.GetWeakPtr()));
115    FlushIndexedDBTaskRunner();
116    base::MessageLoop::current()->RunUntilIdle();
117    return origins_;
118  }
119
120  storage::QuotaStatusCode DeleteOrigin(storage::QuotaClient* client,
121                                        const GURL& origin_url) {
122    delete_status_ = storage::kQuotaStatusUnknown;
123    client->DeleteOriginData(
124        origin_url,
125        kTemp,
126        base::Bind(&IndexedDBQuotaClientTest::OnDeleteOriginComplete,
127                   weak_factory_.GetWeakPtr()));
128    FlushIndexedDBTaskRunner();
129    base::MessageLoop::current()->RunUntilIdle();
130    return delete_status_;
131  }
132
133  IndexedDBContextImpl* idb_context() { return idb_context_.get(); }
134
135  void SetFileSizeTo(const base::FilePath& path, int size) {
136    std::string junk(size, 'a');
137    ASSERT_EQ(size, base::WriteFile(path, junk.c_str(), size));
138  }
139
140  void AddFakeIndexedDB(const GURL& origin, int size) {
141    base::FilePath file_path_origin = idb_context()->GetFilePathForTesting(
142        storage::GetIdentifierFromOrigin(origin));
143    if (!base::CreateDirectory(file_path_origin)) {
144      LOG(ERROR) << "failed to base::CreateDirectory "
145                 << file_path_origin.value();
146    }
147    file_path_origin = file_path_origin.Append(FILE_PATH_LITERAL("fake_file"));
148    SetFileSizeTo(file_path_origin, size);
149    idb_context()->ResetCaches();
150  }
151
152 private:
153  void OnGetOriginUsageComplete(int64 usage) { usage_ = usage; }
154
155  void OnGetOriginsComplete(const std::set<GURL>& origins) {
156    origins_ = origins;
157  }
158
159  void OnDeleteOriginComplete(storage::QuotaStatusCode code) {
160    delete_status_ = code;
161  }
162
163  base::ScopedTempDir temp_dir_;
164  int64 usage_;
165  std::set<GURL> origins_;
166  scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
167  scoped_refptr<IndexedDBContextImpl> idb_context_;
168  content::TestBrowserThreadBundle thread_bundle_;
169  scoped_ptr<TestBrowserContext> browser_context_;
170  storage::QuotaStatusCode delete_status_;
171  base::WeakPtrFactory<IndexedDBQuotaClientTest> weak_factory_;
172
173  DISALLOW_COPY_AND_ASSIGN(IndexedDBQuotaClientTest);
174};
175
176TEST_F(IndexedDBQuotaClientTest, GetOriginUsage) {
177  IndexedDBQuotaClient client(idb_context());
178
179  AddFakeIndexedDB(kOriginA, 6);
180  AddFakeIndexedDB(kOriginB, 3);
181  EXPECT_EQ(6, GetOriginUsage(&client, kOriginA, kTemp));
182  EXPECT_EQ(0, GetOriginUsage(&client, kOriginA, kPerm));
183  EXPECT_EQ(3, GetOriginUsage(&client, kOriginB, kTemp));
184  EXPECT_EQ(0, GetOriginUsage(&client, kOriginB, kPerm));
185
186  AddFakeIndexedDB(kOriginA, 1000);
187  EXPECT_EQ(1000, GetOriginUsage(&client, kOriginA, kTemp));
188  EXPECT_EQ(0, GetOriginUsage(&client, kOriginA, kPerm));
189  EXPECT_EQ(3, GetOriginUsage(&client, kOriginB, kTemp));
190  EXPECT_EQ(0, GetOriginUsage(&client, kOriginB, kPerm));
191}
192
193TEST_F(IndexedDBQuotaClientTest, GetOriginsForHost) {
194  IndexedDBQuotaClient client(idb_context());
195
196  EXPECT_EQ(kOriginA.host(), kOriginB.host());
197  EXPECT_NE(kOriginA.host(), kOriginOther.host());
198
199  std::set<GURL> origins = GetOriginsForHost(&client, kTemp, kOriginA.host());
200  EXPECT_TRUE(origins.empty());
201
202  AddFakeIndexedDB(kOriginA, 1000);
203  origins = GetOriginsForHost(&client, kTemp, kOriginA.host());
204  EXPECT_EQ(origins.size(), 1ul);
205  EXPECT_TRUE(origins.find(kOriginA) != origins.end());
206
207  AddFakeIndexedDB(kOriginB, 1000);
208  origins = GetOriginsForHost(&client, kTemp, kOriginA.host());
209  EXPECT_EQ(origins.size(), 2ul);
210  EXPECT_TRUE(origins.find(kOriginA) != origins.end());
211  EXPECT_TRUE(origins.find(kOriginB) != origins.end());
212
213  EXPECT_TRUE(GetOriginsForHost(&client, kPerm, kOriginA.host()).empty());
214  EXPECT_TRUE(GetOriginsForHost(&client, kTemp, kOriginOther.host()).empty());
215}
216
217TEST_F(IndexedDBQuotaClientTest, GetOriginsForType) {
218  IndexedDBQuotaClient client(idb_context());
219
220  EXPECT_TRUE(GetOriginsForType(&client, kTemp).empty());
221  EXPECT_TRUE(GetOriginsForType(&client, kPerm).empty());
222
223  AddFakeIndexedDB(kOriginA, 1000);
224  std::set<GURL> origins = GetOriginsForType(&client, kTemp);
225  EXPECT_EQ(origins.size(), 1ul);
226  EXPECT_TRUE(origins.find(kOriginA) != origins.end());
227
228  EXPECT_TRUE(GetOriginsForType(&client, kPerm).empty());
229}
230
231TEST_F(IndexedDBQuotaClientTest, DeleteOrigin) {
232  IndexedDBQuotaClient client(idb_context());
233
234  AddFakeIndexedDB(kOriginA, 1000);
235  AddFakeIndexedDB(kOriginB, 50);
236  EXPECT_EQ(1000, GetOriginUsage(&client, kOriginA, kTemp));
237  EXPECT_EQ(50, GetOriginUsage(&client, kOriginB, kTemp));
238
239  storage::QuotaStatusCode delete_status = DeleteOrigin(&client, kOriginA);
240  EXPECT_EQ(storage::kQuotaStatusOk, delete_status);
241  EXPECT_EQ(0, GetOriginUsage(&client, kOriginA, kTemp));
242  EXPECT_EQ(50, GetOriginUsage(&client, kOriginB, kTemp));
243}
244
245}  // namespace content
246