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/run_loop.h"
6#include "content/browser/appcache/appcache.h"
7#include "content/browser/appcache/appcache_group.h"
8#include "content/browser/appcache/appcache_response.h"
9#include "content/browser/appcache/appcache_storage.h"
10#include "content/browser/appcache/mock_appcache_service.h"
11#include "testing/gtest/include/gtest/gtest.h"
12
13namespace content {
14
15class MockAppCacheStorageTest : public testing::Test {
16 public:
17  class MockStorageDelegate : public AppCacheStorage::Delegate {
18   public:
19    explicit MockStorageDelegate()
20        : loaded_cache_id_(0), stored_group_success_(false),
21          obsoleted_success_(false), found_cache_id_(kAppCacheNoCacheId) {
22    }
23
24    virtual void OnCacheLoaded(AppCache* cache, int64 cache_id) OVERRIDE {
25      loaded_cache_ = cache;
26      loaded_cache_id_ = cache_id;
27    }
28
29    virtual void OnGroupLoaded(AppCacheGroup* group,
30                               const GURL& manifest_url) OVERRIDE {
31      loaded_group_ = group;
32      loaded_manifest_url_ = manifest_url;
33    }
34
35    virtual void OnGroupAndNewestCacheStored(
36        AppCacheGroup* group, AppCache* newest_cache, bool success,
37        bool would_exceed_quota) OVERRIDE {
38      stored_group_ = group;
39      stored_group_success_ = success;
40    }
41
42    virtual void OnGroupMadeObsolete(AppCacheGroup* group,
43                                     bool success,
44                                     int response_code) OVERRIDE {
45      obsoleted_group_ = group;
46      obsoleted_success_ = success;
47    }
48
49    virtual void OnMainResponseFound(const GURL& url,
50                                     const AppCacheEntry& entry,
51                                     const GURL& fallback_url,
52                                     const AppCacheEntry& fallback_entry,
53                                     int64 cache_id,
54                                     int64 group_id,
55                                     const GURL& manifest_url) OVERRIDE {
56      found_url_ = url;
57      found_entry_ = entry;
58      found_fallback_url_ = fallback_url;
59      found_fallback_entry_ = fallback_entry;
60      found_cache_id_ = cache_id;
61      found_manifest_url_ = manifest_url;
62    }
63
64    scoped_refptr<AppCache> loaded_cache_;
65    int64 loaded_cache_id_;
66    scoped_refptr<AppCacheGroup> loaded_group_;
67    GURL loaded_manifest_url_;
68    scoped_refptr<AppCacheGroup> stored_group_;
69    bool stored_group_success_;
70    scoped_refptr<AppCacheGroup> obsoleted_group_;
71    bool obsoleted_success_;
72    GURL found_url_;
73    AppCacheEntry found_entry_;
74    GURL found_fallback_url_;
75    AppCacheEntry found_fallback_entry_;
76    int64 found_cache_id_;
77    GURL found_manifest_url_;
78  };
79
80 private:
81  base::MessageLoop message_loop_;
82};
83
84TEST_F(MockAppCacheStorageTest, LoadCache_Miss) {
85  // Attempt to load a cache that doesn't exist. Should
86  // complete asyncly.
87  MockAppCacheService service;
88  MockStorageDelegate delegate;
89  service.storage()->LoadCache(111, &delegate);
90  EXPECT_NE(111, delegate.loaded_cache_id_);
91  base::RunLoop().RunUntilIdle();  // Do async task execution.
92  EXPECT_EQ(111, delegate.loaded_cache_id_);
93  EXPECT_FALSE(delegate.loaded_cache_.get());
94}
95
96TEST_F(MockAppCacheStorageTest, LoadCache_NearHit) {
97  // Attempt to load a cache that is currently in use
98  // and does not require loading from disk. This
99  // load should complete syncly.
100  MockAppCacheService service;
101
102  // Setup some preconditions. Make an 'unstored' cache for
103  // us to load. The ctor should put it in the working set.
104  int64 cache_id = service.storage()->NewCacheId();
105  scoped_refptr<AppCache> cache(new AppCache(service.storage(), cache_id));
106
107  // Conduct the test.
108  MockStorageDelegate delegate;
109  service.storage()->LoadCache(cache_id, &delegate);
110  EXPECT_EQ(cache_id, delegate.loaded_cache_id_);
111  EXPECT_EQ(cache.get(), delegate.loaded_cache_.get());
112}
113
114TEST_F(MockAppCacheStorageTest, CreateGroup) {
115  // Attempt to load/create a group that doesn't exist.
116  // Should complete asyncly.
117  MockAppCacheService service;
118  MockAppCacheStorage* storage =
119      reinterpret_cast<MockAppCacheStorage*>(service.storage());
120  MockStorageDelegate delegate;
121  GURL manifest_url("http://blah/");
122  service.storage()->LoadOrCreateGroup(manifest_url, &delegate);
123  EXPECT_NE(manifest_url, delegate.loaded_manifest_url_);
124  EXPECT_FALSE(delegate.loaded_group_.get());
125  base::RunLoop().RunUntilIdle();  // Do async task execution.
126  EXPECT_EQ(manifest_url, delegate.loaded_manifest_url_);
127  EXPECT_TRUE(delegate.loaded_group_.get());
128  EXPECT_TRUE(delegate.loaded_group_->HasOneRef());
129  EXPECT_FALSE(delegate.loaded_group_->newest_complete_cache());
130  EXPECT_TRUE(storage->stored_groups_.empty());
131}
132
133TEST_F(MockAppCacheStorageTest, LoadGroup_NearHit) {
134  // Attempt to load a group that is currently in use
135  // and does not require loading from disk. This
136  // load should complete syncly.
137  MockAppCacheService service;
138  MockStorageDelegate delegate;
139
140  // Setup some preconditions. Create a group that appears
141  // to be "unstored" and "currently in use".
142  GURL manifest_url("http://blah/");
143  service.storage()->LoadOrCreateGroup(manifest_url, &delegate);
144  base::RunLoop().RunUntilIdle();  // Do async task execution.
145  EXPECT_EQ(manifest_url, delegate.loaded_manifest_url_);
146  EXPECT_TRUE(delegate.loaded_group_.get());
147
148  // Reset our delegate, and take a reference to the new group.
149  scoped_refptr<AppCacheGroup> group;
150  group.swap(delegate.loaded_group_);
151  delegate.loaded_manifest_url_ = GURL();
152
153  // Conduct the test.
154  service.storage()->LoadOrCreateGroup(manifest_url, &delegate);
155  EXPECT_EQ(manifest_url, delegate.loaded_manifest_url_);
156  EXPECT_EQ(group.get(), delegate.loaded_group_.get());
157}
158
159TEST_F(MockAppCacheStorageTest, LoadGroupAndCache_FarHit) {
160  // Attempt to load a cache that is not currently in use
161  // and does require loading from disk. This
162  // load should complete asyncly.
163  MockAppCacheService service;
164  MockAppCacheStorage* storage =
165      reinterpret_cast<MockAppCacheStorage*>(service.storage());
166
167  // Setup some preconditions. Create a group and newest cache that
168  // appears to be "stored" and "not currently in use".
169  GURL manifest_url("http://blah/");
170  scoped_refptr<AppCacheGroup> group(
171      new AppCacheGroup(service.storage(), manifest_url, 111));
172  int64 cache_id = storage->NewCacheId();
173  scoped_refptr<AppCache> cache(new AppCache(service.storage(), cache_id));
174  cache->set_complete(true);
175  group->AddCache(cache.get());
176  storage->AddStoredGroup(group.get());
177  storage->AddStoredCache(cache.get());
178
179  // Drop the references from above so the only refs to these
180  // objects are from within the storage class. This is to make
181  // these objects appear as "not currently in use".
182  AppCache* cache_ptr = cache.get();
183  AppCacheGroup* group_ptr = group.get();
184  cache = NULL;
185  group = NULL;
186
187  // Setup a delegate to receive completion callbacks.
188  MockStorageDelegate delegate;
189
190  // Conduct the cache load test.
191  EXPECT_NE(cache_id, delegate.loaded_cache_id_);
192  EXPECT_NE(cache_ptr, delegate.loaded_cache_.get());
193  storage->LoadCache(cache_id, &delegate);
194  EXPECT_NE(cache_id, delegate.loaded_cache_id_);
195  EXPECT_NE(cache_ptr, delegate.loaded_cache_.get());
196  base::RunLoop().RunUntilIdle();  // Do async task execution.
197  EXPECT_EQ(cache_id, delegate.loaded_cache_id_);
198  EXPECT_EQ(cache_ptr, delegate.loaded_cache_.get());
199  delegate.loaded_cache_ = NULL;
200
201  // Conduct the group load test.
202  EXPECT_NE(manifest_url, delegate.loaded_manifest_url_);
203  EXPECT_FALSE(delegate.loaded_group_.get());
204  storage->LoadOrCreateGroup(manifest_url, &delegate);
205  EXPECT_NE(manifest_url, delegate.loaded_manifest_url_);
206  EXPECT_FALSE(delegate.loaded_group_.get());
207  base::RunLoop().RunUntilIdle();  // Do async task execution.
208  EXPECT_EQ(manifest_url, delegate.loaded_manifest_url_);
209  EXPECT_EQ(group_ptr, delegate.loaded_group_.get());
210}
211
212TEST_F(MockAppCacheStorageTest, StoreNewGroup) {
213  // Store a group and its newest cache. Should complete asyncly.
214  MockAppCacheService service;
215  MockAppCacheStorage* storage =
216      reinterpret_cast<MockAppCacheStorage*>(service.storage());
217
218  // Setup some preconditions. Create a group and newest cache that
219  // appears to be "unstored".
220  GURL manifest_url("http://blah/");
221  scoped_refptr<AppCacheGroup> group(
222      new AppCacheGroup(service.storage(), manifest_url, 111));
223  int64 cache_id = storage->NewCacheId();
224  scoped_refptr<AppCache> cache(new AppCache(service.storage(), cache_id));
225  // Hold a ref to the cache simulate the UpdateJob holding that ref,
226  // and hold a ref to the group to simulate the CacheHost holding that ref.
227
228  // Conduct the store test.
229  MockStorageDelegate delegate;
230  EXPECT_TRUE(storage->stored_caches_.empty());
231  EXPECT_TRUE(storage->stored_groups_.empty());
232  storage->StoreGroupAndNewestCache(group.get(), cache.get(), &delegate);
233  EXPECT_FALSE(delegate.stored_group_success_);
234  EXPECT_TRUE(storage->stored_caches_.empty());
235  EXPECT_TRUE(storage->stored_groups_.empty());
236  base::RunLoop().RunUntilIdle();  // Do async task execution.
237  EXPECT_TRUE(delegate.stored_group_success_);
238  EXPECT_FALSE(storage->stored_caches_.empty());
239  EXPECT_FALSE(storage->stored_groups_.empty());
240  EXPECT_EQ(cache.get(), group->newest_complete_cache());
241  EXPECT_TRUE(cache->is_complete());
242}
243
244TEST_F(MockAppCacheStorageTest, StoreExistingGroup) {
245  // Store a group and its newest cache. Should complete asyncly.
246  MockAppCacheService service;
247  MockAppCacheStorage* storage =
248      reinterpret_cast<MockAppCacheStorage*>(service.storage());
249
250  // Setup some preconditions. Create a group and old complete cache
251  // that appear to be "stored", and a newest unstored complete cache.
252  GURL manifest_url("http://blah/");
253  scoped_refptr<AppCacheGroup> group(
254      new AppCacheGroup(service.storage(), manifest_url, 111));
255  int64 old_cache_id = storage->NewCacheId();
256  scoped_refptr<AppCache> old_cache(
257      new AppCache(service.storage(), old_cache_id));
258  old_cache->set_complete(true);
259  group->AddCache(old_cache.get());
260  storage->AddStoredGroup(group.get());
261  storage->AddStoredCache(old_cache.get());
262  int64 new_cache_id = storage->NewCacheId();
263  scoped_refptr<AppCache> new_cache(
264      new AppCache(service.storage(), new_cache_id));
265  // Hold our refs to simulate the UpdateJob holding these refs.
266
267  // Conduct the test.
268  MockStorageDelegate delegate;
269  EXPECT_EQ(size_t(1), storage->stored_caches_.size());
270  EXPECT_EQ(size_t(1), storage->stored_groups_.size());
271  EXPECT_TRUE(storage->IsCacheStored(old_cache.get()));
272  EXPECT_FALSE(storage->IsCacheStored(new_cache.get()));
273  storage->StoreGroupAndNewestCache(group.get(), new_cache.get(), &delegate);
274  EXPECT_FALSE(delegate.stored_group_success_);
275  EXPECT_EQ(size_t(1), storage->stored_caches_.size());
276  EXPECT_EQ(size_t(1), storage->stored_groups_.size());
277  EXPECT_TRUE(storage->IsCacheStored(old_cache.get()));
278  EXPECT_FALSE(storage->IsCacheStored(new_cache.get()));
279  base::RunLoop().RunUntilIdle();  // Do async task execution.
280  EXPECT_TRUE(delegate.stored_group_success_);
281  EXPECT_EQ(size_t(1), storage->stored_caches_.size());
282  EXPECT_EQ(size_t(1), storage->stored_groups_.size());
283  EXPECT_FALSE(storage->IsCacheStored(old_cache.get()));
284  EXPECT_TRUE(storage->IsCacheStored(new_cache.get()));
285  EXPECT_EQ(new_cache.get(), group->newest_complete_cache());
286  EXPECT_TRUE(new_cache->is_complete());
287}
288
289TEST_F(MockAppCacheStorageTest, StoreExistingGroupExistingCache) {
290  // Store a group with updates to its existing newest complete cache.
291  MockAppCacheService service;
292  MockAppCacheStorage* storage =
293      reinterpret_cast<MockAppCacheStorage*>(service.storage());
294
295  // Setup some preconditions. Create a group and a complete cache that
296  // appear to be "stored".
297  GURL manifest_url("http://blah");
298  scoped_refptr<AppCacheGroup> group(
299      new AppCacheGroup(service.storage(), manifest_url, 111));
300  int64 cache_id = storage->NewCacheId();
301  scoped_refptr<AppCache> cache(new AppCache(service.storage(), cache_id));
302  cache->set_complete(true);
303  group->AddCache(cache.get());
304  storage->AddStoredGroup(group.get());
305  storage->AddStoredCache(cache.get());
306  // Hold our refs to simulate the UpdateJob holding these refs.
307
308  // Change the group's newest cache.
309  EXPECT_EQ(cache.get(), group->newest_complete_cache());
310  GURL entry_url("http://blah/blah");
311  cache->AddEntry(entry_url, AppCacheEntry(AppCacheEntry::MASTER));
312
313  // Conduct the test.
314  MockStorageDelegate delegate;
315  EXPECT_EQ(size_t(1), storage->stored_caches_.size());
316  EXPECT_EQ(size_t(1), storage->stored_groups_.size());
317  EXPECT_TRUE(storage->IsCacheStored(cache.get()));
318  storage->StoreGroupAndNewestCache(group.get(), cache.get(), &delegate);
319  EXPECT_FALSE(delegate.stored_group_success_);
320  EXPECT_EQ(size_t(1), storage->stored_caches_.size());
321  EXPECT_EQ(size_t(1), storage->stored_groups_.size());
322  base::RunLoop().RunUntilIdle();  // Do async task execution.
323  EXPECT_TRUE(delegate.stored_group_success_);
324  EXPECT_EQ(size_t(1), storage->stored_caches_.size());
325  EXPECT_EQ(size_t(1), storage->stored_groups_.size());
326  EXPECT_TRUE(storage->IsCacheStored(cache.get()));
327  EXPECT_EQ(cache.get(), group->newest_complete_cache());
328  EXPECT_TRUE(cache->GetEntry(entry_url));
329}
330
331TEST_F(MockAppCacheStorageTest, MakeGroupObsolete) {
332  // Make a group obsolete, should complete asyncly.
333  MockAppCacheService service;
334  MockAppCacheStorage* storage =
335      reinterpret_cast<MockAppCacheStorage*>(service.storage());
336
337  // Setup some preconditions. Create a group and newest cache that
338  // appears to be "stored" and "currently in use".
339  GURL manifest_url("http://blah/");
340  scoped_refptr<AppCacheGroup> group(
341      new AppCacheGroup(service.storage(), manifest_url, 111));
342  int64 cache_id = storage->NewCacheId();
343  scoped_refptr<AppCache> cache(new AppCache(service.storage(), cache_id));
344  cache->set_complete(true);
345  group->AddCache(cache.get());
346  storage->AddStoredGroup(group.get());
347  storage->AddStoredCache(cache.get());
348  // Hold our refs to simulate the UpdateJob holding these refs.
349
350  // Conduct the test.
351  MockStorageDelegate delegate;
352  EXPECT_FALSE(group->is_obsolete());
353  EXPECT_EQ(size_t(1), storage->stored_caches_.size());
354  EXPECT_EQ(size_t(1), storage->stored_groups_.size());
355  EXPECT_FALSE(cache->HasOneRef());
356  EXPECT_FALSE(group->HasOneRef());
357  storage->MakeGroupObsolete(group.get(), &delegate, 0);
358  EXPECT_FALSE(group->is_obsolete());
359  EXPECT_EQ(size_t(1), storage->stored_caches_.size());
360  EXPECT_EQ(size_t(1), storage->stored_groups_.size());
361  EXPECT_FALSE(cache->HasOneRef());
362  EXPECT_FALSE(group->HasOneRef());
363  base::RunLoop().RunUntilIdle();  // Do async task execution.
364  EXPECT_TRUE(delegate.obsoleted_success_);
365  EXPECT_EQ(group.get(), delegate.obsoleted_group_.get());
366  EXPECT_TRUE(group->is_obsolete());
367  EXPECT_TRUE(storage->stored_caches_.empty());
368  EXPECT_TRUE(storage->stored_groups_.empty());
369  EXPECT_TRUE(cache->HasOneRef());
370  EXPECT_FALSE(group->HasOneRef());
371  delegate.obsoleted_group_ = NULL;
372  cache = NULL;
373  EXPECT_TRUE(group->HasOneRef());
374}
375
376TEST_F(MockAppCacheStorageTest, MarkEntryAsForeign) {
377  // Should complete syncly.
378  MockAppCacheService service;
379  MockAppCacheStorage* storage =
380      reinterpret_cast<MockAppCacheStorage*>(service.storage());
381
382  // Setup some preconditions. Create a cache with an entry.
383  GURL entry_url("http://blah/entry");
384  int64 cache_id = storage->NewCacheId();
385  scoped_refptr<AppCache> cache(new AppCache(service.storage(), cache_id));
386  cache->AddEntry(entry_url, AppCacheEntry(AppCacheEntry::EXPLICIT));
387
388  // Conduct the test.
389  MockStorageDelegate delegate;
390  EXPECT_FALSE(cache->GetEntry(entry_url)->IsForeign());
391  storage->MarkEntryAsForeign(entry_url, cache_id);
392  EXPECT_TRUE(cache->GetEntry(entry_url)->IsForeign());
393  EXPECT_TRUE(cache->GetEntry(entry_url)->IsExplicit());
394}
395
396TEST_F(MockAppCacheStorageTest, FindNoMainResponse) {
397  // Should complete asyncly.
398  MockAppCacheService service;
399  MockAppCacheStorage* storage =
400      reinterpret_cast<MockAppCacheStorage*>(service.storage());
401
402  // Conduct the test.
403  MockStorageDelegate delegate;
404  GURL url("http://blah/some_url");
405  EXPECT_NE(url, delegate.found_url_);
406  storage->FindResponseForMainRequest(url, GURL(), &delegate);
407  EXPECT_NE(url, delegate.found_url_);
408  base::RunLoop().RunUntilIdle();  // Do async task execution.
409  EXPECT_EQ(url, delegate.found_url_);
410  EXPECT_TRUE(delegate.found_manifest_url_.is_empty());
411  EXPECT_EQ(kAppCacheNoCacheId, delegate.found_cache_id_);
412  EXPECT_EQ(kAppCacheNoResponseId, delegate.found_entry_.response_id());
413  EXPECT_EQ(kAppCacheNoResponseId,
414            delegate.found_fallback_entry_.response_id());
415  EXPECT_TRUE(delegate.found_fallback_url_.is_empty());
416  EXPECT_EQ(0, delegate.found_entry_.types());
417  EXPECT_EQ(0, delegate.found_fallback_entry_.types());
418}
419
420TEST_F(MockAppCacheStorageTest, BasicFindMainResponse) {
421  // Should complete asyncly.
422  MockAppCacheService service;
423  MockAppCacheStorage* storage =
424      reinterpret_cast<MockAppCacheStorage*>(service.storage());
425
426  // Setup some preconditions. Create a complete cache with an entry.
427  const int64 kCacheId = storage->NewCacheId();
428  const GURL kEntryUrl("http://blah/entry");
429  const GURL kManifestUrl("http://blah/manifest");
430  const int64 kResponseId = 1;
431  scoped_refptr<AppCache> cache(new AppCache(service.storage(), kCacheId));
432  cache->AddEntry(
433      kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT, kResponseId));
434  cache->set_complete(true);
435  scoped_refptr<AppCacheGroup> group(
436      new AppCacheGroup(service.storage(), kManifestUrl, 111));
437  group->AddCache(cache.get());
438  storage->AddStoredGroup(group.get());
439  storage->AddStoredCache(cache.get());
440
441  // Conduct the test.
442  MockStorageDelegate delegate;
443  EXPECT_NE(kEntryUrl, delegate.found_url_);
444  storage->FindResponseForMainRequest(kEntryUrl, GURL(), &delegate);
445  EXPECT_NE(kEntryUrl, delegate.found_url_);
446  base::RunLoop().RunUntilIdle();  // Do async task execution.
447  EXPECT_EQ(kEntryUrl, delegate.found_url_);
448  EXPECT_EQ(kManifestUrl, delegate.found_manifest_url_);
449  EXPECT_EQ(kCacheId, delegate.found_cache_id_);
450  EXPECT_EQ(kResponseId, delegate.found_entry_.response_id());
451  EXPECT_TRUE(delegate.found_entry_.IsExplicit());
452  EXPECT_FALSE(delegate.found_fallback_entry_.has_response_id());
453}
454
455TEST_F(MockAppCacheStorageTest, BasicFindMainFallbackResponse) {
456  // Should complete asyncly.
457  MockAppCacheService service;
458  MockAppCacheStorage* storage =
459      reinterpret_cast<MockAppCacheStorage*>(service.storage());
460
461  // Setup some preconditions. Create a complete cache with a
462  // fallback namespace and entry.
463  const int64 kCacheId = storage->NewCacheId();
464  const GURL kFallbackEntryUrl1("http://blah/fallback_entry1");
465  const GURL kFallbackNamespaceUrl1("http://blah/fallback_namespace/");
466  const GURL kFallbackEntryUrl2("http://blah/fallback_entry2");
467  const GURL kFallbackNamespaceUrl2("http://blah/fallback_namespace/longer");
468  const GURL kManifestUrl("http://blah/manifest");
469  const int64 kResponseId1 = 1;
470  const int64 kResponseId2 = 2;
471
472  AppCacheManifest manifest;
473  manifest.fallback_namespaces.push_back(
474      AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE, kFallbackNamespaceUrl1,
475                kFallbackEntryUrl1, false));
476  manifest.fallback_namespaces.push_back(
477      AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE, kFallbackNamespaceUrl2,
478                kFallbackEntryUrl2, false));
479
480  scoped_refptr<AppCache> cache(new AppCache(service.storage(), kCacheId));
481  cache->InitializeWithManifest(&manifest);
482  cache->AddEntry(kFallbackEntryUrl1,
483                  AppCacheEntry(AppCacheEntry::FALLBACK, kResponseId1));
484  cache->AddEntry(kFallbackEntryUrl2,
485                  AppCacheEntry(AppCacheEntry::FALLBACK, kResponseId2));
486  cache->set_complete(true);
487
488  scoped_refptr<AppCacheGroup> group(
489      new AppCacheGroup(service.storage(), kManifestUrl, 111));
490  group->AddCache(cache.get());
491  storage->AddStoredGroup(group.get());
492  storage->AddStoredCache(cache.get());
493
494  // The test url is in both fallback namespace urls, but should match
495  // the longer of the two.
496  const GURL kTestUrl("http://blah/fallback_namespace/longer/test");
497
498  // Conduct the test.
499  MockStorageDelegate delegate;
500  EXPECT_NE(kTestUrl, delegate.found_url_);
501  storage->FindResponseForMainRequest(kTestUrl, GURL(), &delegate);
502  EXPECT_NE(kTestUrl, delegate.found_url_);
503  base::RunLoop().RunUntilIdle();  // Do async task execution.
504  EXPECT_EQ(kTestUrl, delegate.found_url_);
505  EXPECT_EQ(kManifestUrl, delegate.found_manifest_url_);
506  EXPECT_EQ(kCacheId, delegate.found_cache_id_);
507  EXPECT_FALSE(delegate.found_entry_.has_response_id());
508  EXPECT_EQ(kResponseId2, delegate.found_fallback_entry_.response_id());
509  EXPECT_EQ(kFallbackEntryUrl2, delegate.found_fallback_url_);
510  EXPECT_TRUE(delegate.found_fallback_entry_.IsFallback());
511}
512
513TEST_F(MockAppCacheStorageTest, FindMainResponseWithMultipleCandidates) {
514  // Should complete asyncly.
515  MockAppCacheService service;
516  MockAppCacheStorage* storage =
517      reinterpret_cast<MockAppCacheStorage*>(service.storage());
518
519  // Setup some preconditions. Create 2 complete caches with an entry
520  // for the same url.
521
522  const GURL kEntryUrl("http://blah/entry");
523  const int64 kCacheId1 = storage->NewCacheId();
524  const int64 kCacheId2 = storage->NewCacheId();
525  const GURL kManifestUrl1("http://blah/manifest1");
526  const GURL kManifestUrl2("http://blah/manifest2");
527  const int64 kResponseId1 = 1;
528  const int64 kResponseId2 = 2;
529
530  // The first cache.
531  scoped_refptr<AppCache> cache(new AppCache(service.storage(), kCacheId1));
532  cache->AddEntry(
533      kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT, kResponseId1));
534  cache->set_complete(true);
535  scoped_refptr<AppCacheGroup> group(
536      new AppCacheGroup(service.storage(), kManifestUrl1, 111));
537  group->AddCache(cache.get());
538  storage->AddStoredGroup(group.get());
539  storage->AddStoredCache(cache.get());
540  // Drop our references to cache1 so it appears as "not in use".
541  cache = NULL;
542  group = NULL;
543
544  // The second cache.
545  cache = new AppCache(service.storage(), kCacheId2);
546  cache->AddEntry(
547      kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT, kResponseId2));
548  cache->set_complete(true);
549  group = new AppCacheGroup(service.storage(), kManifestUrl2, 222);
550  group->AddCache(cache.get());
551  storage->AddStoredGroup(group.get());
552  storage->AddStoredCache(cache.get());
553
554  // Conduct the test, we should find the response from the second cache
555  // since it's "in use".
556  MockStorageDelegate delegate;
557  EXPECT_NE(kEntryUrl, delegate.found_url_);
558  storage->FindResponseForMainRequest(kEntryUrl, GURL(), &delegate);
559  EXPECT_NE(kEntryUrl, delegate.found_url_);
560  base::RunLoop().RunUntilIdle();  // Do async task execution.
561  EXPECT_EQ(kEntryUrl, delegate.found_url_);
562  EXPECT_EQ(kManifestUrl2, delegate.found_manifest_url_);
563  EXPECT_EQ(kCacheId2, delegate.found_cache_id_);
564  EXPECT_EQ(kResponseId2, delegate.found_entry_.response_id());
565  EXPECT_TRUE(delegate.found_entry_.IsExplicit());
566  EXPECT_FALSE(delegate.found_fallback_entry_.has_response_id());
567}
568
569TEST_F(MockAppCacheStorageTest, FindMainResponseExclusions) {
570  // Should complete asyncly.
571  MockAppCacheService service;
572  MockAppCacheStorage* storage =
573      reinterpret_cast<MockAppCacheStorage*>(service.storage());
574
575  // Setup some preconditions. Create a complete cache with a
576  // foreign entry and an online namespace.
577
578  const int64 kCacheId = storage->NewCacheId();
579  const GURL kEntryUrl("http://blah/entry");
580  const GURL kManifestUrl("http://blah/manifest");
581  const GURL kOnlineNamespaceUrl("http://blah/online_namespace");
582  const int64 kResponseId = 1;
583
584  AppCacheManifest manifest;
585  manifest.online_whitelist_namespaces.push_back(
586      AppCacheNamespace(APPCACHE_NETWORK_NAMESPACE, kOnlineNamespaceUrl,
587                GURL(), false));
588  scoped_refptr<AppCache> cache(new AppCache(service.storage(), kCacheId));
589  cache->InitializeWithManifest(&manifest);
590  cache->AddEntry(
591      kEntryUrl,
592      AppCacheEntry(AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN,
593                    kResponseId));
594  cache->set_complete(true);
595  scoped_refptr<AppCacheGroup> group(
596      new AppCacheGroup(service.storage(), kManifestUrl, 111));
597  group->AddCache(cache.get());
598  storage->AddStoredGroup(group.get());
599  storage->AddStoredCache(cache.get());
600
601  MockStorageDelegate delegate;
602
603  // We should not find anything for the foreign entry.
604  EXPECT_NE(kEntryUrl, delegate.found_url_);
605  storage->FindResponseForMainRequest(kEntryUrl, GURL(), &delegate);
606  EXPECT_NE(kEntryUrl, delegate.found_url_);
607  base::RunLoop().RunUntilIdle();  // Do async task execution.
608  EXPECT_EQ(kEntryUrl, delegate.found_url_);
609  EXPECT_TRUE(delegate.found_manifest_url_.is_empty());
610  EXPECT_EQ(kAppCacheNoCacheId, delegate.found_cache_id_);
611  EXPECT_EQ(kAppCacheNoResponseId, delegate.found_entry_.response_id());
612  EXPECT_EQ(kAppCacheNoResponseId,
613            delegate.found_fallback_entry_.response_id());
614  EXPECT_TRUE(delegate.found_fallback_url_.is_empty());
615  EXPECT_EQ(0, delegate.found_entry_.types());
616  EXPECT_EQ(0, delegate.found_fallback_entry_.types());
617
618  // We should not find anything for the online namespace.
619  EXPECT_NE(kOnlineNamespaceUrl, delegate.found_url_);
620  storage->FindResponseForMainRequest(kOnlineNamespaceUrl, GURL(), &delegate);
621  EXPECT_NE(kOnlineNamespaceUrl, delegate.found_url_);
622  base::RunLoop().RunUntilIdle();  // Do async task execution.
623  EXPECT_EQ(kOnlineNamespaceUrl, delegate.found_url_);
624  EXPECT_TRUE(delegate.found_manifest_url_.is_empty());
625  EXPECT_EQ(kAppCacheNoCacheId, delegate.found_cache_id_);
626  EXPECT_EQ(kAppCacheNoResponseId, delegate.found_entry_.response_id());
627  EXPECT_EQ(kAppCacheNoResponseId,
628            delegate.found_fallback_entry_.response_id());
629  EXPECT_TRUE(delegate.found_fallback_url_.is_empty());
630  EXPECT_EQ(0, delegate.found_entry_.types());
631  EXPECT_EQ(0, delegate.found_fallback_entry_.types());
632}
633
634}  // namespace content
635