diff options
author | michaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-12 02:10:27 +0000 |
---|---|---|
committer | michaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-12 02:10:27 +0000 |
commit | 2bfc5c14f395ef247a5980e1a6dcc0f26893f2d6 (patch) | |
tree | 42b0e45b16affe458cc051c7bdd282e2e43546cf /webkit/appcache | |
parent | d32e75740a892b8578c825b9b5fb850ee5f41269 (diff) | |
download | chromium_src-2bfc5c14f395ef247a5980e1a6dcc0f26893f2d6.zip chromium_src-2bfc5c14f395ef247a5980e1a6dcc0f26893f2d6.tar.gz chromium_src-2bfc5c14f395ef247a5980e1a6dcc0f26893f2d6.tar.bz2 |
Lookup appcached responses given a request URL.
TEST=new cases in mock_appcache_storage_unittest.cc and appcache_unittest.cc
BUG=none
Review URL: http://codereview.chromium.org/372070
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@31757 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/appcache')
-rw-r--r-- | webkit/appcache/appcache.cc | 66 | ||||
-rw-r--r-- | webkit/appcache/appcache.h | 11 | ||||
-rw-r--r-- | webkit/appcache/appcache_unittest.cc | 117 | ||||
-rw-r--r-- | webkit/appcache/mock_appcache_storage.cc | 152 | ||||
-rw-r--r-- | webkit/appcache/mock_appcache_storage.h | 12 | ||||
-rw-r--r-- | webkit/appcache/mock_appcache_storage_unittest.cc | 208 |
6 files changed, 538 insertions, 28 deletions
diff --git a/webkit/appcache/appcache.cc b/webkit/appcache/appcache.cc index 41c3f54..6a943c8b 100644 --- a/webkit/appcache/appcache.cc +++ b/webkit/appcache/appcache.cc @@ -2,9 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <algorithm> + #include "webkit/appcache/appcache.h" #include "base/logging.h" +#include "base/string_util.h" #include "webkit/appcache/appcache_group.h" #include "webkit/appcache/appcache_host.h" #include "webkit/appcache/appcache_interfaces.h" @@ -55,11 +58,74 @@ AppCacheEntry* AppCache::GetEntry(const GURL& url) { return (it != entries_.end()) ? &(it->second) : NULL; } +namespace { + +bool SortByLength( + const FallbackNamespace& lhs, const FallbackNamespace& rhs) { + return lhs.first.spec().length() > rhs.first.spec().length(); +} + +} + void AppCache::InitializeWithManifest(Manifest* manifest) { DCHECK(manifest); fallback_namespaces_.swap(manifest->fallback_namespaces); online_whitelist_namespaces_.swap(manifest->online_whitelist_namespaces); online_whitelist_all_ = manifest->online_whitelist_all; + + // Sort the fallback namespaces by url string length, longest to shortest, + // since longer matches trump when matching a url to a namespace. + std::sort(fallback_namespaces_.begin(), fallback_namespaces_.end(), + SortByLength); +} + +bool AppCache::FindResponseForRequest(const GURL& url, + AppCacheEntry* found_entry, AppCacheEntry* found_fallback_entry, + GURL* found_fallback_namespace, bool* found_network_namespace) { + AppCacheEntry* entry = GetEntry(url); + if (entry) { + *found_entry = *entry; + return true; + } + + FallbackNamespace* fallback_namespace = FindFallbackNamespace(url); + if (fallback_namespace) { + entry = GetEntry(fallback_namespace->second); + DCHECK(entry); + *found_fallback_entry = *entry; + *found_fallback_namespace = fallback_namespace->first; + return true; + } + + *found_network_namespace = IsInNetworkNamespace(url); + return *found_network_namespace; +} + +FallbackNamespace* AppCache::FindFallbackNamespace(const GURL& url) { + size_t count = fallback_namespaces_.size(); + for (size_t i = 0; i < count; ++i) { + if (StartsWithASCII( + url.spec(), fallback_namespaces_[i].first.spec(), true)) { + return &fallback_namespaces_[i]; + } + } + return NULL; +} + +bool AppCache::IsInNetworkNamespace(const GURL& url) { + if (online_whitelist_all_) + return true; + + // TODO(michaeln): There are certainly better 'prefix matching' + // structures and algorithms that can be applied here and above. + size_t count = online_whitelist_namespaces_.size(); + for (size_t i = 0; i < count; ++i) { + if (StartsWithASCII( + url.spec(), online_whitelist_namespaces_[i].spec(), true)) { + return true; + } + } + return false; } } // namespace appcache diff --git a/webkit/appcache/appcache.h b/webkit/appcache/appcache.h index b601fcc..6e43a85 100644 --- a/webkit/appcache/appcache.h +++ b/webkit/appcache/appcache.h @@ -75,11 +75,10 @@ class AppCache : public base::RefCounted<AppCache> { // Do not use the manifest after this call. void InitializeWithManifest(Manifest* manifest); - void FindResponseForRequest(const GURL& url, + bool FindResponseForRequest(const GURL& url, AppCacheEntry* found_entry, AppCacheEntry* found_fallback_entry, - bool* found_network_namespace) { - return; // TODO(michaeln): write me - } + GURL* found_fallback_namespace, bool* found_network_namespace); + private: friend class AppCacheGroup; friend class AppCacheHost; @@ -91,6 +90,10 @@ class AppCache : public base::RefCounted<AppCache> { // Use AppCacheGroup::Add/RemoveCache() to manipulate owning group. void set_owning_group(AppCacheGroup* group) { owning_group_ = group; } + // FindResponseForRequest helpers + FallbackNamespace* FindFallbackNamespace(const GURL& url); + bool IsInNetworkNamespace(const GURL& url); + // Use AppCacheHost::AssociateCache() to manipulate host association. void AssociateHost(AppCacheHost* host) { associated_hosts_.insert(host); diff --git a/webkit/appcache/appcache_unittest.cc b/webkit/appcache/appcache_unittest.cc index d188550..5f95f9d 100644 --- a/webkit/appcache/appcache_unittest.cc +++ b/webkit/appcache/appcache_unittest.cc @@ -90,5 +90,122 @@ TEST(AppCacheTest, InitializeWithManifest) { EXPECT_TRUE(manifest.online_whitelist_namespaces.empty()); } +TEST(AppCacheTest, FindResponseForRequest) { + MockAppCacheService service; + + const GURL kOnlineNamespaceUrl("http://blah/online_namespace"); + 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 GURL kForeignExplicitEntryUrl("http://blah/foreign"); + const GURL kInOnlineNamespaceUrl( + "http://blah/online_namespace/network"); + const GURL kExplicitInOnlineNamespaceUrl( + "http://blah/online_namespace/explicit"); + const GURL kFallbackTestUrl1("http://blah/fallback_namespace/1"); + const GURL kFallbackTestUrl2("http://blah/fallback_namespace/longer2"); + + const int64 kFallbackResponseId1 = 1; + const int64 kFallbackResponseId2 = 2; + const int64 kManifestResponseId = 3; + const int64 kForeignExplicitResponseId = 4; + const int64 kExplicitInOnlineNamespaceResponseId = 5; + + Manifest manifest; + manifest.online_whitelist_namespaces.push_back(kOnlineNamespaceUrl); + manifest.fallback_namespaces.push_back( + FallbackNamespace(kFallbackNamespaceUrl1, kFallbackEntryUrl1)); + manifest.fallback_namespaces.push_back( + FallbackNamespace(kFallbackNamespaceUrl2, kFallbackEntryUrl2)); + + // Create a cache with some namespaces and entries. + scoped_refptr<AppCache> cache = new AppCache(&service, 1234); + cache->InitializeWithManifest(&manifest); + cache->AddEntry( + kFallbackEntryUrl1, + AppCacheEntry(AppCacheEntry::FALLBACK, kFallbackResponseId1)); + cache->AddEntry( + kFallbackEntryUrl2, + AppCacheEntry(AppCacheEntry::FALLBACK, kFallbackResponseId2)); + cache->AddEntry( + kManifestUrl, + AppCacheEntry(AppCacheEntry::MANIFEST, kManifestResponseId)); + cache->AddEntry( + kForeignExplicitEntryUrl, + AppCacheEntry(AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN, + kForeignExplicitResponseId)); + cache->AddEntry( + kExplicitInOnlineNamespaceUrl, + AppCacheEntry(AppCacheEntry::EXPLICIT, + kExplicitInOnlineNamespaceResponseId)); + cache->set_complete(true); + + // See that we get expected results from FindResponseForRequest + + bool found = false; + AppCacheEntry entry; + AppCacheEntry fallback_entry; + GURL fallback_namespace; + bool network_namespace = false; + + found = cache->FindResponseForRequest(GURL("http://blah/miss"), + &entry, &fallback_entry, &fallback_namespace, &network_namespace); + EXPECT_FALSE(found); + + found = cache->FindResponseForRequest(kForeignExplicitEntryUrl, + &entry, &fallback_entry, &fallback_namespace, &network_namespace); + EXPECT_TRUE(found); + EXPECT_EQ(kForeignExplicitResponseId, entry.response_id()); + EXPECT_FALSE(fallback_entry.has_response_id()); + EXPECT_FALSE(network_namespace); + + entry = AppCacheEntry(); // reset + + found = cache->FindResponseForRequest(kManifestUrl, + &entry, &fallback_entry, &fallback_namespace, &network_namespace); + EXPECT_TRUE(found); + EXPECT_EQ(kManifestResponseId, entry.response_id()); + EXPECT_FALSE(fallback_entry.has_response_id()); + EXPECT_FALSE(network_namespace); + + entry = AppCacheEntry(); // reset + + found = cache->FindResponseForRequest(kInOnlineNamespaceUrl, + &entry, &fallback_entry, &fallback_namespace, &network_namespace); + EXPECT_TRUE(found); + EXPECT_FALSE(entry.has_response_id()); + EXPECT_FALSE(fallback_entry.has_response_id()); + EXPECT_TRUE(network_namespace); + + network_namespace = false; // reset + + found = cache->FindResponseForRequest(kExplicitInOnlineNamespaceUrl, + &entry, &fallback_entry, &fallback_namespace, &network_namespace); + EXPECT_TRUE(found); + EXPECT_EQ(kExplicitInOnlineNamespaceResponseId, entry.response_id()); + EXPECT_FALSE(fallback_entry.has_response_id()); + EXPECT_FALSE(network_namespace); + + entry = AppCacheEntry(); // reset + + found = cache->FindResponseForRequest(kFallbackTestUrl1, + &entry, &fallback_entry, &fallback_namespace, &network_namespace); + EXPECT_TRUE(found); + EXPECT_FALSE(entry.has_response_id()); + EXPECT_EQ(kFallbackResponseId1, fallback_entry.response_id()); + EXPECT_FALSE(network_namespace); + + fallback_entry = AppCacheEntry(); // reset + + found = cache->FindResponseForRequest(kFallbackTestUrl2, + &entry, &fallback_entry, &fallback_namespace, &network_namespace); + EXPECT_TRUE(found); + EXPECT_FALSE(entry.has_response_id()); + EXPECT_EQ(kFallbackResponseId2, fallback_entry.response_id()); + EXPECT_FALSE(network_namespace); +} + } // namespace appacache diff --git a/webkit/appcache/mock_appcache_storage.cc b/webkit/appcache/mock_appcache_storage.cc index 919e5f1..bc4a385 100644 --- a/webkit/appcache/mock_appcache_storage.cc +++ b/webkit/appcache/mock_appcache_storage.cc @@ -106,8 +106,10 @@ void MockAppCacheStorage::FindResponseForSubRequest( return; } - cache->FindResponseForRequest(url, found_entry, found_fallback_entry, - found_network_namespace); + GURL fallback_namespace_not_used; + cache->FindResponseForRequest( + url, found_entry, found_fallback_entry, + &fallback_namespace_not_used, found_network_namespace); } void MockAppCacheStorage::MarkEntryAsForeign( @@ -205,32 +207,140 @@ void MockAppCacheStorage::ProcessStoreGroupAndNewestCache( // DoomResponses(group->manifest_url(), doomed_responses_); } +namespace { + +struct FoundCandidate { + AppCacheEntry entry; + int64 cache_id; + GURL manifest_url; + bool is_cache_in_use; + + FoundCandidate() : cache_id(kNoCacheId), is_cache_in_use(false) {} +}; + +} // namespace + void MockAppCacheStorage::ProcessFindResponseForMainRequest( const GURL& url, scoped_refptr<DelegateReference> delegate_ref) { - // TODO(michaeln): write me when doing AppCacheRequestHandler - // foreach(stored_group) { - // if (group->manifest_url()->origin() != url.GetOrigin()) - // continue; - // look for an entry - // look for a fallback namespace - // look for a online namespace - // } - AppCacheEntry found_entry; - AppCacheEntry found_fallback_entry; - int64 found_cache_id = kNoCacheId; - GURL found_manifest_url = GURL(); if (simulate_find_main_resource_) { - found_entry = simulated_found_entry_; - found_fallback_entry = simulated_found_fallback_entry_; - found_cache_id = simulated_found_cache_id_; - found_manifest_url = simulated_found_manifest_url_; simulate_find_main_resource_ = false; + if (delegate_ref->delegate) { + delegate_ref->delegate->OnMainResponseFound( + url, simulated_found_entry_, simulated_found_fallback_entry_, + simulated_found_cache_id_, simulated_found_manifest_url_); + } + return; + } + + // This call has no persistent side effects, if the delegate has gone + // away, we can just bail out early. + if (!delegate_ref->delegate) + return; + + // TODO(michaeln): The heuristics around choosing amoungst + // multiple candidates is under specified, and just plain + // not fully understood. Refine these over time. In particular, + // * prefer candidates from newer caches + // * take into account the cache associated with the document + // that initiated the navigation + // * take into account the cache associated with the document + // currently residing in the frame being navigated + FoundCandidate found_candidate; + FoundCandidate found_fallback_candidate; + GURL found_fallback_candidate_namespace; + + for (StoredGroupMap::const_iterator it = stored_groups_.begin(); + it != stored_groups_.end(); ++it) { + AppCacheGroup* group = it->second.get(); + AppCache* cache = group->newest_complete_cache(); + if (group->is_obsolete() || !cache || + (url.GetOrigin() != group->manifest_url().GetOrigin())) { + continue; + } + + AppCacheEntry found_entry; + AppCacheEntry found_fallback_entry; + GURL found_fallback_namespace; + bool ignore_found_network_namespace = false; + bool found = cache->FindResponseForRequest( + url, &found_entry, &found_fallback_entry, + &found_fallback_namespace, + &ignore_found_network_namespace); + + // 6.11.1 Navigating across documents, Step 10. + // Network namespacing doesn't apply to main resource loads, + // and foreign entries are excluded. + if (!found || ignore_found_network_namespace || + (found_entry.has_response_id() && found_entry.IsForeign()) || + (found_fallback_entry.has_response_id() && + found_fallback_entry.IsForeign())) { + continue; + } + + // We have a bias for hits from caches that are in use. + bool is_in_use = IsCacheStored(cache) && !cache->HasOneRef(); + + if (found_entry.has_response_id()) { + found_candidate.entry = found_entry; + found_candidate.cache_id = cache->cache_id(); + found_candidate.manifest_url = group->manifest_url(); + found_candidate.is_cache_in_use = is_in_use; + if (is_in_use) + break; // We break out of the loop with this direct hit. + } else { + DCHECK(found_fallback_entry.has_response_id()); + + bool take_new_candidate = true; + + // Does the newly found entry trump our current candidate? + if (found_fallback_candidate.entry.has_response_id()) { + // Longer namespace prefix matches win. + size_t found_length = + found_fallback_namespace.spec().length(); + size_t candidate_length = + found_fallback_candidate_namespace.spec().length(); + + if (found_length > candidate_length) { + take_new_candidate = true; + } else if (found_length == candidate_length && + is_in_use && !found_fallback_candidate.is_cache_in_use) { + take_new_candidate = true; + } else { + take_new_candidate = false; + } + } + + if (take_new_candidate) { + found_fallback_candidate.entry = found_fallback_entry; + found_fallback_candidate.cache_id = cache->cache_id(); + found_fallback_candidate.manifest_url = group->manifest_url(); + found_fallback_candidate.is_cache_in_use = is_in_use; + found_fallback_candidate_namespace = found_fallback_namespace; + } + } + } + + // Found a direct hit. + if (found_candidate.entry.has_response_id()) { + delegate_ref->delegate->OnMainResponseFound( + url, found_candidate.entry, AppCacheEntry(), + found_candidate.cache_id, found_candidate.manifest_url); + return; } - if (delegate_ref->delegate) { + + // Found a fallback namespace. + if (found_fallback_candidate.entry.has_response_id()) { delegate_ref->delegate->OnMainResponseFound( - url, found_entry, found_fallback_entry, - found_cache_id, found_manifest_url); + url, AppCacheEntry(), found_fallback_candidate.entry, + found_fallback_candidate.cache_id, + found_fallback_candidate.manifest_url); + return; } + + // Didn't find anything. + delegate_ref->delegate->OnMainResponseFound( + url, AppCacheEntry(), AppCacheEntry(), + kNoCacheId, GURL::EmptyGURL()); } void MockAppCacheStorage::ProcessMakeGroupObsolete( diff --git a/webkit/appcache/mock_appcache_storage.h b/webkit/appcache/mock_appcache_storage.h index 9f352bd..bf70fc6 100644 --- a/webkit/appcache/mock_appcache_storage.h +++ b/webkit/appcache/mock_appcache_storage.h @@ -97,7 +97,8 @@ class MockAppCacheStorage : public AppCacheStorage { return disk_cache_.get(); } - // Simulate failures for testing. + // Simulate failures for testing. Once set all subsequent calls + // to MakeGroupObsolete or StorageGroupAndNewestCache will fail. void SimulateMakeGroupObsoleteFailure() { simulate_make_group_obsolete_failure_ = true; } @@ -105,7 +106,10 @@ class MockAppCacheStorage : public AppCacheStorage { simulate_store_group_and_newest_cache_failure_ = true; } - // Simulate FindResponseFor results for testing. + // Simulate FindResponseFor results for testing. These + // provided values will be return on the next call to + // the corresponding Find method, subsequent calls are + // unaffected. void SimulateFindMainResource( const AppCacheEntry& entry, const AppCacheEntry& fallback_entry, @@ -149,7 +153,11 @@ class MockAppCacheStorage : public AppCacheStorage { GURL simulated_found_manifest_url_; bool simulated_found_network_namespace_; + FRIEND_TEST(MockAppCacheStorageTest, BasicFindMainResponse); + FRIEND_TEST(MockAppCacheStorageTest, BasicFindMainFallbackResponse); FRIEND_TEST(MockAppCacheStorageTest, CreateGroup); + FRIEND_TEST(MockAppCacheStorageTest, FindMainResponseExclusions); + FRIEND_TEST(MockAppCacheStorageTest, FindMainResponseWithMultipleCandidates); FRIEND_TEST(MockAppCacheStorageTest, LoadCache_FarHit); FRIEND_TEST(MockAppCacheStorageTest, LoadGroupAndCache_FarHit); FRIEND_TEST(MockAppCacheStorageTest, MakeGroupObsolete); diff --git a/webkit/appcache/mock_appcache_storage_unittest.cc b/webkit/appcache/mock_appcache_storage_unittest.cc index 404df50..39fc445 100644 --- a/webkit/appcache/mock_appcache_storage_unittest.cc +++ b/webkit/appcache/mock_appcache_storage_unittest.cc @@ -323,7 +323,7 @@ TEST_F(MockAppCacheStorageTest, MarkEntryAsForeign) { reinterpret_cast<MockAppCacheStorage*>(service.storage()); // Setup some preconditions. Create a cache with an entry. - GURL entry_url("http://blan/entry"); + GURL entry_url("http://blah/entry"); int64 cache_id = storage->NewCacheId(); scoped_refptr<AppCache> cache = new AppCache(&service, cache_id); cache->AddEntry(entry_url, AppCacheEntry(AppCacheEntry::EXPLICIT)); @@ -358,5 +358,211 @@ TEST_F(MockAppCacheStorageTest, FindNoMainResponse) { 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 kCacheId = storage->NewCacheId(); + const GURL kEntryUrl("http://blah/entry"); + const GURL kManifestUrl("http://blah/manifest"); + const int64 kResponseId = 1; + scoped_refptr<AppCache> cache = new AppCache(&service, kCacheId); + cache->AddEntry( + kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT, kResponseId)); + cache->set_complete(true); + scoped_refptr<AppCacheGroup> group = + new AppCacheGroup(&service, kManifestUrl); + group->AddCache(cache); + storage->AddStoredGroup(group); + storage->AddStoredCache(cache); + + // Conduct the test. + MockStorageDelegate delegate; + EXPECT_NE(kEntryUrl, delegate.found_url_); + storage->FindResponseForMainRequest(kEntryUrl, &delegate); + EXPECT_NE(kEntryUrl, delegate.found_url_); + MessageLoop::current()->RunAllPending(); // 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 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 kResponseId1 = 1; + const int64 kResponseId2 = 2; + + Manifest manifest; + manifest.fallback_namespaces.push_back( + FallbackNamespace(kFallbackNamespaceUrl1, kFallbackEntryUrl1)); + manifest.fallback_namespaces.push_back( + FallbackNamespace(kFallbackNamespaceUrl2, kFallbackEntryUrl2)); + + scoped_refptr<AppCache> cache = new AppCache(&service, 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, kManifestUrl); + group->AddCache(cache); + storage->AddStoredGroup(group); + storage->AddStoredCache(cache); + + // 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, &delegate); + EXPECT_NE(kTestUrl, delegate.found_url_); + MessageLoop::current()->RunAllPending(); // 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_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 kCacheId1 = storage->NewCacheId(); + const int64 kCacheId2 = storage->NewCacheId(); + const GURL kManifestUrl1("http://blah/manifest1"); + const GURL kManifestUrl2("http://blah/manifest2"); + const int64 kResponseId1 = 1; + const int64 kResponseId2 = 2; + + // The first cache. + scoped_refptr<AppCache> cache = new AppCache(&service, kCacheId1); + cache->AddEntry( + kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT, kResponseId1)); + cache->set_complete(true); + scoped_refptr<AppCacheGroup> group = + new AppCacheGroup(&service, kManifestUrl1); + group->AddCache(cache); + storage->AddStoredGroup(group); + storage->AddStoredCache(cache); + // Drop our references to cache1 so it appears as "not in use". + cache = NULL; + group = NULL; + + // The second cache. + cache = new AppCache(&service, kCacheId2); + cache->AddEntry( + kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT, kResponseId2)); + cache->set_complete(true); + group = new AppCacheGroup(&service, kManifestUrl2); + group->AddCache(cache); + storage->AddStoredGroup(group); + storage->AddStoredCache(cache); + + // 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, &delegate); + EXPECT_NE(kEntryUrl, delegate.found_url_); + MessageLoop::current()->RunAllPending(); // 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 kCacheId = storage->NewCacheId(); + const GURL kEntryUrl("http://blah/entry"); + const GURL kManifestUrl("http://blah/manifest"); + const GURL kOnlineNamespaceUrl("http://blah/online_namespace"); + const int64 kResponseId = 1; + + Manifest manifest; + manifest.online_whitelist_namespaces.push_back(kOnlineNamespaceUrl); + + scoped_refptr<AppCache> cache = new AppCache(&service, kCacheId); + cache->InitializeWithManifest(&manifest); + cache->AddEntry( + kEntryUrl, + AppCacheEntry(AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN, + kResponseId)); + cache->set_complete(true); + scoped_refptr<AppCacheGroup> group = + new AppCacheGroup(&service, kManifestUrl); + group->AddCache(cache); + storage->AddStoredGroup(group); + storage->AddStoredCache(cache); + + MockStorageDelegate delegate; + + // We should not find anything for the foreign entry. + EXPECT_NE(kEntryUrl, delegate.found_url_); + storage->FindResponseForMainRequest(kEntryUrl, &delegate); + EXPECT_NE(kEntryUrl, delegate.found_url_); + MessageLoop::current()->RunAllPending(); // Do async task execution. + EXPECT_EQ(kEntryUrl, delegate.found_url_); + EXPECT_TRUE(delegate.found_manifest_url_.is_empty()); + EXPECT_EQ(kNoCacheId, delegate.found_cache_id_); + EXPECT_EQ(kNoResponseId, delegate.found_entry_.response_id()); + EXPECT_EQ(kNoResponseId, delegate.found_fallback_entry_.response_id()); + 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, &delegate); + EXPECT_NE(kOnlineNamespaceUrl, delegate.found_url_); + MessageLoop::current()->RunAllPending(); // Do async task execution. + EXPECT_EQ(kOnlineNamespaceUrl, delegate.found_url_); + EXPECT_TRUE(delegate.found_manifest_url_.is_empty()); + EXPECT_EQ(kNoCacheId, delegate.found_cache_id_); + EXPECT_EQ(kNoResponseId, delegate.found_entry_.response_id()); + EXPECT_EQ(kNoResponseId, delegate.found_fallback_entry_.response_id()); + EXPECT_EQ(0, delegate.found_entry_.types()); + EXPECT_EQ(0, delegate.found_fallback_entry_.types()); +} + } // namespace appcache |