1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
8 #include "base/bind_helpers.h"
9 #include "base/callback.h"
10 #include "base/file_util.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/synchronization/waitable_event.h"
15 #include "base/threading/thread.h"
16 #include "content/browser/appcache/appcache_interceptor.h"
17 #include "net/base/net_errors.h"
18 #include "net/base/request_priority.h"
19 #include "net/http/http_response_headers.h"
20 #include "net/url_request/url_request_error_job.h"
21 #include "net/url_request/url_request_job_factory_impl.h"
22 #include "net/url_request/url_request_test_job.h"
23 #include "net/url_request/url_request_test_util.h"
24 #include "sql/test/test_helpers.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26 #include "webkit/browser/appcache/appcache.h"
27 #include "webkit/browser/appcache/appcache_backend_impl.h"
28 #include "webkit/browser/appcache/appcache_database.h"
29 #include "webkit/browser/appcache/appcache_entry.h"
30 #include "webkit/browser/appcache/appcache_group.h"
31 #include "webkit/browser/appcache/appcache_host.h"
32 #include "webkit/browser/appcache/appcache_request_handler.h"
33 #include "webkit/browser/appcache/appcache_service_impl.h"
34 #include "webkit/browser/appcache/appcache_storage_impl.h"
35 #include "webkit/browser/quota/quota_manager.h"
37 using appcache::APPCACHE_FALLBACK_NAMESPACE;
38 using appcache::APPCACHE_NETWORK_NAMESPACE;
39 using appcache::AppCacheBackendImpl;
40 using appcache::AppCacheDatabase;
41 using appcache::AppCacheEntry;
42 using appcache::AppCacheFrontend;
43 using appcache::AppCacheHost;
44 using appcache::AppCacheInfo;
45 using appcache::AppCacheGroup;
46 using appcache::AppCacheServiceImpl;
47 using appcache::AppCacheStorage;
48 using appcache::AppCacheStorageImpl;
49 using appcache::AppCacheStorageReference;
50 using appcache::AppCache;
51 using appcache::AppCacheErrorDetails;
52 using appcache::AppCacheEventID;
53 using appcache::kAppCacheNoCacheId;
54 using appcache::kAppCacheNoResponseId;
55 using appcache::APPCACHE_INTERCEPT_NAMESPACE;
56 using appcache::AppCacheLogLevel;
57 using appcache::Namespace;
58 using appcache::AppCacheStatus;
64 const base::Time kZeroTime;
65 const GURL kManifestUrl("http://blah/manifest");
66 const GURL kManifestUrl2("http://blah/manifest2");
67 const GURL kManifestUrl3("http://blah/manifest3");
68 const GURL kEntryUrl("http://blah/entry");
69 const GURL kEntryUrl2("http://blah/entry2");
70 const GURL kFallbackNamespace("http://blah/fallback_namespace/");
71 const GURL kFallbackNamespace2("http://blah/fallback_namespace/longer");
72 const GURL kFallbackTestUrl("http://blah/fallback_namespace/longer/test");
73 const GURL kOnlineNamespace("http://blah/online_namespace");
74 const GURL kOnlineNamespaceWithinFallback(
75 "http://blah/fallback_namespace/online/");
76 const GURL kInterceptNamespace("http://blah/intercept_namespace/");
77 const GURL kInterceptNamespace2("http://blah/intercept_namespace/longer/");
78 const GURL kInterceptTestUrl("http://blah/intercept_namespace/longer/test");
79 const GURL kInterceptPatternNamespace("http://blah/intercept_pattern/*/bar");
80 const GURL kInterceptPatternTestPositiveUrl(
81 "http://blah/intercept_pattern/foo/bar");
82 const GURL kInterceptPatternTestNegativeUrl(
83 "http://blah/intercept_pattern/foo/not_bar");
84 const GURL kFallbackPatternNamespace("http://blah/fallback_pattern/*/bar");
85 const GURL kFallbackPatternTestPositiveUrl(
86 "http://blah/fallback_pattern/foo/bar");
87 const GURL kFallbackPatternTestNegativeUrl(
88 "http://blah/fallback_pattern/foo/not_bar");
89 const GURL kOrigin(kManifestUrl.GetOrigin());
91 const int kManifestEntryIdOffset = 100;
92 const int kFallbackEntryIdOffset = 1000;
94 const GURL kDefaultEntryUrl("http://blah/makecacheandgroup_default_entry");
95 const int kDefaultEntrySize = 10;
96 const int kDefaultEntryIdOffset = 12345;
98 const int kMockQuota = 5000;
100 // The Reinitialize test needs some http accessible resources to run,
101 // we mock stuff inprocess for that.
102 class MockHttpServer {
104 static GURL GetMockUrl(const std::string& path) {
105 return GURL("http://mockhost/" + path);
108 static net::URLRequestJob* CreateJob(
109 net::URLRequest* request, net::NetworkDelegate* network_delegate) {
110 if (request->url().host() != "mockhost")
111 return new net::URLRequestErrorJob(request, network_delegate, -100);
113 std::string headers, body;
114 GetMockResponse(request->url().path(), &headers, &body);
115 return new net::URLRequestTestJob(
116 request, network_delegate, headers, body, true);
120 static void GetMockResponse(const std::string& path,
121 std::string* headers,
123 const char manifest_headers[] =
125 "Content-type: text/cache-manifest\0"
127 const char page_headers[] =
129 "Content-type: text/html\0"
131 const char not_found_headers[] =
132 "HTTP/1.1 404 NOT FOUND\0"
135 if (path == "/manifest") {
136 (*headers) = std::string(manifest_headers, arraysize(manifest_headers));
137 (*body) = "CACHE MANIFEST\n";
138 } else if (path == "/empty.html") {
139 (*headers) = std::string(page_headers, arraysize(page_headers));
142 (*headers) = std::string(not_found_headers,
143 arraysize(not_found_headers));
149 class MockHttpServerJobFactory
150 : public net::URLRequestJobFactory::ProtocolHandler {
152 virtual net::URLRequestJob* MaybeCreateJob(
153 net::URLRequest* request,
154 net::NetworkDelegate* network_delegate) const OVERRIDE {
155 return MockHttpServer::CreateJob(request, network_delegate);
159 class IOThread : public base::Thread {
161 explicit IOThread(const char* name)
162 : base::Thread(name) {
165 virtual ~IOThread() {
169 net::URLRequestContext* request_context() {
170 return request_context_.get();
173 virtual void Init() OVERRIDE {
174 scoped_ptr<net::URLRequestJobFactoryImpl> factory(
175 new net::URLRequestJobFactoryImpl());
176 factory->SetProtocolHandler("http", new MockHttpServerJobFactory);
177 job_factory_ = factory.Pass();
178 request_context_.reset(new net::TestURLRequestContext());
179 request_context_->set_job_factory(job_factory_.get());
180 AppCacheInterceptor::EnsureRegistered();
183 virtual void CleanUp() OVERRIDE {
184 request_context_.reset();
185 job_factory_.reset();
189 scoped_ptr<net::URLRequestJobFactory> job_factory_;
190 scoped_ptr<net::URLRequestContext> request_context_;
193 scoped_ptr<IOThread> io_thread;
194 scoped_ptr<base::Thread> db_thread;
198 class AppCacheStorageImplTest : public testing::Test {
200 class MockStorageDelegate : public AppCacheStorage::Delegate {
202 explicit MockStorageDelegate(AppCacheStorageImplTest* test)
203 : loaded_cache_id_(0), stored_group_success_(false),
204 would_exceed_quota_(false), obsoleted_success_(false),
205 found_cache_id_(kAppCacheNoCacheId), test_(test) {
208 virtual void OnCacheLoaded(AppCache* cache, int64 cache_id) OVERRIDE {
209 loaded_cache_ = cache;
210 loaded_cache_id_ = cache_id;
211 test_->ScheduleNextTask();
214 virtual void OnGroupLoaded(AppCacheGroup* group,
215 const GURL& manifest_url) OVERRIDE {
216 loaded_group_ = group;
217 loaded_manifest_url_ = manifest_url;
218 loaded_groups_newest_cache_ = group ? group->newest_complete_cache()
220 test_->ScheduleNextTask();
223 virtual void OnGroupAndNewestCacheStored(
224 AppCacheGroup* group, AppCache* newest_cache, bool success,
225 bool would_exceed_quota) OVERRIDE {
226 stored_group_ = group;
227 stored_group_success_ = success;
228 would_exceed_quota_ = would_exceed_quota;
229 test_->ScheduleNextTask();
232 virtual void OnGroupMadeObsolete(AppCacheGroup* group,
234 int response_code) OVERRIDE {
235 obsoleted_group_ = group;
236 obsoleted_success_ = success;
237 test_->ScheduleNextTask();
240 virtual void OnMainResponseFound(const GURL& url,
241 const AppCacheEntry& entry,
242 const GURL& namespace_entry_url,
243 const AppCacheEntry& fallback_entry,
246 const GURL& manifest_url) OVERRIDE {
248 found_entry_ = entry;
249 found_namespace_entry_url_ = namespace_entry_url;
250 found_fallback_entry_ = fallback_entry;
251 found_cache_id_ = cache_id;
252 found_group_id_ = group_id;
253 found_manifest_url_ = manifest_url;
254 test_->ScheduleNextTask();
257 scoped_refptr<AppCache> loaded_cache_;
258 int64 loaded_cache_id_;
259 scoped_refptr<AppCacheGroup> loaded_group_;
260 GURL loaded_manifest_url_;
261 scoped_refptr<AppCache> loaded_groups_newest_cache_;
262 scoped_refptr<AppCacheGroup> stored_group_;
263 bool stored_group_success_;
264 bool would_exceed_quota_;
265 scoped_refptr<AppCacheGroup> obsoleted_group_;
266 bool obsoleted_success_;
268 AppCacheEntry found_entry_;
269 GURL found_namespace_entry_url_;
270 AppCacheEntry found_fallback_entry_;
271 int64 found_cache_id_;
272 int64 found_group_id_;
273 GURL found_manifest_url_;
274 AppCacheStorageImplTest* test_;
277 class MockQuotaManager : public quota::QuotaManager {
280 : QuotaManager(true /* is_incognito */,
282 io_thread->message_loop_proxy().get(),
283 db_thread->message_loop_proxy().get(),
287 virtual void GetUsageAndQuota(
289 quota::StorageType type,
290 const GetUsageAndQuotaCallback& callback) OVERRIDE {
291 EXPECT_EQ(quota::kStorageTypeTemporary, type);
293 base::MessageLoop::current()->PostTask(
295 base::Bind(&MockQuotaManager::CallCallback,
296 base::Unretained(this),
300 CallCallback(callback);
303 void CallCallback(const GetUsageAndQuotaCallback& callback) {
304 callback.Run(quota::kQuotaStatusOk, 0, kMockQuota);
310 virtual ~MockQuotaManager() {}
313 class MockQuotaManagerProxy : public quota::QuotaManagerProxy {
315 MockQuotaManagerProxy()
316 : QuotaManagerProxy(NULL, NULL),
317 notify_storage_accessed_count_(0),
318 notify_storage_modified_count_(0),
320 mock_manager_(new MockQuotaManager) {
321 manager_ = mock_manager_.get();
324 virtual void NotifyStorageAccessed(quota::QuotaClient::ID client_id,
326 quota::StorageType type) OVERRIDE {
327 EXPECT_EQ(quota::QuotaClient::kAppcache, client_id);
328 EXPECT_EQ(quota::kStorageTypeTemporary, type);
329 ++notify_storage_accessed_count_;
330 last_origin_ = origin;
333 virtual void NotifyStorageModified(quota::QuotaClient::ID client_id,
335 quota::StorageType type,
336 int64 delta) OVERRIDE {
337 EXPECT_EQ(quota::QuotaClient::kAppcache, client_id);
338 EXPECT_EQ(quota::kStorageTypeTemporary, type);
339 ++notify_storage_modified_count_;
340 last_origin_ = origin;
344 // Not needed for our tests.
345 virtual void RegisterClient(quota::QuotaClient* client) OVERRIDE {}
346 virtual void NotifyOriginInUse(const GURL& origin) OVERRIDE {}
347 virtual void NotifyOriginNoLongerInUse(const GURL& origin) OVERRIDE {}
348 virtual void SetUsageCacheEnabled(quota::QuotaClient::ID client_id,
350 quota::StorageType type,
351 bool enabled) OVERRIDE {}
352 virtual void GetUsageAndQuota(
353 base::SequencedTaskRunner* original_task_runner,
355 quota::StorageType type,
356 const GetUsageAndQuotaCallback& callback) OVERRIDE {}
358 int notify_storage_accessed_count_;
359 int notify_storage_modified_count_;
362 scoped_refptr<MockQuotaManager> mock_manager_;
365 virtual ~MockQuotaManagerProxy() {}
368 template <class Method>
369 void RunMethod(Method method) {
373 // Helper callback to run a test on our io_thread. The io_thread is spun up
374 // once and reused for all tests.
375 template <class Method>
376 void MethodWrapper(Method method) {
379 // Ensure InitTask execution prior to conducting a test.
380 FlushDbThreadTasks();
382 // We also have to wait for InitTask completion call to be performed
383 // on the IO thread prior to running the test. Its guaranteed to be
384 // queued by this time.
385 base::MessageLoop::current()->PostTask(
387 base::Bind(&AppCacheStorageImplTest::RunMethod<Method>,
388 base::Unretained(this),
392 static void SetUpTestCase() {
393 // We start both threads as TYPE_IO because we also use the db_thead
394 // for the disk_cache which needs to be of TYPE_IO.
395 base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
396 io_thread.reset(new IOThread("AppCacheTest.IOThread"));
397 ASSERT_TRUE(io_thread->StartWithOptions(options));
398 db_thread.reset(new base::Thread("AppCacheTest::DBThread"));
399 ASSERT_TRUE(db_thread->StartWithOptions(options));
402 static void TearDownTestCase() {
403 io_thread.reset(NULL);
404 db_thread.reset(NULL);
407 // Test harness --------------------------------------------------
409 AppCacheStorageImplTest() {
412 template <class Method>
413 void RunTestOnIOThread(Method method) {
414 test_finished_event_ .reset(new base::WaitableEvent(false, false));
415 io_thread->message_loop()->PostTask(
416 FROM_HERE, base::Bind(&AppCacheStorageImplTest::MethodWrapper<Method>,
417 base::Unretained(this), method));
418 test_finished_event_->Wait();
422 DCHECK(base::MessageLoop::current() == io_thread->message_loop());
423 service_.reset(new AppCacheServiceImpl(NULL));
424 service_->Initialize(
425 base::FilePath(), db_thread->message_loop_proxy().get(), NULL);
426 mock_quota_manager_proxy_ = new MockQuotaManagerProxy();
427 service_->quota_manager_proxy_ = mock_quota_manager_proxy_;
428 delegate_.reset(new MockStorageDelegate(this));
431 void TearDownTest() {
432 DCHECK(base::MessageLoop::current() == io_thread->message_loop());
433 storage()->CancelDelegateCallbacks(delegate());
437 mock_quota_manager_proxy_ = NULL;
440 FlushDbThreadTasks();
443 void TestFinished() {
444 // We unwind the stack prior to finishing up to let stack
445 // based objects get deleted.
446 DCHECK(base::MessageLoop::current() == io_thread->message_loop());
447 base::MessageLoop::current()->PostTask(
449 base::Bind(&AppCacheStorageImplTest::TestFinishedUnwound,
450 base::Unretained(this)));
453 void TestFinishedUnwound() {
455 test_finished_event_->Signal();
458 void PushNextTask(const base::Closure& task) {
459 task_stack_.push(task);
462 void ScheduleNextTask() {
463 DCHECK(base::MessageLoop::current() == io_thread->message_loop());
464 if (task_stack_.empty()) {
467 base::MessageLoop::current()->PostTask(FROM_HERE, task_stack_.top());
471 static void SignalEvent(base::WaitableEvent* event) {
475 void FlushDbThreadTasks() {
476 // We pump a task thru the db thread to ensure any tasks previously
477 // scheduled on that thread have been performed prior to return.
478 base::WaitableEvent event(false, false);
479 db_thread->message_loop()->PostTask(
480 FROM_HERE, base::Bind(&AppCacheStorageImplTest::SignalEvent, &event));
484 // LoadCache_Miss ----------------------------------------------------
486 void LoadCache_Miss() {
487 // Attempt to load a cache that doesn't exist. Should
488 // complete asynchronously.
489 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_LoadCache_Miss,
490 base::Unretained(this)));
492 storage()->LoadCache(111, delegate());
493 EXPECT_NE(111, delegate()->loaded_cache_id_);
496 void Verify_LoadCache_Miss() {
497 EXPECT_EQ(111, delegate()->loaded_cache_id_);
498 EXPECT_FALSE(delegate()->loaded_cache_.get());
499 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_accessed_count_);
500 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
504 // LoadCache_NearHit -------------------------------------------------
506 void LoadCache_NearHit() {
507 // Attempt to load a cache that is currently in use
508 // and does not require loading from storage. This
509 // load should complete syncly.
511 // Setup some preconditions. Make an 'unstored' cache for
512 // us to load. The ctor should put it in the working set.
513 int64 cache_id = storage()->NewCacheId();
514 scoped_refptr<AppCache> cache(new AppCache(storage(), cache_id));
517 storage()->LoadCache(cache_id, delegate());
518 EXPECT_EQ(cache_id, delegate()->loaded_cache_id_);
519 EXPECT_EQ(cache.get(), delegate()->loaded_cache_.get());
520 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_accessed_count_);
521 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
525 // CreateGroup --------------------------------------------
527 void CreateGroupInEmptyOrigin() {
528 // Attempt to load a group that doesn't exist, one should
529 // be created for us, but not stored.
531 // Since the origin has no groups, the storage class will respond
533 storage()->LoadOrCreateGroup(kManifestUrl, delegate());
534 Verify_CreateGroup();
537 void CreateGroupInPopulatedOrigin() {
538 // Attempt to load a group that doesn't exist, one should
539 // be created for us, but not stored.
540 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_CreateGroup,
541 base::Unretained(this)));
543 // Since the origin has groups, storage class will have to
544 // consult the database and completion will be async.
545 storage()->usage_map_[kOrigin] = kDefaultEntrySize;
547 storage()->LoadOrCreateGroup(kManifestUrl, delegate());
548 EXPECT_FALSE(delegate()->loaded_group_.get());
551 void Verify_CreateGroup() {
552 EXPECT_EQ(kManifestUrl, delegate()->loaded_manifest_url_);
553 EXPECT_TRUE(delegate()->loaded_group_.get());
554 EXPECT_TRUE(delegate()->loaded_group_->HasOneRef());
555 EXPECT_FALSE(delegate()->loaded_group_->newest_complete_cache());
557 // Should not have been stored in the database.
558 AppCacheDatabase::GroupRecord record;
559 EXPECT_FALSE(database()->FindGroup(
560 delegate()->loaded_group_->group_id(), &record));
562 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_accessed_count_);
563 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
568 // LoadGroupAndCache_FarHit --------------------------------------
570 void LoadGroupAndCache_FarHit() {
571 // Attempt to load a cache that is not currently in use
572 // and does require loading from disk. This
573 // load should complete asynchronously.
574 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_LoadCache_Far_Hit,
575 base::Unretained(this)));
577 // Setup some preconditions. Create a group and newest cache that
578 // appear to be "stored" and "not currently in use".
579 MakeCacheAndGroup(kManifestUrl, 1, 1, true);
583 // Conduct the cache load test, completes async
584 storage()->LoadCache(1, delegate());
587 void Verify_LoadCache_Far_Hit() {
588 EXPECT_TRUE(delegate()->loaded_cache_.get());
589 EXPECT_TRUE(delegate()->loaded_cache_->HasOneRef());
590 EXPECT_EQ(1, delegate()->loaded_cache_id_);
592 // The group should also have been loaded.
593 EXPECT_TRUE(delegate()->loaded_cache_->owning_group());
594 EXPECT_TRUE(delegate()->loaded_cache_->owning_group()->HasOneRef());
595 EXPECT_EQ(1, delegate()->loaded_cache_->owning_group()->group_id());
597 EXPECT_EQ(1, mock_quota_manager_proxy_->notify_storage_accessed_count_);
598 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
600 // Drop things from the working set.
601 delegate()->loaded_cache_ = NULL;
602 EXPECT_FALSE(delegate()->loaded_group_.get());
604 // Conduct the group load test, also complete asynchronously.
605 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_LoadGroup_Far_Hit,
606 base::Unretained(this)));
608 storage()->LoadOrCreateGroup(kManifestUrl, delegate());
611 void Verify_LoadGroup_Far_Hit() {
612 EXPECT_TRUE(delegate()->loaded_group_.get());
613 EXPECT_EQ(kManifestUrl, delegate()->loaded_manifest_url_);
614 EXPECT_TRUE(delegate()->loaded_group_->newest_complete_cache());
615 delegate()->loaded_groups_newest_cache_ = NULL;
616 EXPECT_TRUE(delegate()->loaded_group_->HasOneRef());
617 EXPECT_EQ(2, mock_quota_manager_proxy_->notify_storage_accessed_count_);
618 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
622 // StoreNewGroup --------------------------------------
624 void StoreNewGroup() {
625 // Store a group and its newest cache. Should complete asynchronously.
626 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_StoreNewGroup,
627 base::Unretained(this)));
629 // Setup some preconditions. Create a group and newest cache that
630 // appear to be "unstored".
631 group_ = new AppCacheGroup(
632 storage(), kManifestUrl, storage()->NewGroupId());
633 cache_ = new AppCache(storage(), storage()->NewCacheId());
634 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT, 1,
636 // Hold a ref to the cache simulate the UpdateJob holding that ref,
637 // and hold a ref to the group to simulate the CacheHost holding that ref.
639 // Have the quota manager retrun asynchronously for this test.
640 mock_quota_manager_proxy_->mock_manager_->async_ = true;
642 // Conduct the store test.
643 storage()->StoreGroupAndNewestCache(group_.get(), cache_.get(), delegate());
644 EXPECT_FALSE(delegate()->stored_group_success_);
647 void Verify_StoreNewGroup() {
648 EXPECT_TRUE(delegate()->stored_group_success_);
649 EXPECT_EQ(group_.get(), delegate()->stored_group_.get());
650 EXPECT_EQ(cache_.get(), group_->newest_complete_cache());
651 EXPECT_TRUE(cache_->is_complete());
653 // Should have been stored in the database.
654 AppCacheDatabase::GroupRecord group_record;
655 AppCacheDatabase::CacheRecord cache_record;
656 EXPECT_TRUE(database()->FindGroup(group_->group_id(), &group_record));
657 EXPECT_TRUE(database()->FindCache(cache_->cache_id(), &cache_record));
659 // Verify quota bookkeeping
660 EXPECT_EQ(kDefaultEntrySize, storage()->usage_map_[kOrigin]);
661 EXPECT_EQ(1, mock_quota_manager_proxy_->notify_storage_modified_count_);
662 EXPECT_EQ(kOrigin, mock_quota_manager_proxy_->last_origin_);
663 EXPECT_EQ(kDefaultEntrySize, mock_quota_manager_proxy_->last_delta_);
668 // StoreExistingGroup --------------------------------------
670 void StoreExistingGroup() {
671 // Store a group and its newest cache. Should complete asynchronously.
672 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_StoreExistingGroup,
673 base::Unretained(this)));
675 // Setup some preconditions. Create a group and old complete cache
676 // that appear to be "stored"
677 MakeCacheAndGroup(kManifestUrl, 1, 1, true);
678 EXPECT_EQ(kDefaultEntrySize, storage()->usage_map_[kOrigin]);
680 // And a newest unstored complete cache.
681 cache2_ = new AppCache(storage(), 2);
682 cache2_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::MASTER, 1,
683 kDefaultEntrySize + 100));
686 storage()->StoreGroupAndNewestCache(
687 group_.get(), cache2_.get(), delegate());
688 EXPECT_FALSE(delegate()->stored_group_success_);
691 void Verify_StoreExistingGroup() {
692 EXPECT_TRUE(delegate()->stored_group_success_);
693 EXPECT_EQ(group_.get(), delegate()->stored_group_.get());
694 EXPECT_EQ(cache2_.get(), group_->newest_complete_cache());
695 EXPECT_TRUE(cache2_->is_complete());
697 // The new cache should have been stored in the database.
698 AppCacheDatabase::GroupRecord group_record;
699 AppCacheDatabase::CacheRecord cache_record;
700 EXPECT_TRUE(database()->FindGroup(1, &group_record));
701 EXPECT_TRUE(database()->FindCache(2, &cache_record));
703 // The old cache should have been deleted
704 EXPECT_FALSE(database()->FindCache(1, &cache_record));
706 // Verify quota bookkeeping
707 EXPECT_EQ(kDefaultEntrySize + 100, storage()->usage_map_[kOrigin]);
708 EXPECT_EQ(1, mock_quota_manager_proxy_->notify_storage_modified_count_);
709 EXPECT_EQ(kOrigin, mock_quota_manager_proxy_->last_origin_);
710 EXPECT_EQ(100, mock_quota_manager_proxy_->last_delta_);
715 // StoreExistingGroupExistingCache -------------------------------
717 void StoreExistingGroupExistingCache() {
718 // Store a group with updates to its existing newest complete cache.
719 // Setup some preconditions. Create a group and a complete cache that
720 // appear to be "stored".
722 // Setup some preconditions. Create a group and old complete cache
723 // that appear to be "stored"
724 MakeCacheAndGroup(kManifestUrl, 1, 1, true);
725 EXPECT_EQ(kDefaultEntrySize, storage()->usage_map_[kOrigin]);
728 base::Time now = base::Time::Now();
729 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::MASTER, 1, 100));
730 cache_->set_update_time(now);
732 PushNextTask(base::Bind(
733 &AppCacheStorageImplTest::Verify_StoreExistingGroupExistingCache,
734 base::Unretained(this), now));
737 EXPECT_EQ(cache_, group_->newest_complete_cache());
738 storage()->StoreGroupAndNewestCache(group_.get(), cache_.get(), delegate());
739 EXPECT_FALSE(delegate()->stored_group_success_);
742 void Verify_StoreExistingGroupExistingCache(
743 base::Time expected_update_time) {
744 EXPECT_TRUE(delegate()->stored_group_success_);
745 EXPECT_EQ(cache_, group_->newest_complete_cache());
747 AppCacheDatabase::CacheRecord cache_record;
748 EXPECT_TRUE(database()->FindCache(1, &cache_record));
749 EXPECT_EQ(1, cache_record.cache_id);
750 EXPECT_EQ(1, cache_record.group_id);
751 EXPECT_FALSE(cache_record.online_wildcard);
752 EXPECT_TRUE(expected_update_time == cache_record.update_time);
753 EXPECT_EQ(100 + kDefaultEntrySize, cache_record.cache_size);
755 std::vector<AppCacheDatabase::EntryRecord> entry_records;
756 EXPECT_TRUE(database()->FindEntriesForCache(1, &entry_records));
757 EXPECT_EQ(2U, entry_records.size());
758 if (entry_records[0].url == kDefaultEntryUrl)
759 entry_records.erase(entry_records.begin());
760 EXPECT_EQ(1 , entry_records[0].cache_id);
761 EXPECT_EQ(kEntryUrl, entry_records[0].url);
762 EXPECT_EQ(AppCacheEntry::MASTER, entry_records[0].flags);
763 EXPECT_EQ(1, entry_records[0].response_id);
764 EXPECT_EQ(100, entry_records[0].response_size);
766 // Verify quota bookkeeping
767 EXPECT_EQ(100 + kDefaultEntrySize, storage()->usage_map_[kOrigin]);
768 EXPECT_EQ(1, mock_quota_manager_proxy_->notify_storage_modified_count_);
769 EXPECT_EQ(kOrigin, mock_quota_manager_proxy_->last_origin_);
770 EXPECT_EQ(100, mock_quota_manager_proxy_->last_delta_);
775 // FailStoreGroup --------------------------------------
777 void FailStoreGroup() {
778 // Store a group and its newest cache. Should complete asynchronously.
779 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_FailStoreGroup,
780 base::Unretained(this)));
782 // Setup some preconditions. Create a group and newest cache that
783 // appear to be "unstored" and big enough to exceed the 5M limit.
784 const int64 kTooBig = 10 * 1024 * 1024; // 10M
785 group_ = new AppCacheGroup(
786 storage(), kManifestUrl, storage()->NewGroupId());
787 cache_ = new AppCache(storage(), storage()->NewCacheId());
788 cache_->AddEntry(kManifestUrl,
789 AppCacheEntry(AppCacheEntry::MANIFEST, 1, kTooBig));
790 // Hold a ref to the cache simulate the UpdateJob holding that ref,
791 // and hold a ref to the group to simulate the CacheHost holding that ref.
793 // Conduct the store test.
794 storage()->StoreGroupAndNewestCache(group_.get(), cache_.get(), delegate());
795 EXPECT_FALSE(delegate()->stored_group_success_); // Expected to be async.
798 void Verify_FailStoreGroup() {
799 EXPECT_FALSE(delegate()->stored_group_success_);
800 EXPECT_TRUE(delegate()->would_exceed_quota_);
802 // Should not have been stored in the database.
803 AppCacheDatabase::GroupRecord group_record;
804 AppCacheDatabase::CacheRecord cache_record;
805 EXPECT_FALSE(database()->FindGroup(group_->group_id(), &group_record));
806 EXPECT_FALSE(database()->FindCache(cache_->cache_id(), &cache_record));
808 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_accessed_count_);
809 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
814 // MakeGroupObsolete -------------------------------
816 void MakeGroupObsolete() {
817 // Make a group obsolete, should complete asynchronously.
818 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_MakeGroupObsolete,
819 base::Unretained(this)));
821 // Setup some preconditions. Create a group and newest cache that
822 // appears to be "stored" and "currently in use".
823 MakeCacheAndGroup(kManifestUrl, 1, 1, true);
824 EXPECT_EQ(kDefaultEntrySize, storage()->usage_map_[kOrigin]);
826 // Also insert some related records.
827 AppCacheDatabase::EntryRecord entry_record;
828 entry_record.cache_id = 1;
829 entry_record.flags = AppCacheEntry::FALLBACK;
830 entry_record.response_id = 1;
831 entry_record.url = kEntryUrl;
832 EXPECT_TRUE(database()->InsertEntry(&entry_record));
834 AppCacheDatabase::NamespaceRecord fallback_namespace_record;
835 fallback_namespace_record.cache_id = 1;
836 fallback_namespace_record.namespace_.target_url = kEntryUrl;
837 fallback_namespace_record.namespace_.namespace_url = kFallbackNamespace;
838 fallback_namespace_record.origin = kManifestUrl.GetOrigin();
839 EXPECT_TRUE(database()->InsertNamespace(&fallback_namespace_record));
841 AppCacheDatabase::OnlineWhiteListRecord online_whitelist_record;
842 online_whitelist_record.cache_id = 1;
843 online_whitelist_record.namespace_url = kOnlineNamespace;
844 EXPECT_TRUE(database()->InsertOnlineWhiteList(&online_whitelist_record));
847 storage()->MakeGroupObsolete(group_.get(), delegate(), 0);
848 EXPECT_FALSE(group_->is_obsolete());
851 void Verify_MakeGroupObsolete() {
852 EXPECT_TRUE(delegate()->obsoleted_success_);
853 EXPECT_EQ(group_.get(), delegate()->obsoleted_group_.get());
854 EXPECT_TRUE(group_->is_obsolete());
855 EXPECT_TRUE(storage()->usage_map_.empty());
857 // The cache and group have been deleted from the database.
858 AppCacheDatabase::GroupRecord group_record;
859 AppCacheDatabase::CacheRecord cache_record;
860 EXPECT_FALSE(database()->FindGroup(1, &group_record));
861 EXPECT_FALSE(database()->FindCache(1, &cache_record));
863 // The related records should have been deleted too.
864 std::vector<AppCacheDatabase::EntryRecord> entry_records;
865 database()->FindEntriesForCache(1, &entry_records);
866 EXPECT_TRUE(entry_records.empty());
867 std::vector<AppCacheDatabase::NamespaceRecord> intercept_records;
868 std::vector<AppCacheDatabase::NamespaceRecord> fallback_records;
869 database()->FindNamespacesForCache(
870 1, &intercept_records, &fallback_records);
871 EXPECT_TRUE(fallback_records.empty());
872 std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelist_records;
873 database()->FindOnlineWhiteListForCache(1, &whitelist_records);
874 EXPECT_TRUE(whitelist_records.empty());
876 // Verify quota bookkeeping
877 EXPECT_TRUE(storage()->usage_map_.empty());
878 EXPECT_EQ(1, mock_quota_manager_proxy_->notify_storage_modified_count_);
879 EXPECT_EQ(kOrigin, mock_quota_manager_proxy_->last_origin_);
880 EXPECT_EQ(-kDefaultEntrySize, mock_quota_manager_proxy_->last_delta_);
885 // MarkEntryAsForeign -------------------------------
887 void MarkEntryAsForeign() {
888 // Setup some preconditions. Create a cache with an entry
889 // in storage and in the working set.
890 MakeCacheAndGroup(kManifestUrl, 1, 1, true);
891 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT));
892 AppCacheDatabase::EntryRecord entry_record;
893 entry_record.cache_id = 1;
894 entry_record.url = kEntryUrl;
895 entry_record.flags = AppCacheEntry::EXPLICIT;
896 entry_record.response_id = 0;
897 EXPECT_TRUE(database()->InsertEntry(&entry_record));
898 EXPECT_FALSE(cache_->GetEntry(kEntryUrl)->IsForeign());
901 storage()->MarkEntryAsForeign(kEntryUrl, 1);
903 // The entry in the working set should have been updated syncly.
904 EXPECT_TRUE(cache_->GetEntry(kEntryUrl)->IsForeign());
905 EXPECT_TRUE(cache_->GetEntry(kEntryUrl)->IsExplicit());
907 // And the entry in storage should also be updated, but that
908 // happens asynchronously on the db thread.
909 FlushDbThreadTasks();
910 AppCacheDatabase::EntryRecord entry_record2;
911 EXPECT_TRUE(database()->FindEntry(1, kEntryUrl, &entry_record2));
912 EXPECT_EQ(AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN,
913 entry_record2.flags);
917 // MarkEntryAsForeignWithLoadInProgress -------------------------------
919 void MarkEntryAsForeignWithLoadInProgress() {
920 PushNextTask(base::Bind(
921 &AppCacheStorageImplTest::Verify_MarkEntryAsForeignWithLoadInProgress,
922 base::Unretained(this)));
924 // Setup some preconditions. Create a cache with an entry
925 // in storage, but not in the working set.
926 MakeCacheAndGroup(kManifestUrl, 1, 1, true);
927 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT));
928 AppCacheDatabase::EntryRecord entry_record;
929 entry_record.cache_id = 1;
930 entry_record.url = kEntryUrl;
931 entry_record.flags = AppCacheEntry::EXPLICIT;
932 entry_record.response_id = 0;
933 EXPECT_TRUE(database()->InsertEntry(&entry_record));
934 EXPECT_FALSE(cache_->GetEntry(kEntryUrl)->IsForeign());
935 EXPECT_TRUE(cache_->HasOneRef());
939 // Conduct the test, start a cache load, and prior to completion
940 // of that load, mark the entry as foreign.
941 storage()->LoadCache(1, delegate());
942 storage()->MarkEntryAsForeign(kEntryUrl, 1);
945 void Verify_MarkEntryAsForeignWithLoadInProgress() {
946 EXPECT_EQ(1, delegate()->loaded_cache_id_);
947 EXPECT_TRUE(delegate()->loaded_cache_.get());
949 // The entry in the working set should have been updated upon load.
950 EXPECT_TRUE(delegate()->loaded_cache_->GetEntry(kEntryUrl)->IsForeign());
951 EXPECT_TRUE(delegate()->loaded_cache_->GetEntry(kEntryUrl)->IsExplicit());
953 // And the entry in storage should also be updated.
954 FlushDbThreadTasks();
955 AppCacheDatabase::EntryRecord entry_record;
956 EXPECT_TRUE(database()->FindEntry(1, kEntryUrl, &entry_record));
957 EXPECT_EQ(AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN,
962 // FindNoMainResponse -------------------------------
964 void FindNoMainResponse() {
965 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_FindNoMainResponse,
966 base::Unretained(this)));
969 storage()->FindResponseForMainRequest(kEntryUrl, GURL(), delegate());
970 EXPECT_NE(kEntryUrl, delegate()->found_url_);
973 void Verify_FindNoMainResponse() {
974 EXPECT_EQ(kEntryUrl, delegate()->found_url_);
975 EXPECT_TRUE(delegate()->found_manifest_url_.is_empty());
976 EXPECT_EQ(kAppCacheNoCacheId, delegate()->found_cache_id_);
977 EXPECT_EQ(kAppCacheNoResponseId, delegate()->found_entry_.response_id());
978 EXPECT_EQ(kAppCacheNoResponseId,
979 delegate()->found_fallback_entry_.response_id());
980 EXPECT_TRUE(delegate()->found_namespace_entry_url_.is_empty());
981 EXPECT_EQ(0, delegate()->found_entry_.types());
982 EXPECT_EQ(0, delegate()->found_fallback_entry_.types());
986 // BasicFindMainResponse -------------------------------
988 void BasicFindMainResponseInDatabase() {
989 BasicFindMainResponse(true);
992 void BasicFindMainResponseInWorkingSet() {
993 BasicFindMainResponse(false);
996 void BasicFindMainResponse(bool drop_from_working_set) {
997 PushNextTask(base::Bind(
998 &AppCacheStorageImplTest::Verify_BasicFindMainResponse,
999 base::Unretained(this)));
1001 // Setup some preconditions. Create a complete cache with an entry
1003 MakeCacheAndGroup(kManifestUrl, 2, 1, true);
1004 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT, 1));
1005 AppCacheDatabase::EntryRecord entry_record;
1006 entry_record.cache_id = 1;
1007 entry_record.url = kEntryUrl;
1008 entry_record.flags = AppCacheEntry::EXPLICIT;
1009 entry_record.response_id = 1;
1010 EXPECT_TRUE(database()->InsertEntry(&entry_record));
1012 // Optionally drop the cache/group pair from the working set.
1013 if (drop_from_working_set) {
1014 EXPECT_TRUE(cache_->HasOneRef());
1016 EXPECT_TRUE(group_->HasOneRef());
1020 // Conduct the test.
1021 storage()->FindResponseForMainRequest(kEntryUrl, GURL(), delegate());
1022 EXPECT_NE(kEntryUrl, delegate()->found_url_);
1025 void Verify_BasicFindMainResponse() {
1026 EXPECT_EQ(kEntryUrl, delegate()->found_url_);
1027 EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
1028 EXPECT_EQ(1, delegate()->found_cache_id_);
1029 EXPECT_EQ(2, delegate()->found_group_id_);
1030 EXPECT_EQ(1, delegate()->found_entry_.response_id());
1031 EXPECT_TRUE(delegate()->found_entry_.IsExplicit());
1032 EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
1036 // BasicFindMainFallbackResponse -------------------------------
1038 void BasicFindMainFallbackResponseInDatabase() {
1039 BasicFindMainFallbackResponse(true);
1042 void BasicFindMainFallbackResponseInWorkingSet() {
1043 BasicFindMainFallbackResponse(false);
1046 void BasicFindMainFallbackResponse(bool drop_from_working_set) {
1047 PushNextTask(base::Bind(
1048 &AppCacheStorageImplTest::Verify_BasicFindMainFallbackResponse,
1049 base::Unretained(this)));
1051 // Setup some preconditions. Create a complete cache with a
1052 // fallback namespace and entry.
1053 MakeCacheAndGroup(kManifestUrl, 2, 1, true);
1054 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::FALLBACK, 1));
1055 cache_->AddEntry(kEntryUrl2, AppCacheEntry(AppCacheEntry::FALLBACK, 2));
1056 cache_->fallback_namespaces_.push_back(
1057 Namespace(APPCACHE_FALLBACK_NAMESPACE,
1058 kFallbackNamespace2,
1061 cache_->fallback_namespaces_.push_back(
1062 Namespace(APPCACHE_FALLBACK_NAMESPACE,
1066 AppCacheDatabase::CacheRecord cache_record;
1067 std::vector<AppCacheDatabase::EntryRecord> entries;
1068 std::vector<AppCacheDatabase::NamespaceRecord> intercepts;
1069 std::vector<AppCacheDatabase::NamespaceRecord> fallbacks;
1070 std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists;
1071 cache_->ToDatabaseRecords(group_.get(),
1078 std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter =
1080 while (iter != entries.end()) {
1081 // MakeCacheAndGroup has inserted the default entry record already.
1082 if (iter->url != kDefaultEntryUrl)
1083 EXPECT_TRUE(database()->InsertEntry(&(*iter)));
1087 EXPECT_TRUE(database()->InsertNamespaceRecords(fallbacks));
1088 EXPECT_TRUE(database()->InsertOnlineWhiteListRecords(whitelists));
1089 if (drop_from_working_set) {
1090 EXPECT_TRUE(cache_->HasOneRef());
1092 EXPECT_TRUE(group_->HasOneRef());
1096 // Conduct the test. The test url is in both fallback namespace urls,
1097 // but should match the longer of the two.
1098 storage()->FindResponseForMainRequest(kFallbackTestUrl, GURL(), delegate());
1099 EXPECT_NE(kFallbackTestUrl, delegate()->found_url_);
1102 void Verify_BasicFindMainFallbackResponse() {
1103 EXPECT_EQ(kFallbackTestUrl, delegate()->found_url_);
1104 EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
1105 EXPECT_EQ(1, delegate()->found_cache_id_);
1106 EXPECT_EQ(2, delegate()->found_group_id_);
1107 EXPECT_FALSE(delegate()->found_entry_.has_response_id());
1108 EXPECT_EQ(2, delegate()->found_fallback_entry_.response_id());
1109 EXPECT_EQ(kEntryUrl2, delegate()->found_namespace_entry_url_);
1110 EXPECT_TRUE(delegate()->found_fallback_entry_.IsFallback());
1114 // BasicFindMainInterceptResponse -------------------------------
1116 void BasicFindMainInterceptResponseInDatabase() {
1117 BasicFindMainInterceptResponse(true);
1120 void BasicFindMainInterceptResponseInWorkingSet() {
1121 BasicFindMainInterceptResponse(false);
1124 void BasicFindMainInterceptResponse(bool drop_from_working_set) {
1125 PushNextTask(base::Bind(
1126 &AppCacheStorageImplTest::Verify_BasicFindMainInterceptResponse,
1127 base::Unretained(this)));
1129 // Setup some preconditions. Create a complete cache with an
1130 // intercept namespace and entry.
1131 MakeCacheAndGroup(kManifestUrl, 2, 1, true);
1132 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::INTERCEPT, 1));
1133 cache_->AddEntry(kEntryUrl2, AppCacheEntry(AppCacheEntry::INTERCEPT, 2));
1134 cache_->intercept_namespaces_.push_back(
1135 Namespace(APPCACHE_INTERCEPT_NAMESPACE, kInterceptNamespace2,
1136 kEntryUrl2, false));
1137 cache_->intercept_namespaces_.push_back(
1138 Namespace(APPCACHE_INTERCEPT_NAMESPACE, kInterceptNamespace,
1140 AppCacheDatabase::CacheRecord cache_record;
1141 std::vector<AppCacheDatabase::EntryRecord> entries;
1142 std::vector<AppCacheDatabase::NamespaceRecord> intercepts;
1143 std::vector<AppCacheDatabase::NamespaceRecord> fallbacks;
1144 std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists;
1145 cache_->ToDatabaseRecords(group_.get(),
1152 std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter =
1154 while (iter != entries.end()) {
1155 // MakeCacheAndGroup has inserted the default entry record already
1156 if (iter->url != kDefaultEntryUrl)
1157 EXPECT_TRUE(database()->InsertEntry(&(*iter)));
1161 EXPECT_TRUE(database()->InsertNamespaceRecords(intercepts));
1162 EXPECT_TRUE(database()->InsertOnlineWhiteListRecords(whitelists));
1163 if (drop_from_working_set) {
1164 EXPECT_TRUE(cache_->HasOneRef());
1166 EXPECT_TRUE(group_->HasOneRef());
1170 // Conduct the test. The test url is in both intercept namespaces,
1171 // but should match the longer of the two.
1172 storage()->FindResponseForMainRequest(
1173 kInterceptTestUrl, GURL(), delegate());
1174 EXPECT_NE(kInterceptTestUrl, delegate()->found_url_);
1177 void Verify_BasicFindMainInterceptResponse() {
1178 EXPECT_EQ(kInterceptTestUrl, delegate()->found_url_);
1179 EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
1180 EXPECT_EQ(1, delegate()->found_cache_id_);
1181 EXPECT_EQ(2, delegate()->found_group_id_);
1182 EXPECT_EQ(2, delegate()->found_entry_.response_id());
1183 EXPECT_TRUE(delegate()->found_entry_.IsIntercept());
1184 EXPECT_EQ(kEntryUrl2, delegate()->found_namespace_entry_url_);
1185 EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
1189 // FindInterceptPatternMatch ----------------------------------------
1191 void FindInterceptPatternMatchInDatabase() {
1192 FindInterceptPatternMatch(true);
1195 void FindInterceptPatternMatchInWorkingSet() {
1196 FindInterceptPatternMatch(false);
1199 void FindInterceptPatternMatch(bool drop_from_working_set) {
1200 // Setup some preconditions. Create a complete cache with an
1201 // pattern matching intercept namespace and entry.
1202 MakeCacheAndGroup(kManifestUrl, 2, 1, true);
1203 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::INTERCEPT, 1));
1204 cache_->intercept_namespaces_.push_back(
1205 Namespace(APPCACHE_INTERCEPT_NAMESPACE, kInterceptPatternNamespace,
1207 AppCacheDatabase::CacheRecord cache_record;
1208 std::vector<AppCacheDatabase::EntryRecord> entries;
1209 std::vector<AppCacheDatabase::NamespaceRecord> intercepts;
1210 std::vector<AppCacheDatabase::NamespaceRecord> fallbacks;
1211 std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists;
1212 cache_->ToDatabaseRecords(group_.get(),
1219 std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter =
1221 while (iter != entries.end()) {
1222 // MakeCacheAndGroup has inserted the default entry record already
1223 if (iter->url != kDefaultEntryUrl)
1224 EXPECT_TRUE(database()->InsertEntry(&(*iter)));
1228 EXPECT_TRUE(database()->InsertNamespaceRecords(intercepts));
1229 if (drop_from_working_set) {
1230 EXPECT_TRUE(cache_->HasOneRef());
1232 EXPECT_TRUE(group_->HasOneRef());
1236 // First test something that does not match the pattern.
1237 PushNextTask(base::Bind(
1238 &AppCacheStorageImplTest::Verify_FindInterceptPatternMatchNegative,
1239 base::Unretained(this)));
1240 storage()->FindResponseForMainRequest(
1241 kInterceptPatternTestNegativeUrl, GURL(), delegate());
1242 EXPECT_EQ(GURL(), delegate()->found_url_); // Is always async.
1245 void Verify_FindInterceptPatternMatchNegative() {
1246 EXPECT_EQ(kInterceptPatternTestNegativeUrl, delegate()->found_url_);
1247 EXPECT_TRUE(delegate()->found_manifest_url_.is_empty());
1248 EXPECT_EQ(kAppCacheNoCacheId, delegate()->found_cache_id_);
1249 EXPECT_EQ(kAppCacheNoResponseId, delegate()->found_entry_.response_id());
1250 EXPECT_EQ(kAppCacheNoResponseId,
1251 delegate()->found_fallback_entry_.response_id());
1252 EXPECT_TRUE(delegate()->found_namespace_entry_url_.is_empty());
1253 EXPECT_EQ(0, delegate()->found_entry_.types());
1254 EXPECT_EQ(0, delegate()->found_fallback_entry_.types());
1256 // Then test something that matches.
1257 PushNextTask(base::Bind(
1258 &AppCacheStorageImplTest::Verify_FindInterceptPatternMatchPositive,
1259 base::Unretained(this)));
1260 storage()->FindResponseForMainRequest(
1261 kInterceptPatternTestPositiveUrl, GURL(), delegate());
1264 void Verify_FindInterceptPatternMatchPositive() {
1265 EXPECT_EQ(kInterceptPatternTestPositiveUrl, delegate()->found_url_);
1266 EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
1267 EXPECT_EQ(1, delegate()->found_cache_id_);
1268 EXPECT_EQ(2, delegate()->found_group_id_);
1269 EXPECT_EQ(1, delegate()->found_entry_.response_id());
1270 EXPECT_TRUE(delegate()->found_entry_.IsIntercept());
1271 EXPECT_EQ(kEntryUrl, delegate()->found_namespace_entry_url_);
1272 EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
1276 // FindFallbackPatternMatch -------------------------------
1278 void FindFallbackPatternMatchInDatabase() {
1279 FindFallbackPatternMatch(true);
1282 void FindFallbackPatternMatchInWorkingSet() {
1283 FindFallbackPatternMatch(false);
1286 void FindFallbackPatternMatch(bool drop_from_working_set) {
1287 // Setup some preconditions. Create a complete cache with a
1288 // pattern matching fallback namespace and entry.
1289 MakeCacheAndGroup(kManifestUrl, 2, 1, true);
1290 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::FALLBACK, 1));
1291 cache_->fallback_namespaces_.push_back(
1292 Namespace(APPCACHE_FALLBACK_NAMESPACE, kFallbackPatternNamespace,
1294 AppCacheDatabase::CacheRecord cache_record;
1295 std::vector<AppCacheDatabase::EntryRecord> entries;
1296 std::vector<AppCacheDatabase::NamespaceRecord> intercepts;
1297 std::vector<AppCacheDatabase::NamespaceRecord> fallbacks;
1298 std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists;
1299 cache_->ToDatabaseRecords(group_.get(),
1306 std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter =
1308 while (iter != entries.end()) {
1309 // MakeCacheAndGroup has inserted the default entry record already.
1310 if (iter->url != kDefaultEntryUrl)
1311 EXPECT_TRUE(database()->InsertEntry(&(*iter)));
1315 EXPECT_TRUE(database()->InsertNamespaceRecords(fallbacks));
1316 if (drop_from_working_set) {
1317 EXPECT_TRUE(cache_->HasOneRef());
1319 EXPECT_TRUE(group_->HasOneRef());
1323 // First test something that does not match the pattern.
1324 PushNextTask(base::Bind(
1325 &AppCacheStorageImplTest::Verify_FindFallbackPatternMatchNegative,
1326 base::Unretained(this)));
1327 storage()->FindResponseForMainRequest(
1328 kFallbackPatternTestNegativeUrl, GURL(), delegate());
1329 EXPECT_EQ(GURL(), delegate()->found_url_); // Is always async.
1332 void Verify_FindFallbackPatternMatchNegative() {
1333 EXPECT_EQ(kFallbackPatternTestNegativeUrl, delegate()->found_url_);
1334 EXPECT_TRUE(delegate()->found_manifest_url_.is_empty());
1335 EXPECT_EQ(kAppCacheNoCacheId, delegate()->found_cache_id_);
1336 EXPECT_EQ(kAppCacheNoResponseId, delegate()->found_entry_.response_id());
1337 EXPECT_EQ(kAppCacheNoResponseId,
1338 delegate()->found_fallback_entry_.response_id());
1339 EXPECT_TRUE(delegate()->found_namespace_entry_url_.is_empty());
1340 EXPECT_EQ(0, delegate()->found_entry_.types());
1341 EXPECT_EQ(0, delegate()->found_fallback_entry_.types());
1343 // Then test something that matches.
1344 PushNextTask(base::Bind(
1345 &AppCacheStorageImplTest::Verify_FindFallbackPatternMatchPositive,
1346 base::Unretained(this)));
1347 storage()->FindResponseForMainRequest(
1348 kFallbackPatternTestPositiveUrl, GURL(), delegate());
1351 void Verify_FindFallbackPatternMatchPositive() {
1352 EXPECT_EQ(kFallbackPatternTestPositiveUrl, delegate()->found_url_);
1353 EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
1354 EXPECT_EQ(1, delegate()->found_cache_id_);
1355 EXPECT_EQ(2, delegate()->found_group_id_);
1356 EXPECT_EQ(1, delegate()->found_fallback_entry_.response_id());
1357 EXPECT_TRUE(delegate()->found_fallback_entry_.IsFallback());
1358 EXPECT_EQ(kEntryUrl, delegate()->found_namespace_entry_url_);
1359 EXPECT_FALSE(delegate()->found_entry_.has_response_id());
1363 // FindMainResponseWithMultipleHits -------------------------------
1365 void FindMainResponseWithMultipleHits() {
1366 PushNextTask(base::Bind(
1367 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits,
1368 base::Unretained(this)));
1370 // Setup some preconditions, create a few caches with an identical set
1371 // of entries and fallback namespaces. Only the last one remains in
1372 // the working set to simulate appearing as "in use".
1373 MakeMultipleHitCacheAndGroup(kManifestUrl, 1);
1374 MakeMultipleHitCacheAndGroup(kManifestUrl2, 2);
1375 MakeMultipleHitCacheAndGroup(kManifestUrl3, 3);
1377 // Conduct the test, we should find the response from the last cache
1378 // since it's "in use".
1379 storage()->FindResponseForMainRequest(kEntryUrl, GURL(), delegate());
1380 EXPECT_NE(kEntryUrl, delegate()->found_url_);
1383 void MakeMultipleHitCacheAndGroup(const GURL& manifest_url, int id) {
1384 MakeCacheAndGroup(manifest_url, id, id, true);
1385 AppCacheDatabase::EntryRecord entry_record;
1387 // Add an entry for kEntryUrl
1388 entry_record.cache_id = id;
1389 entry_record.url = kEntryUrl;
1390 entry_record.flags = AppCacheEntry::EXPLICIT;
1391 entry_record.response_id = id;
1392 EXPECT_TRUE(database()->InsertEntry(&entry_record));
1395 AppCacheEntry(entry_record.flags, entry_record.response_id));
1397 // Add an entry for the manifestUrl
1398 entry_record.cache_id = id;
1399 entry_record.url = manifest_url;
1400 entry_record.flags = AppCacheEntry::MANIFEST;
1401 entry_record.response_id = id + kManifestEntryIdOffset;
1402 EXPECT_TRUE(database()->InsertEntry(&entry_record));
1405 AppCacheEntry(entry_record.flags, entry_record.response_id));
1407 // Add a fallback entry and namespace
1408 entry_record.cache_id = id;
1409 entry_record.url = kEntryUrl2;
1410 entry_record.flags = AppCacheEntry::FALLBACK;
1411 entry_record.response_id = id + kFallbackEntryIdOffset;
1412 EXPECT_TRUE(database()->InsertEntry(&entry_record));
1415 AppCacheEntry(entry_record.flags, entry_record.response_id));
1416 AppCacheDatabase::NamespaceRecord fallback_namespace_record;
1417 fallback_namespace_record.cache_id = id;
1418 fallback_namespace_record.namespace_.target_url = entry_record.url;
1419 fallback_namespace_record.namespace_.namespace_url = kFallbackNamespace;
1420 fallback_namespace_record.origin = manifest_url.GetOrigin();
1421 EXPECT_TRUE(database()->InsertNamespace(&fallback_namespace_record));
1422 cache_->fallback_namespaces_.push_back(
1423 Namespace(APPCACHE_FALLBACK_NAMESPACE,
1429 void Verify_FindMainResponseWithMultipleHits() {
1430 EXPECT_EQ(kEntryUrl, delegate()->found_url_);
1431 EXPECT_EQ(kManifestUrl3, delegate()->found_manifest_url_);
1432 EXPECT_EQ(3, delegate()->found_cache_id_);
1433 EXPECT_EQ(3, delegate()->found_group_id_);
1434 EXPECT_EQ(3, delegate()->found_entry_.response_id());
1435 EXPECT_TRUE(delegate()->found_entry_.IsExplicit());
1436 EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
1438 // Conduct another test perferring kManifestUrl
1439 delegate_.reset(new MockStorageDelegate(this));
1440 PushNextTask(base::Bind(
1441 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits2,
1442 base::Unretained(this)));
1443 storage()->FindResponseForMainRequest(kEntryUrl, kManifestUrl, delegate());
1444 EXPECT_NE(kEntryUrl, delegate()->found_url_);
1447 void Verify_FindMainResponseWithMultipleHits2() {
1448 EXPECT_EQ(kEntryUrl, delegate()->found_url_);
1449 EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
1450 EXPECT_EQ(1, delegate()->found_cache_id_);
1451 EXPECT_EQ(1, delegate()->found_group_id_);
1452 EXPECT_EQ(1, delegate()->found_entry_.response_id());
1453 EXPECT_TRUE(delegate()->found_entry_.IsExplicit());
1454 EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
1456 // Conduct the another test perferring kManifestUrl2
1457 delegate_.reset(new MockStorageDelegate(this));
1458 PushNextTask(base::Bind(
1459 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits3,
1460 base::Unretained(this)));
1461 storage()->FindResponseForMainRequest(kEntryUrl, kManifestUrl2, delegate());
1462 EXPECT_NE(kEntryUrl, delegate()->found_url_);
1465 void Verify_FindMainResponseWithMultipleHits3() {
1466 EXPECT_EQ(kEntryUrl, delegate()->found_url_);
1467 EXPECT_EQ(kManifestUrl2, delegate()->found_manifest_url_);
1468 EXPECT_EQ(2, delegate()->found_cache_id_);
1469 EXPECT_EQ(2, delegate()->found_group_id_);
1470 EXPECT_EQ(2, delegate()->found_entry_.response_id());
1471 EXPECT_TRUE(delegate()->found_entry_.IsExplicit());
1472 EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
1474 // Conduct another test with no preferred manifest that hits the fallback.
1475 delegate_.reset(new MockStorageDelegate(this));
1476 PushNextTask(base::Bind(
1477 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits4,
1478 base::Unretained(this)));
1479 storage()->FindResponseForMainRequest(
1480 kFallbackTestUrl, GURL(), delegate());
1481 EXPECT_NE(kFallbackTestUrl, delegate()->found_url_);
1484 void Verify_FindMainResponseWithMultipleHits4() {
1485 EXPECT_EQ(kFallbackTestUrl, delegate()->found_url_);
1486 EXPECT_EQ(kManifestUrl3, delegate()->found_manifest_url_);
1487 EXPECT_EQ(3, delegate()->found_cache_id_);
1488 EXPECT_EQ(3, delegate()->found_group_id_);
1489 EXPECT_FALSE(delegate()->found_entry_.has_response_id());
1490 EXPECT_EQ(3 + kFallbackEntryIdOffset,
1491 delegate()->found_fallback_entry_.response_id());
1492 EXPECT_TRUE(delegate()->found_fallback_entry_.IsFallback());
1493 EXPECT_EQ(kEntryUrl2, delegate()->found_namespace_entry_url_);
1495 // Conduct another test preferring kManifestUrl2 that hits the fallback.
1496 delegate_.reset(new MockStorageDelegate(this));
1497 PushNextTask(base::Bind(
1498 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits5,
1499 base::Unretained(this)));
1500 storage()->FindResponseForMainRequest(
1501 kFallbackTestUrl, kManifestUrl2, delegate());
1502 EXPECT_NE(kFallbackTestUrl, delegate()->found_url_);
1505 void Verify_FindMainResponseWithMultipleHits5() {
1506 EXPECT_EQ(kFallbackTestUrl, delegate()->found_url_);
1507 EXPECT_EQ(kManifestUrl2, delegate()->found_manifest_url_);
1508 EXPECT_EQ(2, delegate()->found_cache_id_);
1509 EXPECT_EQ(2, delegate()->found_group_id_);
1510 EXPECT_FALSE(delegate()->found_entry_.has_response_id());
1511 EXPECT_EQ(2 + kFallbackEntryIdOffset,
1512 delegate()->found_fallback_entry_.response_id());
1513 EXPECT_TRUE(delegate()->found_fallback_entry_.IsFallback());
1514 EXPECT_EQ(kEntryUrl2, delegate()->found_namespace_entry_url_);
1519 // FindMainResponseExclusions -------------------------------
1521 void FindMainResponseExclusionsInDatabase() {
1522 FindMainResponseExclusions(true);
1525 void FindMainResponseExclusionsInWorkingSet() {
1526 FindMainResponseExclusions(false);
1529 void FindMainResponseExclusions(bool drop_from_working_set) {
1530 // Setup some preconditions. Create a complete cache with a
1531 // foreign entry, an online namespace, and a second online
1532 // namespace nested within a fallback namespace.
1533 MakeCacheAndGroup(kManifestUrl, 1, 1, true);
1534 cache_->AddEntry(kEntryUrl,
1535 AppCacheEntry(AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN, 1));
1536 cache_->AddEntry(kEntryUrl2, AppCacheEntry(AppCacheEntry::FALLBACK, 2));
1537 cache_->fallback_namespaces_.push_back(
1538 Namespace(APPCACHE_FALLBACK_NAMESPACE,
1542 cache_->online_whitelist_namespaces_.push_back(
1543 Namespace(APPCACHE_NETWORK_NAMESPACE, kOnlineNamespace,
1545 cache_->online_whitelist_namespaces_.push_back(
1546 Namespace(APPCACHE_NETWORK_NAMESPACE, kOnlineNamespaceWithinFallback,
1549 AppCacheDatabase::EntryRecord entry_record;
1550 entry_record.cache_id = 1;
1551 entry_record.url = kEntryUrl;
1552 entry_record.flags = AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN;
1553 entry_record.response_id = 1;
1554 EXPECT_TRUE(database()->InsertEntry(&entry_record));
1555 AppCacheDatabase::OnlineWhiteListRecord whitelist_record;
1556 whitelist_record.cache_id = 1;
1557 whitelist_record.namespace_url = kOnlineNamespace;
1558 EXPECT_TRUE(database()->InsertOnlineWhiteList(&whitelist_record));
1559 AppCacheDatabase::NamespaceRecord fallback_namespace_record;
1560 fallback_namespace_record.cache_id = 1;
1561 fallback_namespace_record.namespace_.target_url = kEntryUrl2;
1562 fallback_namespace_record.namespace_.namespace_url = kFallbackNamespace;
1563 fallback_namespace_record.origin = kManifestUrl.GetOrigin();
1564 EXPECT_TRUE(database()->InsertNamespace(&fallback_namespace_record));
1565 whitelist_record.cache_id = 1;
1566 whitelist_record.namespace_url = kOnlineNamespaceWithinFallback;
1567 EXPECT_TRUE(database()->InsertOnlineWhiteList(&whitelist_record));
1568 if (drop_from_working_set) {
1573 // We should not find anything for the foreign entry.
1574 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_ExclusionNotFound,
1575 base::Unretained(this), kEntryUrl, 1));
1576 storage()->FindResponseForMainRequest(kEntryUrl, GURL(), delegate());
1579 void Verify_ExclusionNotFound(GURL expected_url, int phase) {
1580 EXPECT_EQ(expected_url, delegate()->found_url_);
1581 EXPECT_TRUE(delegate()->found_manifest_url_.is_empty());
1582 EXPECT_EQ(kAppCacheNoCacheId, delegate()->found_cache_id_);
1583 EXPECT_EQ(0, delegate()->found_group_id_);
1584 EXPECT_EQ(kAppCacheNoResponseId, delegate()->found_entry_.response_id());
1585 EXPECT_EQ(kAppCacheNoResponseId,
1586 delegate()->found_fallback_entry_.response_id());
1587 EXPECT_TRUE(delegate()->found_namespace_entry_url_.is_empty());
1588 EXPECT_EQ(0, delegate()->found_entry_.types());
1589 EXPECT_EQ(0, delegate()->found_fallback_entry_.types());
1592 // We should not find anything for the online namespace.
1594 base::Bind(&AppCacheStorageImplTest::Verify_ExclusionNotFound,
1595 base::Unretained(this), kOnlineNamespace, 2));
1596 storage()->FindResponseForMainRequest(
1597 kOnlineNamespace, GURL(), delegate());
1601 // We should not find anything for the online namespace nested within
1602 // the fallback namespace.
1603 PushNextTask(base::Bind(
1604 &AppCacheStorageImplTest::Verify_ExclusionNotFound,
1605 base::Unretained(this), kOnlineNamespaceWithinFallback, 3));
1606 storage()->FindResponseForMainRequest(
1607 kOnlineNamespaceWithinFallback, GURL(), delegate());
1614 // Reinitialize -------------------------------
1615 // These tests are somewhat of a system integration test.
1616 // They rely on running a mock http server on our IO thread,
1617 // and involves other appcache classes to get some code
1618 // coverage thruout when Reinitialize happens.
1620 class MockServiceObserver : public AppCacheServiceImpl::Observer {
1622 explicit MockServiceObserver(AppCacheStorageImplTest* test)
1625 virtual void OnServiceReinitialized(
1626 AppCacheStorageReference* old_storage_ref) OVERRIDE {
1627 observed_old_storage_ = old_storage_ref;
1628 test_->ScheduleNextTask();
1631 scoped_refptr<AppCacheStorageReference> observed_old_storage_;
1632 AppCacheStorageImplTest* test_;
1635 class MockAppCacheFrontend : public AppCacheFrontend {
1637 MockAppCacheFrontend() : error_event_was_raised_(false) {}
1639 virtual void OnCacheSelected(
1640 int host_id, const AppCacheInfo& info) OVERRIDE {}
1641 virtual void OnStatusChanged(const std::vector<int>& host_ids,
1642 AppCacheStatus status) OVERRIDE {}
1643 virtual void OnEventRaised(const std::vector<int>& host_ids,
1644 AppCacheEventID event_id) OVERRIDE {}
1645 virtual void OnProgressEventRaised(
1646 const std::vector<int>& host_ids,
1648 int num_total, int num_complete) OVERRIDE {}
1649 virtual void OnErrorEventRaised(const std::vector<int>& host_ids,
1650 const AppCacheErrorDetails& details)
1652 error_event_was_raised_ = true;
1654 virtual void OnLogMessage(int host_id, AppCacheLogLevel log_level,
1655 const std::string& message) OVERRIDE {}
1656 virtual void OnContentBlocked(
1657 int host_id, const GURL& manifest_url) OVERRIDE {}
1659 bool error_event_was_raised_;
1662 enum ReinitTestCase {
1663 CORRUPT_CACHE_ON_INSTALL,
1664 CORRUPT_CACHE_ON_LOAD_EXISTING,
1665 CORRUPT_SQL_ON_INSTALL
1668 void Reinitialize1() {
1669 // Recover from a corrupt disk cache discovered while
1670 // installing a new appcache.
1671 Reinitialize(CORRUPT_CACHE_ON_INSTALL);
1674 void Reinitialize2() {
1675 // Recover from a corrupt disk cache discovered while
1676 // trying to load a resource from an existing appcache.
1677 Reinitialize(CORRUPT_CACHE_ON_LOAD_EXISTING);
1680 void Reinitialize3() {
1681 // Recover from a corrupt sql database discovered while
1682 // installing a new appcache.
1683 Reinitialize(CORRUPT_SQL_ON_INSTALL);
1686 void Reinitialize(ReinitTestCase test_case) {
1687 // Unlike all of the other tests, this one actually read/write files.
1688 ASSERT_TRUE(temp_directory_.CreateUniqueTempDir());
1690 AppCacheDatabase db(temp_directory_.path().AppendASCII("Index"));
1691 EXPECT_TRUE(db.LazyOpen(true));
1693 if (test_case == CORRUPT_CACHE_ON_INSTALL ||
1694 test_case == CORRUPT_CACHE_ON_LOAD_EXISTING) {
1695 // Create a corrupt/unopenable disk_cache index file.
1696 const std::string kCorruptData("deadbeef");
1697 base::FilePath disk_cache_directory =
1698 temp_directory_.path().AppendASCII("Cache");
1699 ASSERT_TRUE(base::CreateDirectory(disk_cache_directory));
1700 base::FilePath index_file = disk_cache_directory.AppendASCII("index");
1701 EXPECT_EQ(static_cast<int>(kCorruptData.length()),
1703 index_file, kCorruptData.data(), kCorruptData.length()));
1706 // Create records for a degenerate cached manifest that only contains
1707 // one entry for the manifest file resource.
1708 if (test_case == CORRUPT_CACHE_ON_LOAD_EXISTING) {
1709 AppCacheDatabase db(temp_directory_.path().AppendASCII("Index"));
1710 GURL manifest_url = MockHttpServer::GetMockUrl("manifest");
1712 AppCacheDatabase::GroupRecord group_record;
1713 group_record.group_id = 1;
1714 group_record.manifest_url = manifest_url;
1715 group_record.origin = manifest_url.GetOrigin();
1716 EXPECT_TRUE(db.InsertGroup(&group_record));
1717 AppCacheDatabase::CacheRecord cache_record;
1718 cache_record.cache_id = 1;
1719 cache_record.group_id = 1;
1720 cache_record.online_wildcard = false;
1721 cache_record.update_time = kZeroTime;
1722 cache_record.cache_size = kDefaultEntrySize;
1723 EXPECT_TRUE(db.InsertCache(&cache_record));
1724 AppCacheDatabase::EntryRecord entry_record;
1725 entry_record.cache_id = 1;
1726 entry_record.url = manifest_url;
1727 entry_record.flags = AppCacheEntry::MANIFEST;
1728 entry_record.response_id = 1;
1729 entry_record.response_size = kDefaultEntrySize;
1730 EXPECT_TRUE(db.InsertEntry(&entry_record));
1733 // Recreate the service to point at the db and corruption on disk.
1734 service_.reset(new AppCacheServiceImpl(NULL));
1735 service_->set_request_context(io_thread->request_context());
1736 service_->Initialize(
1737 temp_directory_.path(),
1738 db_thread->message_loop_proxy().get(),
1739 db_thread->message_loop_proxy().get());
1740 mock_quota_manager_proxy_ = new MockQuotaManagerProxy();
1741 service_->quota_manager_proxy_ = mock_quota_manager_proxy_;
1742 delegate_.reset(new MockStorageDelegate(this));
1744 // Additional setup to observe reinitailize happens.
1745 observer_.reset(new MockServiceObserver(this));
1746 service_->AddObserver(observer_.get());
1748 // We continue after the init task is complete including the callback
1749 // on the current thread.
1750 FlushDbThreadTasks();
1751 base::MessageLoop::current()->PostTask(
1753 base::Bind(&AppCacheStorageImplTest::Continue_Reinitialize,
1754 base::Unretained(this),
1758 void Continue_Reinitialize(ReinitTestCase test_case) {
1759 const int kMockProcessId = 1;
1760 backend_.reset(new AppCacheBackendImpl);
1761 backend_->Initialize(service_.get(), &frontend_, kMockProcessId);
1763 if (test_case == CORRUPT_SQL_ON_INSTALL) {
1764 // Break the db file
1765 EXPECT_FALSE(database()->was_corruption_detected());
1766 ASSERT_TRUE(sql::test::CorruptSizeInHeader(
1767 temp_directory_.path().AppendASCII("Index")));
1770 if (test_case == CORRUPT_CACHE_ON_INSTALL ||
1771 test_case == CORRUPT_SQL_ON_INSTALL) {
1772 // Try to create a new appcache, the resulting update job will
1773 // eventually fail when it gets to disk cache initialization.
1774 backend_->RegisterHost(1);
1775 AppCacheHost* host1 = backend_->GetHost(1);
1776 const GURL kEmptyPageUrl(MockHttpServer::GetMockUrl("empty.html"));
1777 host1->first_party_url_ = kEmptyPageUrl;
1778 host1->SelectCache(kEmptyPageUrl,
1780 MockHttpServer::GetMockUrl("manifest"));
1782 ASSERT_EQ(CORRUPT_CACHE_ON_LOAD_EXISTING, test_case);
1783 // Try to access the existing cache manifest.
1784 // The URLRequestJob will eventually fail when it gets to disk
1785 // cache initialization.
1786 backend_->RegisterHost(2);
1787 AppCacheHost* host2 = backend_->GetHost(2);
1788 GURL manifest_url = MockHttpServer::GetMockUrl("manifest");
1789 request_ = service()->request_context()->CreateRequest(
1790 manifest_url, net::DEFAULT_PRIORITY, NULL, NULL);
1791 AppCacheInterceptor::SetExtraRequestInfo(
1792 request_.get(), service_.get(),
1793 backend_->process_id(), host2->host_id(),
1794 ResourceType::MAIN_FRAME);
1798 PushNextTask(base::Bind(
1799 &AppCacheStorageImplTest::Verify_Reinitialized,
1800 base::Unretained(this),
1804 void Verify_Reinitialized(ReinitTestCase test_case) {
1805 // Verify we got notified of reinit and a new storage instance is created,
1806 // and that the old data has been deleted.
1807 EXPECT_TRUE(observer_->observed_old_storage_.get());
1808 EXPECT_TRUE(observer_->observed_old_storage_->storage() != storage());
1809 EXPECT_FALSE(PathExists(
1810 temp_directory_.path().AppendASCII("Cache").AppendASCII("index")));
1811 EXPECT_FALSE(PathExists(
1812 temp_directory_.path().AppendASCII("Index")));
1814 if (test_case == CORRUPT_SQL_ON_INSTALL) {
1815 AppCacheStorageImpl* storage = static_cast<AppCacheStorageImpl*>(
1816 observer_->observed_old_storage_->storage());
1817 EXPECT_TRUE(storage->database_->was_corruption_detected());
1820 // Verify that the hosts saw appropriate events.
1821 if (test_case == CORRUPT_CACHE_ON_INSTALL ||
1822 test_case == CORRUPT_SQL_ON_INSTALL) {
1823 EXPECT_TRUE(frontend_.error_event_was_raised_);
1824 AppCacheHost* host1 = backend_->GetHost(1);
1825 EXPECT_FALSE(host1->associated_cache());
1826 EXPECT_FALSE(host1->group_being_updated_);
1827 EXPECT_TRUE(host1->disabled_storage_reference_.get());
1829 ASSERT_EQ(CORRUPT_CACHE_ON_LOAD_EXISTING, test_case);
1830 AppCacheHost* host2 = backend_->GetHost(2);
1831 EXPECT_EQ(1, host2->main_resource_cache_->cache_id());
1832 EXPECT_TRUE(host2->disabled_storage_reference_.get());
1835 // Cleanup and claim victory.
1836 service_->RemoveObserver(observer_.get());
1843 // Test case helpers --------------------------------------------------
1845 AppCacheServiceImpl* service() {
1846 return service_.get();
1849 AppCacheStorageImpl* storage() {
1850 return static_cast<AppCacheStorageImpl*>(service()->storage());
1853 AppCacheDatabase* database() {
1854 return storage()->database_;
1857 MockStorageDelegate* delegate() {
1858 return delegate_.get();
1861 void MakeCacheAndGroup(
1862 const GURL& manifest_url, int64 group_id, int64 cache_id,
1863 bool add_to_database) {
1864 AppCacheEntry default_entry(
1865 AppCacheEntry::EXPLICIT, cache_id + kDefaultEntryIdOffset,
1867 group_ = new AppCacheGroup(storage(), manifest_url, group_id);
1868 cache_ = new AppCache(storage(), cache_id);
1869 cache_->AddEntry(kDefaultEntryUrl, default_entry);
1870 cache_->set_complete(true);
1871 group_->AddCache(cache_.get());
1872 if (add_to_database) {
1873 AppCacheDatabase::GroupRecord group_record;
1874 group_record.group_id = group_id;
1875 group_record.manifest_url = manifest_url;
1876 group_record.origin = manifest_url.GetOrigin();
1877 EXPECT_TRUE(database()->InsertGroup(&group_record));
1878 AppCacheDatabase::CacheRecord cache_record;
1879 cache_record.cache_id = cache_id;
1880 cache_record.group_id = group_id;
1881 cache_record.online_wildcard = false;
1882 cache_record.update_time = kZeroTime;
1883 cache_record.cache_size = kDefaultEntrySize;
1884 EXPECT_TRUE(database()->InsertCache(&cache_record));
1885 AppCacheDatabase::EntryRecord entry_record;
1886 entry_record.cache_id = cache_id;
1887 entry_record.url = kDefaultEntryUrl;
1888 entry_record.flags = default_entry.types();
1889 entry_record.response_id = default_entry.response_id();
1890 entry_record.response_size = default_entry.response_size();
1891 EXPECT_TRUE(database()->InsertEntry(&entry_record));
1893 storage()->usage_map_[manifest_url.GetOrigin()] =
1894 default_entry.response_size();
1898 // Data members --------------------------------------------------
1900 scoped_ptr<base::WaitableEvent> test_finished_event_;
1901 std::stack<base::Closure> task_stack_;
1902 scoped_ptr<AppCacheServiceImpl> service_;
1903 scoped_ptr<MockStorageDelegate> delegate_;
1904 scoped_refptr<MockQuotaManagerProxy> mock_quota_manager_proxy_;
1905 scoped_refptr<AppCacheGroup> group_;
1906 scoped_refptr<AppCache> cache_;
1907 scoped_refptr<AppCache> cache2_;
1909 // Specifically for the Reinitalize test.
1910 base::ScopedTempDir temp_directory_;
1911 scoped_ptr<MockServiceObserver> observer_;
1912 MockAppCacheFrontend frontend_;
1913 scoped_ptr<AppCacheBackendImpl> backend_;
1914 scoped_ptr<net::URLRequest> request_;
1918 TEST_F(AppCacheStorageImplTest, LoadCache_Miss) {
1919 RunTestOnIOThread(&AppCacheStorageImplTest::LoadCache_Miss);
1922 TEST_F(AppCacheStorageImplTest, LoadCache_NearHit) {
1923 RunTestOnIOThread(&AppCacheStorageImplTest::LoadCache_NearHit);
1926 TEST_F(AppCacheStorageImplTest, CreateGroupInEmptyOrigin) {
1927 RunTestOnIOThread(&AppCacheStorageImplTest::CreateGroupInEmptyOrigin);
1930 TEST_F(AppCacheStorageImplTest, CreateGroupInPopulatedOrigin) {
1931 RunTestOnIOThread(&AppCacheStorageImplTest::CreateGroupInPopulatedOrigin);
1934 TEST_F(AppCacheStorageImplTest, LoadGroupAndCache_FarHit) {
1935 RunTestOnIOThread(&AppCacheStorageImplTest::LoadGroupAndCache_FarHit);
1938 TEST_F(AppCacheStorageImplTest, StoreNewGroup) {
1939 RunTestOnIOThread(&AppCacheStorageImplTest::StoreNewGroup);
1942 TEST_F(AppCacheStorageImplTest, StoreExistingGroup) {
1943 RunTestOnIOThread(&AppCacheStorageImplTest::StoreExistingGroup);
1946 TEST_F(AppCacheStorageImplTest, StoreExistingGroupExistingCache) {
1947 RunTestOnIOThread(&AppCacheStorageImplTest::StoreExistingGroupExistingCache);
1950 TEST_F(AppCacheStorageImplTest, FailStoreGroup) {
1951 RunTestOnIOThread(&AppCacheStorageImplTest::FailStoreGroup);
1954 TEST_F(AppCacheStorageImplTest, MakeGroupObsolete) {
1955 RunTestOnIOThread(&AppCacheStorageImplTest::MakeGroupObsolete);
1958 TEST_F(AppCacheStorageImplTest, MarkEntryAsForeign) {
1959 RunTestOnIOThread(&AppCacheStorageImplTest::MarkEntryAsForeign);
1962 TEST_F(AppCacheStorageImplTest, MarkEntryAsForeignWithLoadInProgress) {
1964 &AppCacheStorageImplTest::MarkEntryAsForeignWithLoadInProgress);
1967 TEST_F(AppCacheStorageImplTest, FindNoMainResponse) {
1968 RunTestOnIOThread(&AppCacheStorageImplTest::FindNoMainResponse);
1971 TEST_F(AppCacheStorageImplTest, BasicFindMainResponseInDatabase) {
1973 &AppCacheStorageImplTest::BasicFindMainResponseInDatabase);
1976 TEST_F(AppCacheStorageImplTest, BasicFindMainResponseInWorkingSet) {
1978 &AppCacheStorageImplTest::BasicFindMainResponseInWorkingSet);
1981 TEST_F(AppCacheStorageImplTest, BasicFindMainFallbackResponseInDatabase) {
1983 &AppCacheStorageImplTest::BasicFindMainFallbackResponseInDatabase);
1986 TEST_F(AppCacheStorageImplTest, BasicFindMainFallbackResponseInWorkingSet) {
1988 &AppCacheStorageImplTest::BasicFindMainFallbackResponseInWorkingSet);
1991 TEST_F(AppCacheStorageImplTest, BasicFindMainInterceptResponseInDatabase) {
1993 &AppCacheStorageImplTest::BasicFindMainInterceptResponseInDatabase);
1996 TEST_F(AppCacheStorageImplTest, BasicFindMainInterceptResponseInWorkingSet) {
1998 &AppCacheStorageImplTest::BasicFindMainInterceptResponseInWorkingSet);
2001 TEST_F(AppCacheStorageImplTest, FindMainResponseWithMultipleHits) {
2003 &AppCacheStorageImplTest::FindMainResponseWithMultipleHits);
2006 TEST_F(AppCacheStorageImplTest, FindMainResponseExclusionsInDatabase) {
2008 &AppCacheStorageImplTest::FindMainResponseExclusionsInDatabase);
2011 TEST_F(AppCacheStorageImplTest, FindMainResponseExclusionsInWorkingSet) {
2013 &AppCacheStorageImplTest::FindMainResponseExclusionsInWorkingSet);
2016 TEST_F(AppCacheStorageImplTest, FindInterceptPatternMatchInWorkingSet) {
2018 &AppCacheStorageImplTest::FindInterceptPatternMatchInWorkingSet);
2021 TEST_F(AppCacheStorageImplTest, FindInterceptPatternMatchInDatabase) {
2023 &AppCacheStorageImplTest::FindInterceptPatternMatchInDatabase);
2026 TEST_F(AppCacheStorageImplTest, FindFallbackPatternMatchInWorkingSet) {
2028 &AppCacheStorageImplTest::FindFallbackPatternMatchInWorkingSet);
2031 TEST_F(AppCacheStorageImplTest, FindFallbackPatternMatchInDatabase) {
2033 &AppCacheStorageImplTest::FindFallbackPatternMatchInDatabase);
2036 TEST_F(AppCacheStorageImplTest, Reinitialize1) {
2037 RunTestOnIOThread(&AppCacheStorageImplTest::Reinitialize1);
2040 TEST_F(AppCacheStorageImplTest, Reinitialize2) {
2041 RunTestOnIOThread(&AppCacheStorageImplTest::Reinitialize2);
2044 TEST_F(AppCacheStorageImplTest, Reinitialize3) {
2045 RunTestOnIOThread(&AppCacheStorageImplTest::Reinitialize3);
2048 // That's all folks!
2050 } // namespace content