Home | History | Annotate | Download | only in appcache
      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 
     13 namespace content {
     14 
     15 class 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 
     84 TEST_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 
     96 TEST_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 
    114 TEST_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 
    133 TEST_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 
    159 TEST_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 
    212 TEST_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 
    244 TEST_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 
    289 TEST_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 
    331 TEST_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 
    376 TEST_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 
    396 TEST_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 
    420 TEST_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 
    455 TEST_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 
    513 TEST_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 
    569 TEST_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