|  | // Copyright 2014 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include <stddef.h> | 
|  | #include <stdint.h> | 
|  |  | 
|  | #include "base/run_loop.h" | 
|  | #include "content/browser/appcache/appcache.h" | 
|  | #include "content/browser/appcache/appcache_group.h" | 
|  | #include "content/browser/appcache/appcache_response.h" | 
|  | #include "content/browser/appcache/appcache_storage.h" | 
|  | #include "content/browser/appcache/mock_appcache_service.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  |  | 
|  | namespace content { | 
|  |  | 
|  | class MockAppCacheStorageTest : public testing::Test { | 
|  | public: | 
|  | class MockStorageDelegate : public AppCacheStorage::Delegate { | 
|  | public: | 
|  | explicit MockStorageDelegate() | 
|  | : loaded_cache_id_(0), stored_group_success_(false), | 
|  | obsoleted_success_(false), found_cache_id_(kAppCacheNoCacheId) { | 
|  | } | 
|  |  | 
|  | void OnCacheLoaded(AppCache* cache, int64_t cache_id) override { | 
|  | loaded_cache_ = cache; | 
|  | loaded_cache_id_ = cache_id; | 
|  | } | 
|  |  | 
|  | void OnGroupLoaded(AppCacheGroup* group, | 
|  | const GURL& manifest_url) override { | 
|  | loaded_group_ = group; | 
|  | loaded_manifest_url_ = manifest_url; | 
|  | } | 
|  |  | 
|  | void OnGroupAndNewestCacheStored(AppCacheGroup* group, | 
|  | AppCache* newest_cache, | 
|  | bool success, | 
|  | bool would_exceed_quota) override { | 
|  | stored_group_ = group; | 
|  | stored_group_success_ = success; | 
|  | } | 
|  |  | 
|  | void OnGroupMadeObsolete(AppCacheGroup* group, | 
|  | bool success, | 
|  | int response_code) override { | 
|  | obsoleted_group_ = group; | 
|  | obsoleted_success_ = success; | 
|  | } | 
|  |  | 
|  | void OnMainResponseFound(const GURL& url, | 
|  | const AppCacheEntry& entry, | 
|  | const GURL& fallback_url, | 
|  | const AppCacheEntry& fallback_entry, | 
|  | int64_t cache_id, | 
|  | int64_t group_id, | 
|  | const GURL& manifest_url) override { | 
|  | found_url_ = url; | 
|  | found_entry_ = entry; | 
|  | found_fallback_url_ = fallback_url; | 
|  | found_fallback_entry_ = fallback_entry; | 
|  | found_cache_id_ = cache_id; | 
|  | found_manifest_url_ = manifest_url; | 
|  | } | 
|  |  | 
|  | scoped_refptr<AppCache> loaded_cache_; | 
|  | int64_t loaded_cache_id_; | 
|  | scoped_refptr<AppCacheGroup> loaded_group_; | 
|  | GURL loaded_manifest_url_; | 
|  | scoped_refptr<AppCacheGroup> stored_group_; | 
|  | bool stored_group_success_; | 
|  | scoped_refptr<AppCacheGroup> obsoleted_group_; | 
|  | bool obsoleted_success_; | 
|  | GURL found_url_; | 
|  | AppCacheEntry found_entry_; | 
|  | GURL found_fallback_url_; | 
|  | AppCacheEntry found_fallback_entry_; | 
|  | int64_t found_cache_id_; | 
|  | GURL found_manifest_url_; | 
|  | }; | 
|  |  | 
|  | private: | 
|  | base::MessageLoop message_loop_; | 
|  | }; | 
|  |  | 
|  | TEST_F(MockAppCacheStorageTest, LoadCache_Miss) { | 
|  | // Attempt to load a cache that doesn't exist. Should | 
|  | // complete asyncly. | 
|  | MockAppCacheService service; | 
|  | MockStorageDelegate delegate; | 
|  | service.storage()->LoadCache(111, &delegate); | 
|  | EXPECT_NE(111, delegate.loaded_cache_id_); | 
|  | base::RunLoop().RunUntilIdle();  // Do async task execution. | 
|  | EXPECT_EQ(111, delegate.loaded_cache_id_); | 
|  | EXPECT_FALSE(delegate.loaded_cache_.get()); | 
|  | } | 
|  |  | 
|  | TEST_F(MockAppCacheStorageTest, LoadCache_NearHit) { | 
|  | // Attempt to load a cache that is currently in use | 
|  | // and does not require loading from disk. This | 
|  | // load should complete syncly. | 
|  | MockAppCacheService service; | 
|  |  | 
|  | // Setup some preconditions. Make an 'unstored' cache for | 
|  | // us to load. The ctor should put it in the working set. | 
|  | int64_t cache_id = service.storage()->NewCacheId(); | 
|  | scoped_refptr<AppCache> cache(new AppCache(service.storage(), cache_id)); | 
|  |  | 
|  | // Conduct the test. | 
|  | MockStorageDelegate delegate; | 
|  | service.storage()->LoadCache(cache_id, &delegate); | 
|  | EXPECT_EQ(cache_id, delegate.loaded_cache_id_); | 
|  | EXPECT_EQ(cache.get(), delegate.loaded_cache_.get()); | 
|  | } | 
|  |  | 
|  | TEST_F(MockAppCacheStorageTest, CreateGroup) { | 
|  | // Attempt to load/create a group that doesn't exist. | 
|  | // Should complete asyncly. | 
|  | MockAppCacheService service; | 
|  | MockAppCacheStorage* storage = | 
|  | reinterpret_cast<MockAppCacheStorage*>(service.storage()); | 
|  | MockStorageDelegate delegate; | 
|  | GURL manifest_url("http://blah/"); | 
|  | service.storage()->LoadOrCreateGroup(manifest_url, &delegate); | 
|  | EXPECT_NE(manifest_url, delegate.loaded_manifest_url_); | 
|  | EXPECT_FALSE(delegate.loaded_group_.get()); | 
|  | base::RunLoop().RunUntilIdle();  // Do async task execution. | 
|  | EXPECT_EQ(manifest_url, delegate.loaded_manifest_url_); | 
|  | EXPECT_TRUE(delegate.loaded_group_.get()); | 
|  | EXPECT_TRUE(delegate.loaded_group_->HasOneRef()); | 
|  | EXPECT_FALSE(delegate.loaded_group_->newest_complete_cache()); | 
|  | EXPECT_TRUE(storage->stored_groups_.empty()); | 
|  | } | 
|  |  | 
|  | TEST_F(MockAppCacheStorageTest, LoadGroup_NearHit) { | 
|  | // Attempt to load a group that is currently in use | 
|  | // and does not require loading from disk. This | 
|  | // load should complete syncly. | 
|  | MockAppCacheService service; | 
|  | MockStorageDelegate delegate; | 
|  |  | 
|  | // Setup some preconditions. Create a group that appears | 
|  | // to be "unstored" and "currently in use". | 
|  | GURL manifest_url("http://blah/"); | 
|  | service.storage()->LoadOrCreateGroup(manifest_url, &delegate); | 
|  | base::RunLoop().RunUntilIdle();  // Do async task execution. | 
|  | EXPECT_EQ(manifest_url, delegate.loaded_manifest_url_); | 
|  | EXPECT_TRUE(delegate.loaded_group_.get()); | 
|  |  | 
|  | // Reset our delegate, and take a reference to the new group. | 
|  | scoped_refptr<AppCacheGroup> group; | 
|  | group.swap(delegate.loaded_group_); | 
|  | delegate.loaded_manifest_url_ = GURL(); | 
|  |  | 
|  | // Conduct the test. | 
|  | service.storage()->LoadOrCreateGroup(manifest_url, &delegate); | 
|  | EXPECT_EQ(manifest_url, delegate.loaded_manifest_url_); | 
|  | EXPECT_EQ(group.get(), delegate.loaded_group_.get()); | 
|  | } | 
|  |  | 
|  | TEST_F(MockAppCacheStorageTest, LoadGroupAndCache_FarHit) { | 
|  | // Attempt to load a cache that is not currently in use | 
|  | // and does require loading from disk. This | 
|  | // load should complete asyncly. | 
|  | MockAppCacheService service; | 
|  | MockAppCacheStorage* storage = | 
|  | reinterpret_cast<MockAppCacheStorage*>(service.storage()); | 
|  |  | 
|  | // Setup some preconditions. Create a group and newest cache that | 
|  | // appears to be "stored" and "not currently in use". | 
|  | GURL manifest_url("http://blah/"); | 
|  | scoped_refptr<AppCacheGroup> group( | 
|  | new AppCacheGroup(service.storage(), manifest_url, 111)); | 
|  | int64_t cache_id = storage->NewCacheId(); | 
|  | scoped_refptr<AppCache> cache(new AppCache(service.storage(), cache_id)); | 
|  | cache->set_complete(true); | 
|  | group->AddCache(cache.get()); | 
|  | storage->AddStoredGroup(group.get()); | 
|  | storage->AddStoredCache(cache.get()); | 
|  |  | 
|  | // Drop the references from above so the only refs to these | 
|  | // objects are from within the storage class. This is to make | 
|  | // these objects appear as "not currently in use". | 
|  | AppCache* cache_ptr = cache.get(); | 
|  | AppCacheGroup* group_ptr = group.get(); | 
|  | cache = NULL; | 
|  | group = NULL; | 
|  |  | 
|  | // Setup a delegate to receive completion callbacks. | 
|  | MockStorageDelegate delegate; | 
|  |  | 
|  | // Conduct the cache load test. | 
|  | EXPECT_NE(cache_id, delegate.loaded_cache_id_); | 
|  | EXPECT_NE(cache_ptr, delegate.loaded_cache_.get()); | 
|  | storage->LoadCache(cache_id, &delegate); | 
|  | EXPECT_NE(cache_id, delegate.loaded_cache_id_); | 
|  | EXPECT_NE(cache_ptr, delegate.loaded_cache_.get()); | 
|  | base::RunLoop().RunUntilIdle();  // Do async task execution. | 
|  | EXPECT_EQ(cache_id, delegate.loaded_cache_id_); | 
|  | EXPECT_EQ(cache_ptr, delegate.loaded_cache_.get()); | 
|  | delegate.loaded_cache_ = NULL; | 
|  |  | 
|  | // Conduct the group load test. | 
|  | EXPECT_NE(manifest_url, delegate.loaded_manifest_url_); | 
|  | EXPECT_FALSE(delegate.loaded_group_.get()); | 
|  | storage->LoadOrCreateGroup(manifest_url, &delegate); | 
|  | EXPECT_NE(manifest_url, delegate.loaded_manifest_url_); | 
|  | EXPECT_FALSE(delegate.loaded_group_.get()); | 
|  | base::RunLoop().RunUntilIdle();  // Do async task execution. | 
|  | EXPECT_EQ(manifest_url, delegate.loaded_manifest_url_); | 
|  | EXPECT_EQ(group_ptr, delegate.loaded_group_.get()); | 
|  | } | 
|  |  | 
|  | TEST_F(MockAppCacheStorageTest, StoreNewGroup) { | 
|  | // Store a group and its newest cache. Should complete asyncly. | 
|  | MockAppCacheService service; | 
|  | MockAppCacheStorage* storage = | 
|  | reinterpret_cast<MockAppCacheStorage*>(service.storage()); | 
|  |  | 
|  | // Setup some preconditions. Create a group and newest cache that | 
|  | // appears to be "unstored". | 
|  | GURL manifest_url("http://blah/"); | 
|  | scoped_refptr<AppCacheGroup> group( | 
|  | new AppCacheGroup(service.storage(), manifest_url, 111)); | 
|  | int64_t cache_id = storage->NewCacheId(); | 
|  | scoped_refptr<AppCache> cache(new AppCache(service.storage(), cache_id)); | 
|  | // Hold a ref to the cache simulate the UpdateJob holding that ref, | 
|  | // and hold a ref to the group to simulate the CacheHost holding that ref. | 
|  |  | 
|  | // Conduct the store test. | 
|  | MockStorageDelegate delegate; | 
|  | EXPECT_TRUE(storage->stored_caches_.empty()); | 
|  | EXPECT_TRUE(storage->stored_groups_.empty()); | 
|  | storage->StoreGroupAndNewestCache(group.get(), cache.get(), &delegate); | 
|  | EXPECT_FALSE(delegate.stored_group_success_); | 
|  | EXPECT_TRUE(storage->stored_caches_.empty()); | 
|  | EXPECT_TRUE(storage->stored_groups_.empty()); | 
|  | base::RunLoop().RunUntilIdle();  // Do async task execution. | 
|  | EXPECT_TRUE(delegate.stored_group_success_); | 
|  | EXPECT_FALSE(storage->stored_caches_.empty()); | 
|  | EXPECT_FALSE(storage->stored_groups_.empty()); | 
|  | EXPECT_EQ(cache.get(), group->newest_complete_cache()); | 
|  | EXPECT_TRUE(cache->is_complete()); | 
|  | } | 
|  |  | 
|  | TEST_F(MockAppCacheStorageTest, StoreExistingGroup) { | 
|  | // Store a group and its newest cache. Should complete asyncly. | 
|  | MockAppCacheService service; | 
|  | MockAppCacheStorage* storage = | 
|  | reinterpret_cast<MockAppCacheStorage*>(service.storage()); | 
|  |  | 
|  | // Setup some preconditions. Create a group and old complete cache | 
|  | // that appear to be "stored", and a newest unstored complete cache. | 
|  | GURL manifest_url("http://blah/"); | 
|  | scoped_refptr<AppCacheGroup> group( | 
|  | new AppCacheGroup(service.storage(), manifest_url, 111)); | 
|  | int64_t old_cache_id = storage->NewCacheId(); | 
|  | scoped_refptr<AppCache> old_cache( | 
|  | new AppCache(service.storage(), old_cache_id)); | 
|  | old_cache->set_complete(true); | 
|  | group->AddCache(old_cache.get()); | 
|  | storage->AddStoredGroup(group.get()); | 
|  | storage->AddStoredCache(old_cache.get()); | 
|  | int64_t new_cache_id = storage->NewCacheId(); | 
|  | scoped_refptr<AppCache> new_cache( | 
|  | new AppCache(service.storage(), new_cache_id)); | 
|  | // Hold our refs to simulate the UpdateJob holding these refs. | 
|  |  | 
|  | // Conduct the test. | 
|  | MockStorageDelegate delegate; | 
|  | EXPECT_EQ(size_t(1), storage->stored_caches_.size()); | 
|  | EXPECT_EQ(size_t(1), storage->stored_groups_.size()); | 
|  | EXPECT_TRUE(storage->IsCacheStored(old_cache.get())); | 
|  | EXPECT_FALSE(storage->IsCacheStored(new_cache.get())); | 
|  | storage->StoreGroupAndNewestCache(group.get(), new_cache.get(), &delegate); | 
|  | EXPECT_FALSE(delegate.stored_group_success_); | 
|  | EXPECT_EQ(size_t(1), storage->stored_caches_.size()); | 
|  | EXPECT_EQ(size_t(1), storage->stored_groups_.size()); | 
|  | EXPECT_TRUE(storage->IsCacheStored(old_cache.get())); | 
|  | EXPECT_FALSE(storage->IsCacheStored(new_cache.get())); | 
|  | base::RunLoop().RunUntilIdle();  // Do async task execution. | 
|  | EXPECT_TRUE(delegate.stored_group_success_); | 
|  | EXPECT_EQ(size_t(1), storage->stored_caches_.size()); | 
|  | EXPECT_EQ(size_t(1), storage->stored_groups_.size()); | 
|  | EXPECT_FALSE(storage->IsCacheStored(old_cache.get())); | 
|  | EXPECT_TRUE(storage->IsCacheStored(new_cache.get())); | 
|  | EXPECT_EQ(new_cache.get(), group->newest_complete_cache()); | 
|  | EXPECT_TRUE(new_cache->is_complete()); | 
|  | } | 
|  |  | 
|  | TEST_F(MockAppCacheStorageTest, StoreExistingGroupExistingCache) { | 
|  | // Store a group with updates to its existing newest complete cache. | 
|  | MockAppCacheService service; | 
|  | MockAppCacheStorage* storage = | 
|  | reinterpret_cast<MockAppCacheStorage*>(service.storage()); | 
|  |  | 
|  | // Setup some preconditions. Create a group and a complete cache that | 
|  | // appear to be "stored". | 
|  | GURL manifest_url("http://blah"); | 
|  | scoped_refptr<AppCacheGroup> group( | 
|  | new AppCacheGroup(service.storage(), manifest_url, 111)); | 
|  | int64_t cache_id = storage->NewCacheId(); | 
|  | scoped_refptr<AppCache> cache(new AppCache(service.storage(), cache_id)); | 
|  | cache->set_complete(true); | 
|  | group->AddCache(cache.get()); | 
|  | storage->AddStoredGroup(group.get()); | 
|  | storage->AddStoredCache(cache.get()); | 
|  | // Hold our refs to simulate the UpdateJob holding these refs. | 
|  |  | 
|  | // Change the group's newest cache. | 
|  | EXPECT_EQ(cache.get(), group->newest_complete_cache()); | 
|  | GURL entry_url("http://blah/blah"); | 
|  | cache->AddEntry(entry_url, AppCacheEntry(AppCacheEntry::MASTER)); | 
|  |  | 
|  | // Conduct the test. | 
|  | MockStorageDelegate delegate; | 
|  | EXPECT_EQ(size_t(1), storage->stored_caches_.size()); | 
|  | EXPECT_EQ(size_t(1), storage->stored_groups_.size()); | 
|  | EXPECT_TRUE(storage->IsCacheStored(cache.get())); | 
|  | storage->StoreGroupAndNewestCache(group.get(), cache.get(), &delegate); | 
|  | EXPECT_FALSE(delegate.stored_group_success_); | 
|  | EXPECT_EQ(size_t(1), storage->stored_caches_.size()); | 
|  | EXPECT_EQ(size_t(1), storage->stored_groups_.size()); | 
|  | base::RunLoop().RunUntilIdle();  // Do async task execution. | 
|  | EXPECT_TRUE(delegate.stored_group_success_); | 
|  | EXPECT_EQ(size_t(1), storage->stored_caches_.size()); | 
|  | EXPECT_EQ(size_t(1), storage->stored_groups_.size()); | 
|  | EXPECT_TRUE(storage->IsCacheStored(cache.get())); | 
|  | EXPECT_EQ(cache.get(), group->newest_complete_cache()); | 
|  | EXPECT_TRUE(cache->GetEntry(entry_url)); | 
|  | } | 
|  |  | 
|  | TEST_F(MockAppCacheStorageTest, MakeGroupObsolete) { | 
|  | // Make a group obsolete, should complete asyncly. | 
|  | MockAppCacheService service; | 
|  | MockAppCacheStorage* storage = | 
|  | reinterpret_cast<MockAppCacheStorage*>(service.storage()); | 
|  |  | 
|  | // Setup some preconditions. Create a group and newest cache that | 
|  | // appears to be "stored" and "currently in use". | 
|  | GURL manifest_url("http://blah/"); | 
|  | scoped_refptr<AppCacheGroup> group( | 
|  | new AppCacheGroup(service.storage(), manifest_url, 111)); | 
|  | int64_t cache_id = storage->NewCacheId(); | 
|  | scoped_refptr<AppCache> cache(new AppCache(service.storage(), cache_id)); | 
|  | cache->set_complete(true); | 
|  | group->AddCache(cache.get()); | 
|  | storage->AddStoredGroup(group.get()); | 
|  | storage->AddStoredCache(cache.get()); | 
|  | // Hold our refs to simulate the UpdateJob holding these refs. | 
|  |  | 
|  | // Conduct the test. | 
|  | MockStorageDelegate delegate; | 
|  | EXPECT_FALSE(group->is_obsolete()); | 
|  | EXPECT_EQ(size_t(1), storage->stored_caches_.size()); | 
|  | EXPECT_EQ(size_t(1), storage->stored_groups_.size()); | 
|  | EXPECT_FALSE(cache->HasOneRef()); | 
|  | EXPECT_FALSE(group->HasOneRef()); | 
|  | storage->MakeGroupObsolete(group.get(), &delegate, 0); | 
|  | EXPECT_FALSE(group->is_obsolete()); | 
|  | EXPECT_EQ(size_t(1), storage->stored_caches_.size()); | 
|  | EXPECT_EQ(size_t(1), storage->stored_groups_.size()); | 
|  | EXPECT_FALSE(cache->HasOneRef()); | 
|  | EXPECT_FALSE(group->HasOneRef()); | 
|  | base::RunLoop().RunUntilIdle();  // Do async task execution. | 
|  | EXPECT_TRUE(delegate.obsoleted_success_); | 
|  | EXPECT_EQ(group.get(), delegate.obsoleted_group_.get()); | 
|  | EXPECT_TRUE(group->is_obsolete()); | 
|  | EXPECT_TRUE(storage->stored_caches_.empty()); | 
|  | EXPECT_TRUE(storage->stored_groups_.empty()); | 
|  | EXPECT_TRUE(cache->HasOneRef()); | 
|  | EXPECT_FALSE(group->HasOneRef()); | 
|  | delegate.obsoleted_group_ = NULL; | 
|  | cache = NULL; | 
|  | EXPECT_TRUE(group->HasOneRef()); | 
|  | } | 
|  |  | 
|  | TEST_F(MockAppCacheStorageTest, MarkEntryAsForeign) { | 
|  | // Should complete syncly. | 
|  | MockAppCacheService service; | 
|  | MockAppCacheStorage* storage = | 
|  | reinterpret_cast<MockAppCacheStorage*>(service.storage()); | 
|  |  | 
|  | // Setup some preconditions. Create a cache with an entry. | 
|  | GURL entry_url("http://blah/entry"); | 
|  | int64_t cache_id = storage->NewCacheId(); | 
|  | scoped_refptr<AppCache> cache(new AppCache(service.storage(), cache_id)); | 
|  | cache->AddEntry(entry_url, AppCacheEntry(AppCacheEntry::EXPLICIT)); | 
|  |  | 
|  | // Conduct the test. | 
|  | MockStorageDelegate delegate; | 
|  | EXPECT_FALSE(cache->GetEntry(entry_url)->IsForeign()); | 
|  | storage->MarkEntryAsForeign(entry_url, cache_id); | 
|  | EXPECT_TRUE(cache->GetEntry(entry_url)->IsForeign()); | 
|  | EXPECT_TRUE(cache->GetEntry(entry_url)->IsExplicit()); | 
|  | } | 
|  |  | 
|  | TEST_F(MockAppCacheStorageTest, FindNoMainResponse) { | 
|  | // Should complete asyncly. | 
|  | MockAppCacheService service; | 
|  | MockAppCacheStorage* storage = | 
|  | reinterpret_cast<MockAppCacheStorage*>(service.storage()); | 
|  |  | 
|  | // Conduct the test. | 
|  | MockStorageDelegate delegate; | 
|  | GURL url("http://blah/some_url"); | 
|  | EXPECT_NE(url, delegate.found_url_); | 
|  | storage->FindResponseForMainRequest(url, GURL(), &delegate); | 
|  | EXPECT_NE(url, delegate.found_url_); | 
|  | base::RunLoop().RunUntilIdle();  // Do async task execution. | 
|  | EXPECT_EQ(url, delegate.found_url_); | 
|  | EXPECT_TRUE(delegate.found_manifest_url_.is_empty()); | 
|  | EXPECT_EQ(kAppCacheNoCacheId, delegate.found_cache_id_); | 
|  | EXPECT_EQ(kAppCacheNoResponseId, delegate.found_entry_.response_id()); | 
|  | EXPECT_EQ(kAppCacheNoResponseId, | 
|  | delegate.found_fallback_entry_.response_id()); | 
|  | EXPECT_TRUE(delegate.found_fallback_url_.is_empty()); | 
|  | EXPECT_EQ(0, delegate.found_entry_.types()); | 
|  | EXPECT_EQ(0, delegate.found_fallback_entry_.types()); | 
|  | } | 
|  |  | 
|  | TEST_F(MockAppCacheStorageTest, BasicFindMainResponse) { | 
|  | // Should complete asyncly. | 
|  | MockAppCacheService service; | 
|  | MockAppCacheStorage* storage = | 
|  | reinterpret_cast<MockAppCacheStorage*>(service.storage()); | 
|  |  | 
|  | // Setup some preconditions. Create a complete cache with an entry. | 
|  | const int64_t kCacheId = storage->NewCacheId(); | 
|  | const GURL kEntryUrl("http://blah/entry"); | 
|  | const GURL kManifestUrl("http://blah/manifest"); | 
|  | const int64_t kResponseId = 1; | 
|  | scoped_refptr<AppCache> cache(new AppCache(service.storage(), kCacheId)); | 
|  | cache->AddEntry( | 
|  | kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT, kResponseId)); | 
|  | cache->set_complete(true); | 
|  | scoped_refptr<AppCacheGroup> group( | 
|  | new AppCacheGroup(service.storage(), kManifestUrl, 111)); | 
|  | group->AddCache(cache.get()); | 
|  | storage->AddStoredGroup(group.get()); | 
|  | storage->AddStoredCache(cache.get()); | 
|  |  | 
|  | // Conduct the test. | 
|  | MockStorageDelegate delegate; | 
|  | EXPECT_NE(kEntryUrl, delegate.found_url_); | 
|  | storage->FindResponseForMainRequest(kEntryUrl, GURL(), &delegate); | 
|  | EXPECT_NE(kEntryUrl, delegate.found_url_); | 
|  | base::RunLoop().RunUntilIdle();  // Do async task execution. | 
|  | EXPECT_EQ(kEntryUrl, delegate.found_url_); | 
|  | EXPECT_EQ(kManifestUrl, delegate.found_manifest_url_); | 
|  | EXPECT_EQ(kCacheId, delegate.found_cache_id_); | 
|  | EXPECT_EQ(kResponseId, delegate.found_entry_.response_id()); | 
|  | EXPECT_TRUE(delegate.found_entry_.IsExplicit()); | 
|  | EXPECT_FALSE(delegate.found_fallback_entry_.has_response_id()); | 
|  | } | 
|  |  | 
|  | TEST_F(MockAppCacheStorageTest, BasicFindMainFallbackResponse) { | 
|  | // Should complete asyncly. | 
|  | MockAppCacheService service; | 
|  | MockAppCacheStorage* storage = | 
|  | reinterpret_cast<MockAppCacheStorage*>(service.storage()); | 
|  |  | 
|  | // Setup some preconditions. Create a complete cache with a | 
|  | // fallback namespace and entry. | 
|  | const int64_t kCacheId = storage->NewCacheId(); | 
|  | const GURL kFallbackEntryUrl1("http://blah/fallback_entry1"); | 
|  | const GURL kFallbackNamespaceUrl1("http://blah/fallback_namespace/"); | 
|  | const GURL kFallbackEntryUrl2("http://blah/fallback_entry2"); | 
|  | const GURL kFallbackNamespaceUrl2("http://blah/fallback_namespace/longer"); | 
|  | const GURL kManifestUrl("http://blah/manifest"); | 
|  | const int64_t kResponseId1 = 1; | 
|  | const int64_t kResponseId2 = 2; | 
|  |  | 
|  | AppCacheManifest manifest; | 
|  | manifest.fallback_namespaces.push_back( | 
|  | AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE, kFallbackNamespaceUrl1, | 
|  | kFallbackEntryUrl1, false)); | 
|  | manifest.fallback_namespaces.push_back( | 
|  | AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE, kFallbackNamespaceUrl2, | 
|  | kFallbackEntryUrl2, false)); | 
|  |  | 
|  | scoped_refptr<AppCache> cache(new AppCache(service.storage(), kCacheId)); | 
|  | cache->InitializeWithManifest(&manifest); | 
|  | cache->AddEntry(kFallbackEntryUrl1, | 
|  | AppCacheEntry(AppCacheEntry::FALLBACK, kResponseId1)); | 
|  | cache->AddEntry(kFallbackEntryUrl2, | 
|  | AppCacheEntry(AppCacheEntry::FALLBACK, kResponseId2)); | 
|  | cache->set_complete(true); | 
|  |  | 
|  | scoped_refptr<AppCacheGroup> group( | 
|  | new AppCacheGroup(service.storage(), kManifestUrl, 111)); | 
|  | group->AddCache(cache.get()); | 
|  | storage->AddStoredGroup(group.get()); | 
|  | storage->AddStoredCache(cache.get()); | 
|  |  | 
|  | // The test url is in both fallback namespace urls, but should match | 
|  | // the longer of the two. | 
|  | const GURL kTestUrl("http://blah/fallback_namespace/longer/test"); | 
|  |  | 
|  | // Conduct the test. | 
|  | MockStorageDelegate delegate; | 
|  | EXPECT_NE(kTestUrl, delegate.found_url_); | 
|  | storage->FindResponseForMainRequest(kTestUrl, GURL(), &delegate); | 
|  | EXPECT_NE(kTestUrl, delegate.found_url_); | 
|  | base::RunLoop().RunUntilIdle();  // Do async task execution. | 
|  | EXPECT_EQ(kTestUrl, delegate.found_url_); | 
|  | EXPECT_EQ(kManifestUrl, delegate.found_manifest_url_); | 
|  | EXPECT_EQ(kCacheId, delegate.found_cache_id_); | 
|  | EXPECT_FALSE(delegate.found_entry_.has_response_id()); | 
|  | EXPECT_EQ(kResponseId2, delegate.found_fallback_entry_.response_id()); | 
|  | EXPECT_EQ(kFallbackEntryUrl2, delegate.found_fallback_url_); | 
|  | EXPECT_TRUE(delegate.found_fallback_entry_.IsFallback()); | 
|  | } | 
|  |  | 
|  | TEST_F(MockAppCacheStorageTest, FindMainResponseWithMultipleCandidates) { | 
|  | // Should complete asyncly. | 
|  | MockAppCacheService service; | 
|  | MockAppCacheStorage* storage = | 
|  | reinterpret_cast<MockAppCacheStorage*>(service.storage()); | 
|  |  | 
|  | // Setup some preconditions. Create 2 complete caches with an entry | 
|  | // for the same url. | 
|  |  | 
|  | const GURL kEntryUrl("http://blah/entry"); | 
|  | const int64_t kCacheId1 = storage->NewCacheId(); | 
|  | const int64_t kCacheId2 = storage->NewCacheId(); | 
|  | const GURL kManifestUrl1("http://blah/manifest1"); | 
|  | const GURL kManifestUrl2("http://blah/manifest2"); | 
|  | const int64_t kResponseId1 = 1; | 
|  | const int64_t kResponseId2 = 2; | 
|  |  | 
|  | // The first cache. | 
|  | scoped_refptr<AppCache> cache(new AppCache(service.storage(), kCacheId1)); | 
|  | cache->AddEntry( | 
|  | kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT, kResponseId1)); | 
|  | cache->set_complete(true); | 
|  | scoped_refptr<AppCacheGroup> group( | 
|  | new AppCacheGroup(service.storage(), kManifestUrl1, 111)); | 
|  | group->AddCache(cache.get()); | 
|  | storage->AddStoredGroup(group.get()); | 
|  | storage->AddStoredCache(cache.get()); | 
|  | // Drop our references to cache1 so it appears as "not in use". | 
|  | cache = NULL; | 
|  | group = NULL; | 
|  |  | 
|  | // The second cache. | 
|  | cache = new AppCache(service.storage(), kCacheId2); | 
|  | cache->AddEntry( | 
|  | kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT, kResponseId2)); | 
|  | cache->set_complete(true); | 
|  | group = new AppCacheGroup(service.storage(), kManifestUrl2, 222); | 
|  | group->AddCache(cache.get()); | 
|  | storage->AddStoredGroup(group.get()); | 
|  | storage->AddStoredCache(cache.get()); | 
|  |  | 
|  | // Conduct the test, we should find the response from the second cache | 
|  | // since it's "in use". | 
|  | MockStorageDelegate delegate; | 
|  | EXPECT_NE(kEntryUrl, delegate.found_url_); | 
|  | storage->FindResponseForMainRequest(kEntryUrl, GURL(), &delegate); | 
|  | EXPECT_NE(kEntryUrl, delegate.found_url_); | 
|  | base::RunLoop().RunUntilIdle();  // Do async task execution. | 
|  | EXPECT_EQ(kEntryUrl, delegate.found_url_); | 
|  | EXPECT_EQ(kManifestUrl2, delegate.found_manifest_url_); | 
|  | EXPECT_EQ(kCacheId2, delegate.found_cache_id_); | 
|  | EXPECT_EQ(kResponseId2, delegate.found_entry_.response_id()); | 
|  | EXPECT_TRUE(delegate.found_entry_.IsExplicit()); | 
|  | EXPECT_FALSE(delegate.found_fallback_entry_.has_response_id()); | 
|  | } | 
|  |  | 
|  | TEST_F(MockAppCacheStorageTest, FindMainResponseExclusions) { | 
|  | // Should complete asyncly. | 
|  | MockAppCacheService service; | 
|  | MockAppCacheStorage* storage = | 
|  | reinterpret_cast<MockAppCacheStorage*>(service.storage()); | 
|  |  | 
|  | // Setup some preconditions. Create a complete cache with a | 
|  | // foreign entry and an online namespace. | 
|  |  | 
|  | const int64_t kCacheId = storage->NewCacheId(); | 
|  | const GURL kEntryUrl("http://blah/entry"); | 
|  | const GURL kManifestUrl("http://blah/manifest"); | 
|  | const GURL kOnlineNamespaceUrl("http://blah/online_namespace"); | 
|  | const int64_t kResponseId = 1; | 
|  |  | 
|  | AppCacheManifest manifest; | 
|  | manifest.online_whitelist_namespaces.push_back( | 
|  | AppCacheNamespace(APPCACHE_NETWORK_NAMESPACE, kOnlineNamespaceUrl, | 
|  | GURL(), false)); | 
|  | scoped_refptr<AppCache> cache(new AppCache(service.storage(), kCacheId)); | 
|  | cache->InitializeWithManifest(&manifest); | 
|  | cache->AddEntry( | 
|  | kEntryUrl, | 
|  | AppCacheEntry(AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN, | 
|  | kResponseId)); | 
|  | cache->set_complete(true); | 
|  | scoped_refptr<AppCacheGroup> group( | 
|  | new AppCacheGroup(service.storage(), kManifestUrl, 111)); | 
|  | group->AddCache(cache.get()); | 
|  | storage->AddStoredGroup(group.get()); | 
|  | storage->AddStoredCache(cache.get()); | 
|  |  | 
|  | MockStorageDelegate delegate; | 
|  |  | 
|  | // We should not find anything for the foreign entry. | 
|  | EXPECT_NE(kEntryUrl, delegate.found_url_); | 
|  | storage->FindResponseForMainRequest(kEntryUrl, GURL(), &delegate); | 
|  | EXPECT_NE(kEntryUrl, delegate.found_url_); | 
|  | base::RunLoop().RunUntilIdle();  // Do async task execution. | 
|  | EXPECT_EQ(kEntryUrl, delegate.found_url_); | 
|  | EXPECT_TRUE(delegate.found_manifest_url_.is_empty()); | 
|  | EXPECT_EQ(kAppCacheNoCacheId, delegate.found_cache_id_); | 
|  | EXPECT_EQ(kAppCacheNoResponseId, delegate.found_entry_.response_id()); | 
|  | EXPECT_EQ(kAppCacheNoResponseId, | 
|  | delegate.found_fallback_entry_.response_id()); | 
|  | EXPECT_TRUE(delegate.found_fallback_url_.is_empty()); | 
|  | EXPECT_EQ(0, delegate.found_entry_.types()); | 
|  | EXPECT_EQ(0, delegate.found_fallback_entry_.types()); | 
|  |  | 
|  | // We should not find anything for the online namespace. | 
|  | EXPECT_NE(kOnlineNamespaceUrl, delegate.found_url_); | 
|  | storage->FindResponseForMainRequest(kOnlineNamespaceUrl, GURL(), &delegate); | 
|  | EXPECT_NE(kOnlineNamespaceUrl, delegate.found_url_); | 
|  | base::RunLoop().RunUntilIdle();  // Do async task execution. | 
|  | EXPECT_EQ(kOnlineNamespaceUrl, delegate.found_url_); | 
|  | EXPECT_TRUE(delegate.found_manifest_url_.is_empty()); | 
|  | EXPECT_EQ(kAppCacheNoCacheId, delegate.found_cache_id_); | 
|  | EXPECT_EQ(kAppCacheNoResponseId, delegate.found_entry_.response_id()); | 
|  | EXPECT_EQ(kAppCacheNoResponseId, | 
|  | delegate.found_fallback_entry_.response_id()); | 
|  | EXPECT_TRUE(delegate.found_fallback_url_.is_empty()); | 
|  | EXPECT_EQ(0, delegate.found_entry_.types()); | 
|  | EXPECT_EQ(0, delegate.found_fallback_entry_.types()); | 
|  | } | 
|  |  | 
|  | }  // namespace content |