|  | // 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. | 
|  |  | 
|  | #ifndef CONTENT_BROWSER_APPCACHE_MOCK_APPCACHE_STORAGE_H_ | 
|  | #define CONTENT_BROWSER_APPCACHE_MOCK_APPCACHE_STORAGE_H_ | 
|  |  | 
|  | #include <stdint.h> | 
|  |  | 
|  | #include <map> | 
|  | #include <memory> | 
|  | #include <vector> | 
|  |  | 
|  | #include "base/callback.h" | 
|  | #include "base/containers/circular_deque.h" | 
|  | #include "base/containers/hash_tables.h" | 
|  | #include "base/gtest_prod_util.h" | 
|  | #include "base/macros.h" | 
|  | #include "base/memory/weak_ptr.h" | 
|  | #include "content/browser/appcache/appcache.h" | 
|  | #include "content/browser/appcache/appcache_disk_cache.h" | 
|  | #include "content/browser/appcache/appcache_group.h" | 
|  | #include "content/browser/appcache/appcache_response.h" | 
|  | #include "content/browser/appcache/appcache_storage.h" | 
|  |  | 
|  | namespace content { | 
|  | FORWARD_DECLARE_TEST(AppCacheServiceImplTest, DeleteAppCachesForOrigin); | 
|  | FORWARD_DECLARE_TEST(MockAppCacheStorageTest, BasicFindMainResponse); | 
|  | FORWARD_DECLARE_TEST(MockAppCacheStorageTest, | 
|  | BasicFindMainFallbackResponse); | 
|  | FORWARD_DECLARE_TEST(MockAppCacheStorageTest, CreateGroup); | 
|  | FORWARD_DECLARE_TEST(MockAppCacheStorageTest, FindMainResponseExclusions); | 
|  | FORWARD_DECLARE_TEST(MockAppCacheStorageTest, | 
|  | FindMainResponseWithMultipleCandidates); | 
|  | FORWARD_DECLARE_TEST(MockAppCacheStorageTest, LoadCache_FarHit); | 
|  | FORWARD_DECLARE_TEST(MockAppCacheStorageTest, LoadGroupAndCache_FarHit); | 
|  | FORWARD_DECLARE_TEST(MockAppCacheStorageTest, MakeGroupObsolete); | 
|  | FORWARD_DECLARE_TEST(MockAppCacheStorageTest, StoreNewGroup); | 
|  | FORWARD_DECLARE_TEST(MockAppCacheStorageTest, StoreExistingGroup); | 
|  | FORWARD_DECLARE_TEST(MockAppCacheStorageTest, | 
|  | StoreExistingGroupExistingCache); | 
|  | class AppCacheRequestHandlerTest; | 
|  | class AppCacheServiceImplTest; | 
|  | class MockAppCacheStorageTest; | 
|  |  | 
|  | namespace appcache_update_job_unittest { | 
|  | class AppCacheUpdateJobTest; | 
|  | } | 
|  |  | 
|  | // For use in unit tests. | 
|  | // Note: This class is also being used to bootstrap our development efforts. | 
|  | // We can get layout tests up and running, and back fill with real storage | 
|  | // somewhat in parallel. | 
|  | class MockAppCacheStorage : public AppCacheStorage { | 
|  | public: | 
|  | explicit MockAppCacheStorage(AppCacheServiceImpl* service); | 
|  | ~MockAppCacheStorage() override; | 
|  |  | 
|  | void GetAllInfo(Delegate* delegate) override; | 
|  | void LoadCache(int64_t id, Delegate* delegate) override; | 
|  | void LoadOrCreateGroup(const GURL& manifest_url, Delegate* delegate) override; | 
|  | void StoreGroupAndNewestCache(AppCacheGroup* group, | 
|  | AppCache* newest_cache, | 
|  | Delegate* delegate) override; | 
|  | void FindResponseForMainRequest(const GURL& url, | 
|  | const GURL& preferred_manifest_url, | 
|  | Delegate* delegate) override; | 
|  | void FindResponseForSubRequest(AppCache* cache, | 
|  | const GURL& url, | 
|  | AppCacheEntry* found_entry, | 
|  | AppCacheEntry* found_fallback_entry, | 
|  | bool* found_network_namespace) override; | 
|  | void MarkEntryAsForeign(const GURL& entry_url, int64_t cache_id) override; | 
|  | void MakeGroupObsolete(AppCacheGroup* group, | 
|  | Delegate* delegate, | 
|  | int response_code) override; | 
|  | void StoreEvictionTimes(AppCacheGroup* group) override; | 
|  | AppCacheResponseReader* CreateResponseReader(const GURL& manifest_url, | 
|  | int64_t response_id) override; | 
|  | AppCacheResponseWriter* CreateResponseWriter( | 
|  | const GURL& manifest_url) override; | 
|  | AppCacheResponseMetadataWriter* CreateResponseMetadataWriter( | 
|  | int64_t response_id) override; | 
|  | void DoomResponses(const GURL& manifest_url, | 
|  | const std::vector<int64_t>& response_ids) override; | 
|  | void DeleteResponses(const GURL& manifest_url, | 
|  | const std::vector<int64_t>& response_ids) override; | 
|  | bool IsInitialized() override; | 
|  |  | 
|  | private: | 
|  | friend class AppCacheRequestHandlerTest; | 
|  | friend class AppCacheServiceImplTest; | 
|  | friend class appcache_update_job_unittest::AppCacheUpdateJobTest; | 
|  | friend class MockAppCacheStorageTest; | 
|  |  | 
|  | using StoredCacheMap = base::hash_map<int64_t, scoped_refptr<AppCache>>; | 
|  | using StoredGroupMap = std::map<GURL, scoped_refptr<AppCacheGroup>>; | 
|  | using DoomedResponseIds = std::set<int64_t>; | 
|  | using StoredEvictionTimesMap = | 
|  | std::map<int64_t, std::pair<base::Time, base::Time>>; | 
|  |  | 
|  | void ProcessGetAllInfo(scoped_refptr<DelegateReference> delegate_ref); | 
|  | void ProcessLoadCache(int64_t id, | 
|  | scoped_refptr<DelegateReference> delegate_ref); | 
|  | void ProcessLoadOrCreateGroup( | 
|  | const GURL& manifest_url, scoped_refptr<DelegateReference> delegate_ref); | 
|  | void ProcessStoreGroupAndNewestCache( | 
|  | scoped_refptr<AppCacheGroup> group, scoped_refptr<AppCache> newest_cache, | 
|  | scoped_refptr<DelegateReference> delegate_ref); | 
|  | void ProcessMakeGroupObsolete(scoped_refptr<AppCacheGroup> group, | 
|  | scoped_refptr<DelegateReference> delegate_ref, | 
|  | int response_code); | 
|  | void ProcessFindResponseForMainRequest( | 
|  | const GURL& url, scoped_refptr<DelegateReference> delegate_ref); | 
|  |  | 
|  | void ScheduleTask(base::OnceClosure task); | 
|  | void RunOnePendingTask(); | 
|  |  | 
|  | void AddStoredCache(AppCache* cache); | 
|  | void RemoveStoredCache(AppCache* cache); | 
|  | void RemoveStoredCaches(const AppCacheGroup::Caches& caches); | 
|  | bool IsCacheStored(const AppCache* cache) { | 
|  | return stored_caches_.find(cache->cache_id()) != stored_caches_.end(); | 
|  | } | 
|  |  | 
|  | void AddStoredGroup(AppCacheGroup* group); | 
|  | void RemoveStoredGroup(AppCacheGroup* group); | 
|  | bool IsGroupStored(const AppCacheGroup* group) { | 
|  | return IsGroupForManifestStored(group->manifest_url()); | 
|  | } | 
|  | bool IsGroupForManifestStored(const GURL& manifest_url) { | 
|  | return stored_groups_.find(manifest_url) != stored_groups_.end(); | 
|  | } | 
|  |  | 
|  | // These helpers determine when certain operations should complete | 
|  | // asynchronously vs synchronously to faithfully mimic, or mock, | 
|  | // the behavior of the real implemenation of the AppCacheStorage | 
|  | // interface. | 
|  | bool ShouldGroupLoadAppearAsync(const AppCacheGroup* group); | 
|  | bool ShouldCacheLoadAppearAsync(const AppCache* cache); | 
|  |  | 
|  | // Lazily constructed in-memory disk cache. | 
|  | AppCacheDiskCache* disk_cache() { | 
|  | if (!disk_cache_) { | 
|  | const int kMaxCacheSize = 10 * 1024 * 1024; | 
|  | disk_cache_.reset(new AppCacheDiskCache); | 
|  | disk_cache_->InitWithMemBackend(kMaxCacheSize, | 
|  | net::CompletionOnceCallback()); | 
|  | } | 
|  | return disk_cache_.get(); | 
|  | } | 
|  |  | 
|  | // Simulate failures for testing. Once set all subsequent calls | 
|  | // to MakeGroupObsolete or StorageGroupAndNewestCache will fail. | 
|  | void SimulateMakeGroupObsoleteFailure() { | 
|  | simulate_make_group_obsolete_failure_ = true; | 
|  | } | 
|  | void SimulateStoreGroupAndNewestCacheFailure() { | 
|  | simulate_store_group_and_newest_cache_failure_ = true; | 
|  | } | 
|  |  | 
|  | // 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 GURL& fallback_url, | 
|  | const AppCacheEntry& fallback_entry, | 
|  | int64_t cache_id, | 
|  | int64_t group_id, | 
|  | const GURL& manifest_url) { | 
|  | simulate_find_main_resource_ = true; | 
|  | simulate_find_sub_resource_ = false; | 
|  | simulated_found_entry_ = entry; | 
|  | simulated_found_fallback_url_ = fallback_url; | 
|  | simulated_found_fallback_entry_ = fallback_entry; | 
|  | simulated_found_cache_id_ = cache_id; | 
|  | simulated_found_group_id_ = group_id; | 
|  | simulated_found_manifest_url_ = manifest_url, | 
|  | simulated_found_network_namespace_ = false;  // N/A to main resource loads | 
|  | } | 
|  | void SimulateFindSubResource( | 
|  | const AppCacheEntry& entry, | 
|  | const AppCacheEntry& fallback_entry, | 
|  | bool network_namespace) { | 
|  | simulate_find_main_resource_ = false; | 
|  | simulate_find_sub_resource_ = true; | 
|  | simulated_found_entry_ = entry; | 
|  | simulated_found_fallback_entry_ = fallback_entry; | 
|  | simulated_found_cache_id_ = kAppCacheNoCacheId; // N/A to sub resource loads | 
|  | simulated_found_manifest_url_ = GURL();  // N/A to sub resource loads | 
|  | simulated_found_group_id_ = 0;  // N/A to sub resource loads | 
|  | simulated_found_network_namespace_ = network_namespace; | 
|  | } | 
|  |  | 
|  | void SimulateGetAllInfo(AppCacheInfoCollection* info) { | 
|  | simulated_appcache_info_ = info; | 
|  | } | 
|  |  | 
|  | void SimulateResponseReader(AppCacheResponseReader* reader) { | 
|  | simulated_reader_.reset(reader); | 
|  | } | 
|  |  | 
|  | StoredCacheMap stored_caches_; | 
|  | StoredGroupMap stored_groups_; | 
|  | StoredEvictionTimesMap stored_eviction_times_; | 
|  | DoomedResponseIds doomed_response_ids_; | 
|  | std::unique_ptr<AppCacheDiskCache> disk_cache_; | 
|  | base::circular_deque<base::OnceClosure> pending_tasks_; | 
|  |  | 
|  | bool simulate_make_group_obsolete_failure_; | 
|  | bool simulate_store_group_and_newest_cache_failure_; | 
|  |  | 
|  | bool simulate_find_main_resource_; | 
|  | bool simulate_find_sub_resource_; | 
|  | AppCacheEntry simulated_found_entry_; | 
|  | AppCacheEntry simulated_found_fallback_entry_; | 
|  | int64_t simulated_found_cache_id_; | 
|  | int64_t simulated_found_group_id_; | 
|  | GURL simulated_found_fallback_url_; | 
|  | GURL simulated_found_manifest_url_; | 
|  | bool simulated_found_network_namespace_; | 
|  | scoped_refptr<AppCacheInfoCollection> simulated_appcache_info_; | 
|  | std::unique_ptr<AppCacheResponseReader> simulated_reader_; | 
|  |  | 
|  | base::WeakPtrFactory<MockAppCacheStorage> weak_factory_; | 
|  |  | 
|  | FRIEND_TEST_ALL_PREFIXES(MockAppCacheStorageTest, | 
|  | BasicFindMainResponse); | 
|  | FRIEND_TEST_ALL_PREFIXES(MockAppCacheStorageTest, | 
|  | BasicFindMainFallbackResponse); | 
|  | FRIEND_TEST_ALL_PREFIXES(MockAppCacheStorageTest, CreateGroup); | 
|  | FRIEND_TEST_ALL_PREFIXES(MockAppCacheStorageTest, | 
|  | FindMainResponseExclusions); | 
|  | FRIEND_TEST_ALL_PREFIXES(MockAppCacheStorageTest, | 
|  | FindMainResponseWithMultipleCandidates); | 
|  | FRIEND_TEST_ALL_PREFIXES(MockAppCacheStorageTest, LoadCache_FarHit); | 
|  | FRIEND_TEST_ALL_PREFIXES(MockAppCacheStorageTest, | 
|  | LoadGroupAndCache_FarHit); | 
|  | FRIEND_TEST_ALL_PREFIXES(MockAppCacheStorageTest, MakeGroupObsolete); | 
|  | FRIEND_TEST_ALL_PREFIXES(MockAppCacheStorageTest, StoreNewGroup); | 
|  | FRIEND_TEST_ALL_PREFIXES(MockAppCacheStorageTest, | 
|  | StoreExistingGroup); | 
|  | FRIEND_TEST_ALL_PREFIXES(MockAppCacheStorageTest, | 
|  | StoreExistingGroupExistingCache); | 
|  | FRIEND_TEST_ALL_PREFIXES(AppCacheServiceImplTest, | 
|  | DeleteAppCachesForOrigin); | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(MockAppCacheStorage); | 
|  | }; | 
|  |  | 
|  | }  // namespace content | 
|  |  | 
|  | #endif  // CONTENT_BROWSER_APPCACHE_MOCK_APPCACHE_STORAGE_H_ |