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 <map>
6#include <set>
7
8#include "base/bind.h"
9#include "base/message_loop/message_loop_proxy.h"
10#include "base/run_loop.h"
11#include "content/browser/appcache/appcache_quota_client.h"
12#include "content/browser/appcache/mock_appcache_service.h"
13#include "net/base/net_errors.h"
14#include "testing/gtest/include/gtest/gtest.h"
15
16namespace content {
17
18// Declared to shorten the line lengths.
19static const storage::StorageType kTemp = storage::kStorageTypeTemporary;
20static const storage::StorageType kPerm = storage::kStorageTypePersistent;
21
22// Base class for our test fixtures.
23class AppCacheQuotaClientTest : public testing::Test {
24 public:
25  const GURL kOriginA;
26  const GURL kOriginB;
27  const GURL kOriginOther;
28
29  AppCacheQuotaClientTest()
30      : kOriginA("http://host"),
31        kOriginB("http://host:8000"),
32        kOriginOther("http://other"),
33        usage_(0),
34        delete_status_(storage::kQuotaStatusUnknown),
35        num_get_origin_usage_completions_(0),
36        num_get_origins_completions_(0),
37        num_delete_origins_completions_(0),
38        weak_factory_(this) {}
39
40  int64 GetOriginUsage(storage::QuotaClient* client,
41                       const GURL& origin,
42                       storage::StorageType type) {
43    usage_ = -1;
44    AsyncGetOriginUsage(client, origin, type);
45    base::RunLoop().RunUntilIdle();
46    return usage_;
47  }
48
49  const std::set<GURL>& GetOriginsForType(storage::QuotaClient* client,
50                                          storage::StorageType type) {
51    origins_.clear();
52    AsyncGetOriginsForType(client, type);
53    base::RunLoop().RunUntilIdle();
54    return origins_;
55  }
56
57  const std::set<GURL>& GetOriginsForHost(storage::QuotaClient* client,
58                                          storage::StorageType type,
59                                          const std::string& host) {
60    origins_.clear();
61    AsyncGetOriginsForHost(client, type, host);
62    base::RunLoop().RunUntilIdle();
63    return origins_;
64  }
65
66  storage::QuotaStatusCode DeleteOriginData(storage::QuotaClient* client,
67                                            storage::StorageType type,
68                                            const GURL& origin) {
69    delete_status_ = storage::kQuotaStatusUnknown;
70    AsyncDeleteOriginData(client, type, origin);
71    base::RunLoop().RunUntilIdle();
72    return delete_status_;
73  }
74
75  void AsyncGetOriginUsage(storage::QuotaClient* client,
76                           const GURL& origin,
77                           storage::StorageType type) {
78    client->GetOriginUsage(
79        origin, type,
80        base::Bind(&AppCacheQuotaClientTest::OnGetOriginUsageComplete,
81                   weak_factory_.GetWeakPtr()));
82  }
83
84  void AsyncGetOriginsForType(storage::QuotaClient* client,
85                              storage::StorageType type) {
86    client->GetOriginsForType(
87        type,
88        base::Bind(&AppCacheQuotaClientTest::OnGetOriginsComplete,
89                   weak_factory_.GetWeakPtr()));
90  }
91
92  void AsyncGetOriginsForHost(storage::QuotaClient* client,
93                              storage::StorageType type,
94                              const std::string& host) {
95    client->GetOriginsForHost(
96        type, host,
97        base::Bind(&AppCacheQuotaClientTest::OnGetOriginsComplete,
98                   weak_factory_.GetWeakPtr()));
99  }
100
101  void AsyncDeleteOriginData(storage::QuotaClient* client,
102                             storage::StorageType type,
103                             const GURL& origin) {
104    client->DeleteOriginData(
105        origin, type,
106        base::Bind(&AppCacheQuotaClientTest::OnDeleteOriginDataComplete,
107                   weak_factory_.GetWeakPtr()));
108  }
109
110  void SetUsageMapEntry(const GURL& origin, int64 usage) {
111    mock_service_.storage()->usage_map_[origin] = usage;
112  }
113
114  AppCacheQuotaClient* CreateClient() {
115    return new AppCacheQuotaClient(&mock_service_);
116  }
117
118  void Call_NotifyAppCacheReady(AppCacheQuotaClient* client) {
119    client->NotifyAppCacheReady();
120  }
121
122  void Call_NotifyAppCacheDestroyed(AppCacheQuotaClient* client) {
123    client->NotifyAppCacheDestroyed();
124  }
125
126  void Call_OnQuotaManagerDestroyed(AppCacheQuotaClient* client) {
127    client->OnQuotaManagerDestroyed();
128  }
129
130 protected:
131  void OnGetOriginUsageComplete(int64 usage) {
132    ++num_get_origin_usage_completions_;
133    usage_ = usage;
134  }
135
136  void OnGetOriginsComplete(const std::set<GURL>& origins) {
137    ++num_get_origins_completions_;
138    origins_ = origins;
139  }
140
141  void OnDeleteOriginDataComplete(storage::QuotaStatusCode status) {
142    ++num_delete_origins_completions_;
143    delete_status_ = status;
144  }
145
146  base::MessageLoop message_loop_;
147  int64 usage_;
148  std::set<GURL> origins_;
149  storage::QuotaStatusCode delete_status_;
150  int num_get_origin_usage_completions_;
151  int num_get_origins_completions_;
152  int num_delete_origins_completions_;
153  MockAppCacheService mock_service_;
154  base::WeakPtrFactory<AppCacheQuotaClientTest> weak_factory_;
155};
156
157
158TEST_F(AppCacheQuotaClientTest, BasicCreateDestroy) {
159  AppCacheQuotaClient* client = CreateClient();
160  Call_NotifyAppCacheReady(client);
161  Call_OnQuotaManagerDestroyed(client);
162  Call_NotifyAppCacheDestroyed(client);
163}
164
165TEST_F(AppCacheQuotaClientTest, EmptyService) {
166  AppCacheQuotaClient* client = CreateClient();
167  Call_NotifyAppCacheReady(client);
168
169  EXPECT_EQ(0, GetOriginUsage(client, kOriginA, kTemp));
170  EXPECT_EQ(0, GetOriginUsage(client, kOriginA, kPerm));
171  EXPECT_TRUE(GetOriginsForType(client, kTemp).empty());
172  EXPECT_TRUE(GetOriginsForType(client, kPerm).empty());
173  EXPECT_TRUE(GetOriginsForHost(client, kTemp, kOriginA.host()).empty());
174  EXPECT_TRUE(GetOriginsForHost(client, kPerm, kOriginA.host()).empty());
175  EXPECT_EQ(storage::kQuotaStatusOk, DeleteOriginData(client, kTemp, kOriginA));
176  EXPECT_EQ(storage::kQuotaStatusOk, DeleteOriginData(client, kPerm, kOriginA));
177
178  Call_NotifyAppCacheDestroyed(client);
179  Call_OnQuotaManagerDestroyed(client);
180}
181
182TEST_F(AppCacheQuotaClientTest, NoService) {
183  AppCacheQuotaClient* client = CreateClient();
184  Call_NotifyAppCacheReady(client);
185  Call_NotifyAppCacheDestroyed(client);
186
187  EXPECT_EQ(0, GetOriginUsage(client, kOriginA, kTemp));
188  EXPECT_EQ(0, GetOriginUsage(client, kOriginA, kPerm));
189  EXPECT_TRUE(GetOriginsForType(client, kTemp).empty());
190  EXPECT_TRUE(GetOriginsForType(client, kPerm).empty());
191  EXPECT_TRUE(GetOriginsForHost(client, kTemp, kOriginA.host()).empty());
192  EXPECT_TRUE(GetOriginsForHost(client, kPerm, kOriginA.host()).empty());
193  EXPECT_EQ(storage::kQuotaErrorAbort,
194            DeleteOriginData(client, kTemp, kOriginA));
195  EXPECT_EQ(storage::kQuotaErrorAbort,
196            DeleteOriginData(client, kPerm, kOriginA));
197
198  Call_OnQuotaManagerDestroyed(client);
199}
200
201TEST_F(AppCacheQuotaClientTest, GetOriginUsage) {
202  AppCacheQuotaClient* client = CreateClient();
203  Call_NotifyAppCacheReady(client);
204
205  SetUsageMapEntry(kOriginA, 1000);
206  EXPECT_EQ(1000, GetOriginUsage(client, kOriginA, kTemp));
207  EXPECT_EQ(0, GetOriginUsage(client, kOriginA, kPerm));
208
209  Call_NotifyAppCacheDestroyed(client);
210  Call_OnQuotaManagerDestroyed(client);
211}
212
213TEST_F(AppCacheQuotaClientTest, GetOriginsForHost) {
214  AppCacheQuotaClient* client = CreateClient();
215  Call_NotifyAppCacheReady(client);
216
217  EXPECT_EQ(kOriginA.host(), kOriginB.host());
218  EXPECT_NE(kOriginA.host(), kOriginOther.host());
219
220  std::set<GURL> origins = GetOriginsForHost(client, kTemp, kOriginA.host());
221  EXPECT_TRUE(origins.empty());
222
223  SetUsageMapEntry(kOriginA, 1000);
224  SetUsageMapEntry(kOriginB, 10);
225  SetUsageMapEntry(kOriginOther, 500);
226
227  origins = GetOriginsForHost(client, kTemp, kOriginA.host());
228  EXPECT_EQ(2ul, origins.size());
229  EXPECT_TRUE(origins.find(kOriginA) != origins.end());
230  EXPECT_TRUE(origins.find(kOriginB) != origins.end());
231
232  origins = GetOriginsForHost(client, kTemp, kOriginOther.host());
233  EXPECT_EQ(1ul, origins.size());
234  EXPECT_TRUE(origins.find(kOriginOther) != origins.end());
235
236  origins = GetOriginsForHost(client, kPerm, kOriginA.host());
237  EXPECT_TRUE(origins.empty());
238
239  Call_NotifyAppCacheDestroyed(client);
240  Call_OnQuotaManagerDestroyed(client);
241}
242
243TEST_F(AppCacheQuotaClientTest, GetOriginsForType) {
244  AppCacheQuotaClient* client = CreateClient();
245  Call_NotifyAppCacheReady(client);
246
247  EXPECT_TRUE(GetOriginsForType(client, kTemp).empty());
248  EXPECT_TRUE(GetOriginsForType(client, kPerm).empty());
249
250  SetUsageMapEntry(kOriginA, 1000);
251  SetUsageMapEntry(kOriginB, 10);
252
253  std::set<GURL> origins = GetOriginsForType(client, kTemp);
254  EXPECT_EQ(2ul, origins.size());
255  EXPECT_TRUE(origins.find(kOriginA) != origins.end());
256  EXPECT_TRUE(origins.find(kOriginB) != origins.end());
257
258  EXPECT_TRUE(GetOriginsForType(client, kPerm).empty());
259
260  Call_NotifyAppCacheDestroyed(client);
261  Call_OnQuotaManagerDestroyed(client);
262}
263
264TEST_F(AppCacheQuotaClientTest, DeleteOriginData) {
265  AppCacheQuotaClient* client = CreateClient();
266  Call_NotifyAppCacheReady(client);
267
268  // Perm deletions are short circuited in the Client and
269  // should not reach the AppCacheServiceImpl.
270  EXPECT_EQ(storage::kQuotaStatusOk, DeleteOriginData(client, kPerm, kOriginA));
271  EXPECT_EQ(0, mock_service_.delete_called_count());
272
273  EXPECT_EQ(storage::kQuotaStatusOk, DeleteOriginData(client, kTemp, kOriginA));
274  EXPECT_EQ(1, mock_service_.delete_called_count());
275
276  mock_service_.set_mock_delete_appcaches_for_origin_result(
277      net::ERR_ABORTED);
278  EXPECT_EQ(storage::kQuotaErrorAbort,
279            DeleteOriginData(client, kTemp, kOriginA));
280  EXPECT_EQ(2, mock_service_.delete_called_count());
281
282  Call_OnQuotaManagerDestroyed(client);
283  Call_NotifyAppCacheDestroyed(client);
284}
285
286TEST_F(AppCacheQuotaClientTest, PendingRequests) {
287  AppCacheQuotaClient* client = CreateClient();
288
289  SetUsageMapEntry(kOriginA, 1000);
290  SetUsageMapEntry(kOriginB, 10);
291  SetUsageMapEntry(kOriginOther, 500);
292
293  // Queue up some reqeusts.
294  AsyncGetOriginUsage(client, kOriginA, kPerm);
295  AsyncGetOriginUsage(client, kOriginB, kTemp);
296  AsyncGetOriginsForType(client, kPerm);
297  AsyncGetOriginsForType(client, kTemp);
298  AsyncGetOriginsForHost(client, kTemp, kOriginA.host());
299  AsyncGetOriginsForHost(client, kTemp, kOriginOther.host());
300  AsyncDeleteOriginData(client, kTemp, kOriginA);
301  AsyncDeleteOriginData(client, kPerm, kOriginA);
302  AsyncDeleteOriginData(client, kTemp, kOriginB);
303
304  EXPECT_EQ(0, num_get_origin_usage_completions_);
305  EXPECT_EQ(0, num_get_origins_completions_);
306  EXPECT_EQ(0, num_delete_origins_completions_);
307  base::RunLoop().RunUntilIdle();
308  EXPECT_EQ(0, num_get_origin_usage_completions_);
309  EXPECT_EQ(0, num_get_origins_completions_);
310  EXPECT_EQ(0, num_delete_origins_completions_);
311
312  // Pending requests should get serviced when the appcache is ready.
313  Call_NotifyAppCacheReady(client);
314  EXPECT_EQ(2, num_get_origin_usage_completions_);
315  EXPECT_EQ(4, num_get_origins_completions_);
316  EXPECT_EQ(0, num_delete_origins_completions_);
317  base::RunLoop().RunUntilIdle();
318  EXPECT_EQ(3, num_delete_origins_completions_);  // deletes are really async
319
320  // They should be serviced in order requested.
321  EXPECT_EQ(10, usage_);
322  EXPECT_EQ(1ul, origins_.size());
323  EXPECT_TRUE(origins_.find(kOriginOther) != origins_.end());
324
325  Call_NotifyAppCacheDestroyed(client);
326  Call_OnQuotaManagerDestroyed(client);
327}
328
329TEST_F(AppCacheQuotaClientTest, DestroyServiceWithPending) {
330  AppCacheQuotaClient* client = CreateClient();
331
332  SetUsageMapEntry(kOriginA, 1000);
333  SetUsageMapEntry(kOriginB, 10);
334  SetUsageMapEntry(kOriginOther, 500);
335
336  // Queue up some reqeusts prior to being ready.
337  AsyncGetOriginUsage(client, kOriginA, kPerm);
338  AsyncGetOriginUsage(client, kOriginB, kTemp);
339  AsyncGetOriginsForType(client, kPerm);
340  AsyncGetOriginsForType(client, kTemp);
341  AsyncGetOriginsForHost(client, kTemp, kOriginA.host());
342  AsyncGetOriginsForHost(client, kTemp, kOriginOther.host());
343  AsyncDeleteOriginData(client, kTemp, kOriginA);
344  AsyncDeleteOriginData(client, kPerm, kOriginA);
345  AsyncDeleteOriginData(client, kTemp, kOriginB);
346  base::RunLoop().RunUntilIdle();
347  EXPECT_EQ(0, num_get_origin_usage_completions_);
348  EXPECT_EQ(0, num_get_origins_completions_);
349  EXPECT_EQ(0, num_delete_origins_completions_);
350
351  // Kill the service.
352  Call_NotifyAppCacheDestroyed(client);
353
354  // All should have been aborted and called completion.
355  EXPECT_EQ(2, num_get_origin_usage_completions_);
356  EXPECT_EQ(4, num_get_origins_completions_);
357  EXPECT_EQ(3, num_delete_origins_completions_);
358  EXPECT_EQ(0, usage_);
359  EXPECT_TRUE(origins_.empty());
360  EXPECT_EQ(storage::kQuotaErrorAbort, delete_status_);
361
362  Call_OnQuotaManagerDestroyed(client);
363}
364
365TEST_F(AppCacheQuotaClientTest, DestroyQuotaManagerWithPending) {
366  AppCacheQuotaClient* client = CreateClient();
367
368  SetUsageMapEntry(kOriginA, 1000);
369  SetUsageMapEntry(kOriginB, 10);
370  SetUsageMapEntry(kOriginOther, 500);
371
372  // Queue up some reqeusts prior to being ready.
373  AsyncGetOriginUsage(client, kOriginA, kPerm);
374  AsyncGetOriginUsage(client, kOriginB, kTemp);
375  AsyncGetOriginsForType(client, kPerm);
376  AsyncGetOriginsForType(client, kTemp);
377  AsyncGetOriginsForHost(client, kTemp, kOriginA.host());
378  AsyncGetOriginsForHost(client, kTemp, kOriginOther.host());
379  AsyncDeleteOriginData(client, kTemp, kOriginA);
380  AsyncDeleteOriginData(client, kPerm, kOriginA);
381  AsyncDeleteOriginData(client, kTemp, kOriginB);
382  base::RunLoop().RunUntilIdle();
383  EXPECT_EQ(0, num_get_origin_usage_completions_);
384  EXPECT_EQ(0, num_get_origins_completions_);
385  EXPECT_EQ(0, num_delete_origins_completions_);
386
387  // Kill the quota manager.
388  Call_OnQuotaManagerDestroyed(client);
389  Call_NotifyAppCacheReady(client);
390
391  // Callbacks should be deleted and not called.
392  base::RunLoop().RunUntilIdle();
393  EXPECT_EQ(0, num_get_origin_usage_completions_);
394  EXPECT_EQ(0, num_get_origins_completions_);
395  EXPECT_EQ(0, num_delete_origins_completions_);
396
397  Call_NotifyAppCacheDestroyed(client);
398}
399
400TEST_F(AppCacheQuotaClientTest, DestroyWithDeleteInProgress) {
401  AppCacheQuotaClient* client = CreateClient();
402  Call_NotifyAppCacheReady(client);
403
404  // Start an async delete.
405  AsyncDeleteOriginData(client, kTemp, kOriginB);
406  EXPECT_EQ(0, num_delete_origins_completions_);
407
408  // Kill the service.
409  Call_NotifyAppCacheDestroyed(client);
410
411  // Should have been aborted.
412  EXPECT_EQ(1, num_delete_origins_completions_);
413  EXPECT_EQ(storage::kQuotaErrorAbort, delete_status_);
414
415  // A real completion callback from the service should
416  // be dropped if it comes in after NotifyAppCacheDestroyed.
417  base::RunLoop().RunUntilIdle();
418  EXPECT_EQ(1, num_delete_origins_completions_);
419  EXPECT_EQ(storage::kQuotaErrorAbort, delete_status_);
420
421  Call_OnQuotaManagerDestroyed(client);
422}
423
424}  // namespace content
425