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