1// Copyright 2014 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 "base/bind.h"
6#include "base/run_loop.h"
7#include "content/public/test/mock_special_storage_policy.h"
8#include "net/base/net_util.h"
9#include "storage/browser/quota/usage_tracker.h"
10#include "testing/gtest/include/gtest/gtest.h"
11
12using storage::kQuotaStatusOk;
13using storage::kStorageTypeTemporary;
14using storage::QuotaClient;
15using storage::QuotaClientList;
16using storage::SpecialStoragePolicy;
17using storage::StorageType;
18using storage::UsageTracker;
19
20namespace content {
21
22namespace {
23
24void DidGetGlobalUsage(bool* done,
25                       int64* usage_out,
26                       int64* unlimited_usage_out,
27                       int64 usage,
28                       int64 unlimited_usage) {
29  EXPECT_FALSE(*done);
30  *done = true;
31  *usage_out = usage;
32  *unlimited_usage_out = unlimited_usage;
33}
34
35void DidGetUsage(bool* done,
36                 int64* usage_out,
37                 int64 usage) {
38  EXPECT_FALSE(*done);
39  *done = true;
40  *usage_out = usage;
41}
42
43}  // namespace
44
45class MockQuotaClient : public QuotaClient {
46 public:
47  MockQuotaClient() {}
48  virtual ~MockQuotaClient() {}
49
50  virtual ID id() const OVERRIDE {
51    return kFileSystem;
52  }
53
54  virtual void OnQuotaManagerDestroyed() OVERRIDE {}
55
56  virtual void GetOriginUsage(const GURL& origin,
57                              StorageType type,
58                              const GetUsageCallback& callback) OVERRIDE {
59    EXPECT_EQ(kStorageTypeTemporary, type);
60    int64 usage = GetUsage(origin);
61    base::MessageLoop::current()->PostTask(FROM_HERE,
62                                           base::Bind(callback, usage));
63  }
64
65  virtual void GetOriginsForType(StorageType type,
66                                 const GetOriginsCallback& callback) OVERRIDE {
67    EXPECT_EQ(kStorageTypeTemporary, type);
68    std::set<GURL> origins;
69    for (UsageMap::const_iterator itr = usage_map_.begin();
70         itr != usage_map_.end(); ++itr) {
71      origins.insert(itr->first);
72    }
73    base::MessageLoop::current()->PostTask(FROM_HERE,
74                                           base::Bind(callback, origins));
75  }
76
77  virtual void GetOriginsForHost(StorageType type,
78                                 const std::string& host,
79                                 const GetOriginsCallback& callback) OVERRIDE {
80    EXPECT_EQ(kStorageTypeTemporary, type);
81    std::set<GURL> origins;
82    for (UsageMap::const_iterator itr = usage_map_.begin();
83         itr != usage_map_.end(); ++itr) {
84      if (net::GetHostOrSpecFromURL(itr->first) == host)
85        origins.insert(itr->first);
86    }
87    base::MessageLoop::current()->PostTask(FROM_HERE,
88                                           base::Bind(callback, origins));
89  }
90
91  virtual void DeleteOriginData(const GURL& origin,
92                                StorageType type,
93                                const DeletionCallback& callback) OVERRIDE {
94    EXPECT_EQ(kStorageTypeTemporary, type);
95    usage_map_.erase(origin);
96    base::MessageLoop::current()->PostTask(
97        FROM_HERE, base::Bind(callback, kQuotaStatusOk));
98  }
99
100  virtual bool DoesSupport(storage::StorageType type) const OVERRIDE {
101    return type == storage::kStorageTypeTemporary;
102  }
103
104  int64 GetUsage(const GURL& origin) {
105    UsageMap::const_iterator found = usage_map_.find(origin);
106    if (found == usage_map_.end())
107      return 0;
108    return found->second;
109  }
110
111  void SetUsage(const GURL& origin, int64 usage) {
112    usage_map_[origin] = usage;
113  }
114
115  int64 UpdateUsage(const GURL& origin, int64 delta) {
116    return usage_map_[origin] += delta;
117  }
118
119 private:
120  typedef std::map<GURL, int64> UsageMap;
121
122  UsageMap usage_map_;
123
124  DISALLOW_COPY_AND_ASSIGN(MockQuotaClient);
125};
126
127class UsageTrackerTest : public testing::Test {
128 public:
129  UsageTrackerTest()
130      : storage_policy_(new MockSpecialStoragePolicy()),
131        usage_tracker_(GetUsageTrackerList(), kStorageTypeTemporary,
132                       storage_policy_.get(), NULL) {
133  }
134
135  virtual ~UsageTrackerTest() {}
136
137  UsageTracker* usage_tracker() {
138    return &usage_tracker_;
139  }
140
141  void UpdateUsage(const GURL& origin, int64 delta) {
142    quota_client_.UpdateUsage(origin, delta);
143    usage_tracker_.UpdateUsageCache(quota_client_.id(), origin, delta);
144    base::RunLoop().RunUntilIdle();
145  }
146
147  void UpdateUsageWithoutNotification(const GURL& origin, int64 delta) {
148    quota_client_.UpdateUsage(origin, delta);
149  }
150
151  void GetGlobalLimitedUsage(int64* limited_usage) {
152    bool done = false;
153    usage_tracker_.GetGlobalLimitedUsage(base::Bind(
154        &DidGetUsage, &done, limited_usage));
155    base::RunLoop().RunUntilIdle();
156
157    EXPECT_TRUE(done);
158  }
159
160  void GetGlobalUsage(int64* usage, int64* unlimited_usage) {
161    bool done = false;
162    usage_tracker_.GetGlobalUsage(base::Bind(
163        &DidGetGlobalUsage,
164        &done, usage, unlimited_usage));
165    base::RunLoop().RunUntilIdle();
166
167    EXPECT_TRUE(done);
168  }
169
170  void GetHostUsage(const std::string& host, int64* usage) {
171    bool done = false;
172    usage_tracker_.GetHostUsage(host, base::Bind(&DidGetUsage, &done, usage));
173    base::RunLoop().RunUntilIdle();
174
175    EXPECT_TRUE(done);
176  }
177
178  void GrantUnlimitedStoragePolicy(const GURL& origin) {
179    if (!storage_policy_->IsStorageUnlimited(origin)) {
180      storage_policy_->AddUnlimited(origin);
181      storage_policy_->NotifyGranted(
182          origin, SpecialStoragePolicy::STORAGE_UNLIMITED);
183    }
184  }
185
186  void RevokeUnlimitedStoragePolicy(const GURL& origin) {
187    if (storage_policy_->IsStorageUnlimited(origin)) {
188      storage_policy_->RemoveUnlimited(origin);
189      storage_policy_->NotifyRevoked(
190          origin, SpecialStoragePolicy::STORAGE_UNLIMITED);
191    }
192  }
193
194  void SetUsageCacheEnabled(const GURL& origin, bool enabled) {
195    usage_tracker_.SetUsageCacheEnabled(
196        quota_client_.id(), origin, enabled);
197  }
198
199 private:
200  QuotaClientList GetUsageTrackerList() {
201    QuotaClientList client_list;
202    client_list.push_back(&quota_client_);
203    return client_list;
204  }
205
206  base::MessageLoop message_loop_;
207
208  scoped_refptr<MockSpecialStoragePolicy> storage_policy_;
209  MockQuotaClient quota_client_;
210  UsageTracker usage_tracker_;
211
212  DISALLOW_COPY_AND_ASSIGN(UsageTrackerTest);
213};
214
215TEST_F(UsageTrackerTest, GrantAndRevokeUnlimitedStorage) {
216  int64 usage = 0;
217  int64 unlimited_usage = 0;
218  int64 host_usage = 0;
219  GetGlobalUsage(&usage, &unlimited_usage);
220  EXPECT_EQ(0, usage);
221  EXPECT_EQ(0, unlimited_usage);
222
223  const GURL origin("http://example.com");
224  const std::string host(net::GetHostOrSpecFromURL(origin));
225
226  UpdateUsage(origin, 100);
227  GetGlobalUsage(&usage, &unlimited_usage);
228  GetHostUsage(host, &host_usage);
229  EXPECT_EQ(100, usage);
230  EXPECT_EQ(0, unlimited_usage);
231  EXPECT_EQ(100, host_usage);
232
233  GrantUnlimitedStoragePolicy(origin);
234  GetGlobalUsage(&usage, &unlimited_usage);
235  GetHostUsage(host, &host_usage);
236  EXPECT_EQ(100, usage);
237  EXPECT_EQ(100, unlimited_usage);
238  EXPECT_EQ(100, host_usage);
239
240  RevokeUnlimitedStoragePolicy(origin);
241  GetGlobalUsage(&usage, &unlimited_usage);
242  GetHostUsage(host, &host_usage);
243  EXPECT_EQ(100, usage);
244  EXPECT_EQ(0, unlimited_usage);
245  EXPECT_EQ(100, host_usage);
246}
247
248TEST_F(UsageTrackerTest, CacheDisabledClientTest) {
249  int64 usage = 0;
250  int64 unlimited_usage = 0;
251  int64 host_usage = 0;
252
253  const GURL origin("http://example.com");
254  const std::string host(net::GetHostOrSpecFromURL(origin));
255
256  UpdateUsage(origin, 100);
257  GetGlobalUsage(&usage, &unlimited_usage);
258  GetHostUsage(host, &host_usage);
259  EXPECT_EQ(100, usage);
260  EXPECT_EQ(0, unlimited_usage);
261  EXPECT_EQ(100, host_usage);
262
263  UpdateUsageWithoutNotification(origin, 100);
264  GetGlobalUsage(&usage, &unlimited_usage);
265  GetHostUsage(host, &host_usage);
266  EXPECT_EQ(100, usage);
267  EXPECT_EQ(0, unlimited_usage);
268  EXPECT_EQ(100, host_usage);
269
270  GrantUnlimitedStoragePolicy(origin);
271  UpdateUsageWithoutNotification(origin, 100);
272  SetUsageCacheEnabled(origin, false);
273  UpdateUsageWithoutNotification(origin, 100);
274
275  GetGlobalUsage(&usage, &unlimited_usage);
276  GetHostUsage(host, &host_usage);
277  EXPECT_EQ(400, usage);
278  EXPECT_EQ(400, unlimited_usage);
279  EXPECT_EQ(400, host_usage);
280
281  RevokeUnlimitedStoragePolicy(origin);
282  GetGlobalUsage(&usage, &unlimited_usage);
283  GetHostUsage(host, &host_usage);
284  EXPECT_EQ(400, usage);
285  EXPECT_EQ(0, unlimited_usage);
286  EXPECT_EQ(400, host_usage);
287
288  SetUsageCacheEnabled(origin, true);
289  UpdateUsage(origin, 100);
290
291  GetGlobalUsage(&usage, &unlimited_usage);
292  GetHostUsage(host, &host_usage);
293  EXPECT_EQ(500, usage);
294  EXPECT_EQ(0, unlimited_usage);
295  EXPECT_EQ(500, host_usage);
296}
297
298TEST_F(UsageTrackerTest, LimitedGlobalUsageTest) {
299  const GURL kNormal("http://normal");
300  const GURL kUnlimited("http://unlimited");
301  const GURL kNonCached("http://non_cached");
302  const GURL kNonCachedUnlimited("http://non_cached-unlimited");
303
304  GrantUnlimitedStoragePolicy(kUnlimited);
305  GrantUnlimitedStoragePolicy(kNonCachedUnlimited);
306
307  SetUsageCacheEnabled(kNonCached, false);
308  SetUsageCacheEnabled(kNonCachedUnlimited, false);
309
310  UpdateUsageWithoutNotification(kNormal, 1);
311  UpdateUsageWithoutNotification(kUnlimited, 2);
312  UpdateUsageWithoutNotification(kNonCached, 4);
313  UpdateUsageWithoutNotification(kNonCachedUnlimited, 8);
314
315  int64 limited_usage = 0;
316  int64 total_usage = 0;
317  int64 unlimited_usage = 0;
318
319  GetGlobalLimitedUsage(&limited_usage);
320  GetGlobalUsage(&total_usage, &unlimited_usage);
321  EXPECT_EQ(1 + 4, limited_usage);
322  EXPECT_EQ(1 + 2 + 4 + 8, total_usage);
323  EXPECT_EQ(2 + 8, unlimited_usage);
324
325  UpdateUsageWithoutNotification(kNonCached, 16 - 4);
326  UpdateUsageWithoutNotification(kNonCachedUnlimited, 32 - 8);
327
328  GetGlobalLimitedUsage(&limited_usage);
329  GetGlobalUsage(&total_usage, &unlimited_usage);
330  EXPECT_EQ(1 + 16, limited_usage);
331  EXPECT_EQ(1 + 2 + 16 + 32, total_usage);
332  EXPECT_EQ(2 + 32, unlimited_usage);
333}
334
335
336}  // namespace content
337