1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
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 "net/base/net_errors.h"
17 #include "net/base/request_priority.h"
18 #include "net/http/http_response_headers.h"
19 #include "net/url_request/url_request_error_job.h"
20 #include "net/url_request/url_request_job_factory_impl.h"
21 #include "net/url_request/url_request_test_job.h"
22 #include "net/url_request/url_request_test_util.h"
23 #include "sql/test/test_helpers.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 #include "webkit/browser/appcache/appcache.h"
26 #include "webkit/browser/appcache/appcache_backend_impl.h"
27 #include "webkit/browser/appcache/appcache_database.h"
28 #include "webkit/browser/appcache/appcache_entry.h"
29 #include "webkit/browser/appcache/appcache_group.h"
30 #include "webkit/browser/appcache/appcache_host.h"
31 #include "webkit/browser/appcache/appcache_interceptor.h"
32 #include "webkit/browser/appcache/appcache_request_handler.h"
33 #include "webkit/browser/appcache/appcache_service.h"
34 #include "webkit/browser/appcache/appcache_storage_impl.h"
35 #include "webkit/browser/quota/quota_manager.h"
41 const base::Time kZeroTime;
42 const GURL kManifestUrl("http://blah/manifest");
43 const GURL kManifestUrl2("http://blah/manifest2");
44 const GURL kManifestUrl3("http://blah/manifest3");
45 const GURL kEntryUrl("http://blah/entry");
46 const GURL kEntryUrl2("http://blah/entry2");
47 const GURL kFallbackNamespace("http://blah/fallback_namespace/");
48 const GURL kFallbackNamespace2("http://blah/fallback_namespace/longer");
49 const GURL kFallbackTestUrl("http://blah/fallback_namespace/longer/test");
50 const GURL kOnlineNamespace("http://blah/online_namespace");
51 const GURL kOnlineNamespaceWithinFallback(
52 "http://blah/fallback_namespace/online/");
53 const GURL kInterceptNamespace("http://blah/intercept_namespace/");
54 const GURL kInterceptNamespace2("http://blah/intercept_namespace/longer/");
55 const GURL kInterceptTestUrl("http://blah/intercept_namespace/longer/test");
56 const GURL kInterceptPatternNamespace("http://blah/intercept_pattern/*/bar");
57 const GURL kInterceptPatternTestPositiveUrl(
58 "http://blah/intercept_pattern/foo/bar");
59 const GURL kInterceptPatternTestNegativeUrl(
60 "http://blah/intercept_pattern/foo/not_bar");
61 const GURL kFallbackPatternNamespace("http://blah/fallback_pattern/*/bar");
62 const GURL kFallbackPatternTestPositiveUrl(
63 "http://blah/fallback_pattern/foo/bar");
64 const GURL kFallbackPatternTestNegativeUrl(
65 "http://blah/fallback_pattern/foo/not_bar");
66 const GURL kOrigin(kManifestUrl.GetOrigin());
68 const int kManifestEntryIdOffset = 100;
69 const int kFallbackEntryIdOffset = 1000;
71 const GURL kDefaultEntryUrl("http://blah/makecacheandgroup_default_entry");
72 const int kDefaultEntrySize = 10;
73 const int kDefaultEntryIdOffset = 12345;
75 const int kMockQuota = 5000;
77 // The Reinitialize test needs some http accessible resources to run,
78 // we mock stuff inprocess for that.
79 class MockHttpServer {
81 static GURL GetMockUrl(const std::string& path) {
82 return GURL("http://mockhost/" + path);
85 static net::URLRequestJob* CreateJob(
86 net::URLRequest* request, net::NetworkDelegate* network_delegate) {
87 if (request->url().host() != "mockhost")
88 return new net::URLRequestErrorJob(request, network_delegate, -100);
90 std::string headers, body;
91 GetMockResponse(request->url().path(), &headers, &body);
92 return new net::URLRequestTestJob(
93 request, network_delegate, headers, body, true);
97 static void GetMockResponse(const std::string& path,
100 const char manifest_headers[] =
102 "Content-type: text/cache-manifest\0"
104 const char page_headers[] =
106 "Content-type: text/html\0"
108 const char not_found_headers[] =
109 "HTTP/1.1 404 NOT FOUND\0"
112 if (path == "/manifest") {
113 (*headers) = std::string(manifest_headers, arraysize(manifest_headers));
114 (*body) = "CACHE MANIFEST\n";
115 } else if (path == "/empty.html") {
116 (*headers) = std::string(page_headers, arraysize(page_headers));
119 (*headers) = std::string(not_found_headers,
120 arraysize(not_found_headers));
126 class MockHttpServerJobFactory
127 : public net::URLRequestJobFactory::ProtocolHandler {
129 virtual net::URLRequestJob* MaybeCreateJob(
130 net::URLRequest* request,
131 net::NetworkDelegate* network_delegate) const OVERRIDE {
132 return MockHttpServer::CreateJob(request, network_delegate);
136 class IOThread : public base::Thread {
138 explicit IOThread(const char* name)
139 : base::Thread(name) {
142 virtual ~IOThread() {
146 net::URLRequestContext* request_context() {
147 return request_context_.get();
150 virtual void Init() OVERRIDE {
151 scoped_ptr<net::URLRequestJobFactoryImpl> factory(
152 new net::URLRequestJobFactoryImpl());
153 factory->SetProtocolHandler("http", new MockHttpServerJobFactory);
154 job_factory_ = factory.Pass();
155 request_context_.reset(new net::TestURLRequestContext());
156 request_context_->set_job_factory(job_factory_.get());
157 AppCacheInterceptor::EnsureRegistered();
160 virtual void CleanUp() OVERRIDE {
161 request_context_.reset();
162 job_factory_.reset();
166 scoped_ptr<net::URLRequestJobFactory> job_factory_;
167 scoped_ptr<net::URLRequestContext> request_context_;
170 scoped_ptr<IOThread> io_thread;
171 scoped_ptr<base::Thread> db_thread;
175 class AppCacheStorageImplTest : public testing::Test {
177 class MockStorageDelegate : public AppCacheStorage::Delegate {
179 explicit MockStorageDelegate(AppCacheStorageImplTest* test)
180 : loaded_cache_id_(0), stored_group_success_(false),
181 would_exceed_quota_(false), obsoleted_success_(false),
182 found_cache_id_(kNoCacheId), test_(test) {
185 virtual void OnCacheLoaded(AppCache* cache, int64 cache_id) OVERRIDE {
186 loaded_cache_ = cache;
187 loaded_cache_id_ = cache_id;
188 test_->ScheduleNextTask();
191 virtual void OnGroupLoaded(AppCacheGroup* group,
192 const GURL& manifest_url) OVERRIDE {
193 loaded_group_ = group;
194 loaded_manifest_url_ = manifest_url;
195 loaded_groups_newest_cache_ = group ? group->newest_complete_cache()
197 test_->ScheduleNextTask();
200 virtual void OnGroupAndNewestCacheStored(
201 AppCacheGroup* group, AppCache* newest_cache, bool success,
202 bool would_exceed_quota) OVERRIDE {
203 stored_group_ = group;
204 stored_group_success_ = success;
205 would_exceed_quota_ = would_exceed_quota;
206 test_->ScheduleNextTask();
209 virtual void OnGroupMadeObsolete(AppCacheGroup* group,
210 bool success) OVERRIDE {
211 obsoleted_group_ = group;
212 obsoleted_success_ = success;
213 test_->ScheduleNextTask();
216 virtual void OnMainResponseFound(const GURL& url,
217 const AppCacheEntry& entry,
218 const GURL& namespace_entry_url,
219 const AppCacheEntry& fallback_entry,
222 const GURL& manifest_url) OVERRIDE {
224 found_entry_ = entry;
225 found_namespace_entry_url_ = namespace_entry_url;
226 found_fallback_entry_ = fallback_entry;
227 found_cache_id_ = cache_id;
228 found_group_id_ = group_id;
229 found_manifest_url_ = manifest_url;
230 test_->ScheduleNextTask();
233 scoped_refptr<AppCache> loaded_cache_;
234 int64 loaded_cache_id_;
235 scoped_refptr<AppCacheGroup> loaded_group_;
236 GURL loaded_manifest_url_;
237 scoped_refptr<AppCache> loaded_groups_newest_cache_;
238 scoped_refptr<AppCacheGroup> stored_group_;
239 bool stored_group_success_;
240 bool would_exceed_quota_;
241 scoped_refptr<AppCacheGroup> obsoleted_group_;
242 bool obsoleted_success_;
244 AppCacheEntry found_entry_;
245 GURL found_namespace_entry_url_;
246 AppCacheEntry found_fallback_entry_;
247 int64 found_cache_id_;
248 int64 found_group_id_;
249 GURL found_manifest_url_;
250 AppCacheStorageImplTest* test_;
253 class MockQuotaManager : public quota::QuotaManager {
256 : QuotaManager(true /* is_incognito */,
258 io_thread->message_loop_proxy().get(),
259 db_thread->message_loop_proxy().get(),
263 virtual void GetUsageAndQuota(
265 quota::StorageType type,
266 const GetUsageAndQuotaCallback& callback) OVERRIDE {
267 EXPECT_EQ(quota::kStorageTypeTemporary, type);
269 base::MessageLoop::current()->PostTask(
271 base::Bind(&MockQuotaManager::CallCallback,
272 base::Unretained(this),
276 CallCallback(callback);
279 void CallCallback(const GetUsageAndQuotaCallback& callback) {
280 callback.Run(quota::kQuotaStatusOk, 0, kMockQuota);
286 virtual ~MockQuotaManager() {}
289 class MockQuotaManagerProxy : public quota::QuotaManagerProxy {
291 MockQuotaManagerProxy()
292 : QuotaManagerProxy(NULL, NULL),
293 notify_storage_accessed_count_(0),
294 notify_storage_modified_count_(0),
296 mock_manager_(new MockQuotaManager) {
297 manager_ = mock_manager_.get();
300 virtual void NotifyStorageAccessed(quota::QuotaClient::ID client_id,
302 quota::StorageType type) OVERRIDE {
303 EXPECT_EQ(quota::QuotaClient::kAppcache, client_id);
304 EXPECT_EQ(quota::kStorageTypeTemporary, type);
305 ++notify_storage_accessed_count_;
306 last_origin_ = origin;
309 virtual void NotifyStorageModified(quota::QuotaClient::ID client_id,
311 quota::StorageType type,
312 int64 delta) OVERRIDE {
313 EXPECT_EQ(quota::QuotaClient::kAppcache, client_id);
314 EXPECT_EQ(quota::kStorageTypeTemporary, type);
315 ++notify_storage_modified_count_;
316 last_origin_ = origin;
320 // Not needed for our tests.
321 virtual void RegisterClient(quota::QuotaClient* client) OVERRIDE {}
322 virtual void NotifyOriginInUse(const GURL& origin) OVERRIDE {}
323 virtual void NotifyOriginNoLongerInUse(const GURL& origin) OVERRIDE {}
324 virtual void SetUsageCacheEnabled(quota::QuotaClient::ID client_id,
326 quota::StorageType type,
327 bool enabled) OVERRIDE {}
328 virtual void GetUsageAndQuota(
329 base::SequencedTaskRunner* original_task_runner,
331 quota::StorageType type,
332 const GetUsageAndQuotaCallback& callback) OVERRIDE {}
334 int notify_storage_accessed_count_;
335 int notify_storage_modified_count_;
338 scoped_refptr<MockQuotaManager> mock_manager_;
341 virtual ~MockQuotaManagerProxy() {}
344 template <class Method>
345 void RunMethod(Method method) {
349 // Helper callback to run a test on our io_thread. The io_thread is spun up
350 // once and reused for all tests.
351 template <class Method>
352 void MethodWrapper(Method method) {
355 // Ensure InitTask execution prior to conducting a test.
356 FlushDbThreadTasks();
358 // We also have to wait for InitTask completion call to be performed
359 // on the IO thread prior to running the test. Its guaranteed to be
360 // queued by this time.
361 base::MessageLoop::current()->PostTask(
363 base::Bind(&AppCacheStorageImplTest::RunMethod<Method>,
364 base::Unretained(this),
368 static void SetUpTestCase() {
369 // We start both threads as TYPE_IO because we also use the db_thead
370 // for the disk_cache which needs to be of TYPE_IO.
371 base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
372 io_thread.reset(new IOThread("AppCacheTest.IOThread"));
373 ASSERT_TRUE(io_thread->StartWithOptions(options));
374 db_thread.reset(new base::Thread("AppCacheTest::DBThread"));
375 ASSERT_TRUE(db_thread->StartWithOptions(options));
378 static void TearDownTestCase() {
379 io_thread.reset(NULL);
380 db_thread.reset(NULL);
383 // Test harness --------------------------------------------------
385 AppCacheStorageImplTest() {
388 template <class Method>
389 void RunTestOnIOThread(Method method) {
390 test_finished_event_ .reset(new base::WaitableEvent(false, false));
391 io_thread->message_loop()->PostTask(
392 FROM_HERE, base::Bind(&AppCacheStorageImplTest::MethodWrapper<Method>,
393 base::Unretained(this), method));
394 test_finished_event_->Wait();
398 DCHECK(base::MessageLoop::current() == io_thread->message_loop());
399 service_.reset(new AppCacheService(NULL));
400 service_->Initialize(
401 base::FilePath(), db_thread->message_loop_proxy().get(), NULL);
402 mock_quota_manager_proxy_ = new MockQuotaManagerProxy();
403 service_->quota_manager_proxy_ = mock_quota_manager_proxy_;
404 delegate_.reset(new MockStorageDelegate(this));
407 void TearDownTest() {
408 DCHECK(base::MessageLoop::current() == io_thread->message_loop());
409 storage()->CancelDelegateCallbacks(delegate());
413 mock_quota_manager_proxy_ = NULL;
416 FlushDbThreadTasks();
419 void TestFinished() {
420 // We unwind the stack prior to finishing up to let stack
421 // based objects get deleted.
422 DCHECK(base::MessageLoop::current() == io_thread->message_loop());
423 base::MessageLoop::current()->PostTask(
425 base::Bind(&AppCacheStorageImplTest::TestFinishedUnwound,
426 base::Unretained(this)));
429 void TestFinishedUnwound() {
431 test_finished_event_->Signal();
434 void PushNextTask(const base::Closure& task) {
435 task_stack_.push(task);
438 void ScheduleNextTask() {
439 DCHECK(base::MessageLoop::current() == io_thread->message_loop());
440 if (task_stack_.empty()) {
443 base::MessageLoop::current()->PostTask(FROM_HERE, task_stack_.top());
447 static void SignalEvent(base::WaitableEvent* event) {
451 void FlushDbThreadTasks() {
452 // We pump a task thru the db thread to ensure any tasks previously
453 // scheduled on that thread have been performed prior to return.
454 base::WaitableEvent event(false, false);
455 db_thread->message_loop()->PostTask(
456 FROM_HERE, base::Bind(&AppCacheStorageImplTest::SignalEvent, &event));
460 // LoadCache_Miss ----------------------------------------------------
462 void LoadCache_Miss() {
463 // Attempt to load a cache that doesn't exist. Should
464 // complete asynchronously.
465 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_LoadCache_Miss,
466 base::Unretained(this)));
468 storage()->LoadCache(111, delegate());
469 EXPECT_NE(111, delegate()->loaded_cache_id_);
472 void Verify_LoadCache_Miss() {
473 EXPECT_EQ(111, delegate()->loaded_cache_id_);
474 EXPECT_FALSE(delegate()->loaded_cache_.get());
475 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_accessed_count_);
476 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
480 // LoadCache_NearHit -------------------------------------------------
482 void LoadCache_NearHit() {
483 // Attempt to load a cache that is currently in use
484 // and does not require loading from storage. This
485 // load should complete syncly.
487 // Setup some preconditions. Make an 'unstored' cache for
488 // us to load. The ctor should put it in the working set.
489 int64 cache_id = storage()->NewCacheId();
490 scoped_refptr<AppCache> cache(new AppCache(storage(), cache_id));
493 storage()->LoadCache(cache_id, delegate());
494 EXPECT_EQ(cache_id, delegate()->loaded_cache_id_);
495 EXPECT_EQ(cache.get(), delegate()->loaded_cache_.get());
496 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_accessed_count_);
497 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
501 // CreateGroup --------------------------------------------
503 void CreateGroupInEmptyOrigin() {
504 // Attempt to load a group that doesn't exist, one should
505 // be created for us, but not stored.
507 // Since the origin has no groups, the storage class will respond
509 storage()->LoadOrCreateGroup(kManifestUrl, delegate());
510 Verify_CreateGroup();
513 void CreateGroupInPopulatedOrigin() {
514 // Attempt to load a group that doesn't exist, one should
515 // be created for us, but not stored.
516 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_CreateGroup,
517 base::Unretained(this)));
519 // Since the origin has groups, storage class will have to
520 // consult the database and completion will be async.
521 storage()->usage_map_[kOrigin] = kDefaultEntrySize;
523 storage()->LoadOrCreateGroup(kManifestUrl, delegate());
524 EXPECT_FALSE(delegate()->loaded_group_.get());
527 void Verify_CreateGroup() {
528 EXPECT_EQ(kManifestUrl, delegate()->loaded_manifest_url_);
529 EXPECT_TRUE(delegate()->loaded_group_.get());
530 EXPECT_TRUE(delegate()->loaded_group_->HasOneRef());
531 EXPECT_FALSE(delegate()->loaded_group_->newest_complete_cache());
533 // Should not have been stored in the database.
534 AppCacheDatabase::GroupRecord record;
535 EXPECT_FALSE(database()->FindGroup(
536 delegate()->loaded_group_->group_id(), &record));
538 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_accessed_count_);
539 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
544 // LoadGroupAndCache_FarHit --------------------------------------
546 void LoadGroupAndCache_FarHit() {
547 // Attempt to load a cache that is not currently in use
548 // and does require loading from disk. This
549 // load should complete asynchronously.
550 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_LoadCache_Far_Hit,
551 base::Unretained(this)));
553 // Setup some preconditions. Create a group and newest cache that
554 // appear to be "stored" and "not currently in use".
555 MakeCacheAndGroup(kManifestUrl, 1, 1, true);
559 // Conduct the cache load test, completes async
560 storage()->LoadCache(1, delegate());
563 void Verify_LoadCache_Far_Hit() {
564 EXPECT_TRUE(delegate()->loaded_cache_.get());
565 EXPECT_TRUE(delegate()->loaded_cache_->HasOneRef());
566 EXPECT_EQ(1, delegate()->loaded_cache_id_);
568 // The group should also have been loaded.
569 EXPECT_TRUE(delegate()->loaded_cache_->owning_group());
570 EXPECT_TRUE(delegate()->loaded_cache_->owning_group()->HasOneRef());
571 EXPECT_EQ(1, delegate()->loaded_cache_->owning_group()->group_id());
573 EXPECT_EQ(1, mock_quota_manager_proxy_->notify_storage_accessed_count_);
574 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
576 // Drop things from the working set.
577 delegate()->loaded_cache_ = NULL;
578 EXPECT_FALSE(delegate()->loaded_group_.get());
580 // Conduct the group load test, also complete asynchronously.
581 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_LoadGroup_Far_Hit,
582 base::Unretained(this)));
584 storage()->LoadOrCreateGroup(kManifestUrl, delegate());
587 void Verify_LoadGroup_Far_Hit() {
588 EXPECT_TRUE(delegate()->loaded_group_.get());
589 EXPECT_EQ(kManifestUrl, delegate()->loaded_manifest_url_);
590 EXPECT_TRUE(delegate()->loaded_group_->newest_complete_cache());
591 delegate()->loaded_groups_newest_cache_ = NULL;
592 EXPECT_TRUE(delegate()->loaded_group_->HasOneRef());
593 EXPECT_EQ(2, mock_quota_manager_proxy_->notify_storage_accessed_count_);
594 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
598 // StoreNewGroup --------------------------------------
600 void StoreNewGroup() {
601 // Store a group and its newest cache. Should complete asynchronously.
602 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_StoreNewGroup,
603 base::Unretained(this)));
605 // Setup some preconditions. Create a group and newest cache that
606 // appear to be "unstored".
607 group_ = new AppCacheGroup(
608 storage(), kManifestUrl, storage()->NewGroupId());
609 cache_ = new AppCache(storage(), storage()->NewCacheId());
610 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT, 1,
612 // Hold a ref to the cache simulate the UpdateJob holding that ref,
613 // and hold a ref to the group to simulate the CacheHost holding that ref.
615 // Have the quota manager retrun asynchronously for this test.
616 mock_quota_manager_proxy_->mock_manager_->async_ = true;
618 // Conduct the store test.
619 storage()->StoreGroupAndNewestCache(group_.get(), cache_.get(), delegate());
620 EXPECT_FALSE(delegate()->stored_group_success_);
623 void Verify_StoreNewGroup() {
624 EXPECT_TRUE(delegate()->stored_group_success_);
625 EXPECT_EQ(group_.get(), delegate()->stored_group_.get());
626 EXPECT_EQ(cache_.get(), group_->newest_complete_cache());
627 EXPECT_TRUE(cache_->is_complete());
629 // Should have been stored in the database.
630 AppCacheDatabase::GroupRecord group_record;
631 AppCacheDatabase::CacheRecord cache_record;
632 EXPECT_TRUE(database()->FindGroup(group_->group_id(), &group_record));
633 EXPECT_TRUE(database()->FindCache(cache_->cache_id(), &cache_record));
635 // Verify quota bookkeeping
636 EXPECT_EQ(kDefaultEntrySize, storage()->usage_map_[kOrigin]);
637 EXPECT_EQ(1, mock_quota_manager_proxy_->notify_storage_modified_count_);
638 EXPECT_EQ(kOrigin, mock_quota_manager_proxy_->last_origin_);
639 EXPECT_EQ(kDefaultEntrySize, mock_quota_manager_proxy_->last_delta_);
644 // StoreExistingGroup --------------------------------------
646 void StoreExistingGroup() {
647 // Store a group and its newest cache. Should complete asynchronously.
648 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_StoreExistingGroup,
649 base::Unretained(this)));
651 // Setup some preconditions. Create a group and old complete cache
652 // that appear to be "stored"
653 MakeCacheAndGroup(kManifestUrl, 1, 1, true);
654 EXPECT_EQ(kDefaultEntrySize, storage()->usage_map_[kOrigin]);
656 // And a newest unstored complete cache.
657 cache2_ = new AppCache(storage(), 2);
658 cache2_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::MASTER, 1,
659 kDefaultEntrySize + 100));
662 storage()->StoreGroupAndNewestCache(
663 group_.get(), cache2_.get(), delegate());
664 EXPECT_FALSE(delegate()->stored_group_success_);
667 void Verify_StoreExistingGroup() {
668 EXPECT_TRUE(delegate()->stored_group_success_);
669 EXPECT_EQ(group_.get(), delegate()->stored_group_.get());
670 EXPECT_EQ(cache2_.get(), group_->newest_complete_cache());
671 EXPECT_TRUE(cache2_->is_complete());
673 // The new cache should have been stored in the database.
674 AppCacheDatabase::GroupRecord group_record;
675 AppCacheDatabase::CacheRecord cache_record;
676 EXPECT_TRUE(database()->FindGroup(1, &group_record));
677 EXPECT_TRUE(database()->FindCache(2, &cache_record));
679 // The old cache should have been deleted
680 EXPECT_FALSE(database()->FindCache(1, &cache_record));
682 // Verify quota bookkeeping
683 EXPECT_EQ(kDefaultEntrySize + 100, storage()->usage_map_[kOrigin]);
684 EXPECT_EQ(1, mock_quota_manager_proxy_->notify_storage_modified_count_);
685 EXPECT_EQ(kOrigin, mock_quota_manager_proxy_->last_origin_);
686 EXPECT_EQ(100, mock_quota_manager_proxy_->last_delta_);
691 // StoreExistingGroupExistingCache -------------------------------
693 void StoreExistingGroupExistingCache() {
694 // Store a group with updates to its existing newest complete cache.
695 // Setup some preconditions. Create a group and a complete cache that
696 // appear to be "stored".
698 // Setup some preconditions. Create a group and old complete cache
699 // that appear to be "stored"
700 MakeCacheAndGroup(kManifestUrl, 1, 1, true);
701 EXPECT_EQ(kDefaultEntrySize, storage()->usage_map_[kOrigin]);
704 base::Time now = base::Time::Now();
705 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::MASTER, 1, 100));
706 cache_->set_update_time(now);
708 PushNextTask(base::Bind(
709 &AppCacheStorageImplTest::Verify_StoreExistingGroupExistingCache,
710 base::Unretained(this), now));
713 EXPECT_EQ(cache_, group_->newest_complete_cache());
714 storage()->StoreGroupAndNewestCache(group_.get(), cache_.get(), delegate());
715 EXPECT_FALSE(delegate()->stored_group_success_);
718 void Verify_StoreExistingGroupExistingCache(
719 base::Time expected_update_time) {
720 EXPECT_TRUE(delegate()->stored_group_success_);
721 EXPECT_EQ(cache_, group_->newest_complete_cache());
723 AppCacheDatabase::CacheRecord cache_record;
724 EXPECT_TRUE(database()->FindCache(1, &cache_record));
725 EXPECT_EQ(1, cache_record.cache_id);
726 EXPECT_EQ(1, cache_record.group_id);
727 EXPECT_FALSE(cache_record.online_wildcard);
728 EXPECT_TRUE(expected_update_time == cache_record.update_time);
729 EXPECT_EQ(100 + kDefaultEntrySize, cache_record.cache_size);
731 std::vector<AppCacheDatabase::EntryRecord> entry_records;
732 EXPECT_TRUE(database()->FindEntriesForCache(1, &entry_records));
733 EXPECT_EQ(2U, entry_records.size());
734 if (entry_records[0].url == kDefaultEntryUrl)
735 entry_records.erase(entry_records.begin());
736 EXPECT_EQ(1 , entry_records[0].cache_id);
737 EXPECT_EQ(kEntryUrl, entry_records[0].url);
738 EXPECT_EQ(AppCacheEntry::MASTER, entry_records[0].flags);
739 EXPECT_EQ(1, entry_records[0].response_id);
740 EXPECT_EQ(100, entry_records[0].response_size);
742 // Verify quota bookkeeping
743 EXPECT_EQ(100 + kDefaultEntrySize, storage()->usage_map_[kOrigin]);
744 EXPECT_EQ(1, mock_quota_manager_proxy_->notify_storage_modified_count_);
745 EXPECT_EQ(kOrigin, mock_quota_manager_proxy_->last_origin_);
746 EXPECT_EQ(100, mock_quota_manager_proxy_->last_delta_);
751 // FailStoreGroup --------------------------------------
753 void FailStoreGroup() {
754 // Store a group and its newest cache. Should complete asynchronously.
755 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_FailStoreGroup,
756 base::Unretained(this)));
758 // Setup some preconditions. Create a group and newest cache that
759 // appear to be "unstored" and big enough to exceed the 5M limit.
760 const int64 kTooBig = 10 * 1024 * 1024; // 10M
761 group_ = new AppCacheGroup(
762 storage(), kManifestUrl, storage()->NewGroupId());
763 cache_ = new AppCache(storage(), storage()->NewCacheId());
764 cache_->AddEntry(kManifestUrl,
765 AppCacheEntry(AppCacheEntry::MANIFEST, 1, kTooBig));
766 // Hold a ref to the cache simulate the UpdateJob holding that ref,
767 // and hold a ref to the group to simulate the CacheHost holding that ref.
769 // Conduct the store test.
770 storage()->StoreGroupAndNewestCache(group_.get(), cache_.get(), delegate());
771 EXPECT_FALSE(delegate()->stored_group_success_); // Expected to be async.
774 void Verify_FailStoreGroup() {
775 EXPECT_FALSE(delegate()->stored_group_success_);
776 EXPECT_TRUE(delegate()->would_exceed_quota_);
778 // Should not have been stored in the database.
779 AppCacheDatabase::GroupRecord group_record;
780 AppCacheDatabase::CacheRecord cache_record;
781 EXPECT_FALSE(database()->FindGroup(group_->group_id(), &group_record));
782 EXPECT_FALSE(database()->FindCache(cache_->cache_id(), &cache_record));
784 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_accessed_count_);
785 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
790 // MakeGroupObsolete -------------------------------
792 void MakeGroupObsolete() {
793 // Make a group obsolete, should complete asynchronously.
794 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_MakeGroupObsolete,
795 base::Unretained(this)));
797 // Setup some preconditions. Create a group and newest cache that
798 // appears to be "stored" and "currently in use".
799 MakeCacheAndGroup(kManifestUrl, 1, 1, true);
800 EXPECT_EQ(kDefaultEntrySize, storage()->usage_map_[kOrigin]);
802 // Also insert some related records.
803 AppCacheDatabase::EntryRecord entry_record;
804 entry_record.cache_id = 1;
805 entry_record.flags = AppCacheEntry::FALLBACK;
806 entry_record.response_id = 1;
807 entry_record.url = kEntryUrl;
808 EXPECT_TRUE(database()->InsertEntry(&entry_record));
810 AppCacheDatabase::NamespaceRecord fallback_namespace_record;
811 fallback_namespace_record.cache_id = 1;
812 fallback_namespace_record.namespace_.target_url = kEntryUrl;
813 fallback_namespace_record.namespace_.namespace_url = kFallbackNamespace;
814 fallback_namespace_record.origin = kManifestUrl.GetOrigin();
815 EXPECT_TRUE(database()->InsertNamespace(&fallback_namespace_record));
817 AppCacheDatabase::OnlineWhiteListRecord online_whitelist_record;
818 online_whitelist_record.cache_id = 1;
819 online_whitelist_record.namespace_url = kOnlineNamespace;
820 EXPECT_TRUE(database()->InsertOnlineWhiteList(&online_whitelist_record));
823 storage()->MakeGroupObsolete(group_.get(), delegate());
824 EXPECT_FALSE(group_->is_obsolete());
827 void Verify_MakeGroupObsolete() {
828 EXPECT_TRUE(delegate()->obsoleted_success_);
829 EXPECT_EQ(group_.get(), delegate()->obsoleted_group_.get());
830 EXPECT_TRUE(group_->is_obsolete());
831 EXPECT_TRUE(storage()->usage_map_.empty());
833 // The cache and group have been deleted from the database.
834 AppCacheDatabase::GroupRecord group_record;
835 AppCacheDatabase::CacheRecord cache_record;
836 EXPECT_FALSE(database()->FindGroup(1, &group_record));
837 EXPECT_FALSE(database()->FindCache(1, &cache_record));
839 // The related records should have been deleted too.
840 std::vector<AppCacheDatabase::EntryRecord> entry_records;
841 database()->FindEntriesForCache(1, &entry_records);
842 EXPECT_TRUE(entry_records.empty());
843 std::vector<AppCacheDatabase::NamespaceRecord> intercept_records;
844 std::vector<AppCacheDatabase::NamespaceRecord> fallback_records;
845 database()->FindNamespacesForCache(
846 1, &intercept_records, &fallback_records);
847 EXPECT_TRUE(fallback_records.empty());
848 std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelist_records;
849 database()->FindOnlineWhiteListForCache(1, &whitelist_records);
850 EXPECT_TRUE(whitelist_records.empty());
852 // Verify quota bookkeeping
853 EXPECT_TRUE(storage()->usage_map_.empty());
854 EXPECT_EQ(1, mock_quota_manager_proxy_->notify_storage_modified_count_);
855 EXPECT_EQ(kOrigin, mock_quota_manager_proxy_->last_origin_);
856 EXPECT_EQ(-kDefaultEntrySize, mock_quota_manager_proxy_->last_delta_);
861 // MarkEntryAsForeign -------------------------------
863 void MarkEntryAsForeign() {
864 // Setup some preconditions. Create a cache with an entry
865 // in storage and in the working set.
866 MakeCacheAndGroup(kManifestUrl, 1, 1, true);
867 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT));
868 AppCacheDatabase::EntryRecord entry_record;
869 entry_record.cache_id = 1;
870 entry_record.url = kEntryUrl;
871 entry_record.flags = AppCacheEntry::EXPLICIT;
872 entry_record.response_id = 0;
873 EXPECT_TRUE(database()->InsertEntry(&entry_record));
874 EXPECT_FALSE(cache_->GetEntry(kEntryUrl)->IsForeign());
877 storage()->MarkEntryAsForeign(kEntryUrl, 1);
879 // The entry in the working set should have been updated syncly.
880 EXPECT_TRUE(cache_->GetEntry(kEntryUrl)->IsForeign());
881 EXPECT_TRUE(cache_->GetEntry(kEntryUrl)->IsExplicit());
883 // And the entry in storage should also be updated, but that
884 // happens asynchronously on the db thread.
885 FlushDbThreadTasks();
886 AppCacheDatabase::EntryRecord entry_record2;
887 EXPECT_TRUE(database()->FindEntry(1, kEntryUrl, &entry_record2));
888 EXPECT_EQ(AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN,
889 entry_record2.flags);
893 // MarkEntryAsForeignWithLoadInProgress -------------------------------
895 void MarkEntryAsForeignWithLoadInProgress() {
896 PushNextTask(base::Bind(
897 &AppCacheStorageImplTest::Verify_MarkEntryAsForeignWithLoadInProgress,
898 base::Unretained(this)));
900 // Setup some preconditions. Create a cache with an entry
901 // in storage, but not in the working set.
902 MakeCacheAndGroup(kManifestUrl, 1, 1, true);
903 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT));
904 AppCacheDatabase::EntryRecord entry_record;
905 entry_record.cache_id = 1;
906 entry_record.url = kEntryUrl;
907 entry_record.flags = AppCacheEntry::EXPLICIT;
908 entry_record.response_id = 0;
909 EXPECT_TRUE(database()->InsertEntry(&entry_record));
910 EXPECT_FALSE(cache_->GetEntry(kEntryUrl)->IsForeign());
911 EXPECT_TRUE(cache_->HasOneRef());
915 // Conduct the test, start a cache load, and prior to completion
916 // of that load, mark the entry as foreign.
917 storage()->LoadCache(1, delegate());
918 storage()->MarkEntryAsForeign(kEntryUrl, 1);
921 void Verify_MarkEntryAsForeignWithLoadInProgress() {
922 EXPECT_EQ(1, delegate()->loaded_cache_id_);
923 EXPECT_TRUE(delegate()->loaded_cache_.get());
925 // The entry in the working set should have been updated upon load.
926 EXPECT_TRUE(delegate()->loaded_cache_->GetEntry(kEntryUrl)->IsForeign());
927 EXPECT_TRUE(delegate()->loaded_cache_->GetEntry(kEntryUrl)->IsExplicit());
929 // And the entry in storage should also be updated.
930 FlushDbThreadTasks();
931 AppCacheDatabase::EntryRecord entry_record;
932 EXPECT_TRUE(database()->FindEntry(1, kEntryUrl, &entry_record));
933 EXPECT_EQ(AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN,
938 // FindNoMainResponse -------------------------------
940 void FindNoMainResponse() {
941 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_FindNoMainResponse,
942 base::Unretained(this)));
945 storage()->FindResponseForMainRequest(kEntryUrl, GURL(), delegate());
946 EXPECT_NE(kEntryUrl, delegate()->found_url_);
949 void Verify_FindNoMainResponse() {
950 EXPECT_EQ(kEntryUrl, delegate()->found_url_);
951 EXPECT_TRUE(delegate()->found_manifest_url_.is_empty());
952 EXPECT_EQ(kNoCacheId, delegate()->found_cache_id_);
953 EXPECT_EQ(kNoResponseId, delegate()->found_entry_.response_id());
954 EXPECT_EQ(kNoResponseId, delegate()->found_fallback_entry_.response_id());
955 EXPECT_TRUE(delegate()->found_namespace_entry_url_.is_empty());
956 EXPECT_EQ(0, delegate()->found_entry_.types());
957 EXPECT_EQ(0, delegate()->found_fallback_entry_.types());
961 // BasicFindMainResponse -------------------------------
963 void BasicFindMainResponseInDatabase() {
964 BasicFindMainResponse(true);
967 void BasicFindMainResponseInWorkingSet() {
968 BasicFindMainResponse(false);
971 void BasicFindMainResponse(bool drop_from_working_set) {
972 PushNextTask(base::Bind(
973 &AppCacheStorageImplTest::Verify_BasicFindMainResponse,
974 base::Unretained(this)));
976 // Setup some preconditions. Create a complete cache with an entry
978 MakeCacheAndGroup(kManifestUrl, 2, 1, true);
979 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT, 1));
980 AppCacheDatabase::EntryRecord entry_record;
981 entry_record.cache_id = 1;
982 entry_record.url = kEntryUrl;
983 entry_record.flags = AppCacheEntry::EXPLICIT;
984 entry_record.response_id = 1;
985 EXPECT_TRUE(database()->InsertEntry(&entry_record));
987 // Optionally drop the cache/group pair from the working set.
988 if (drop_from_working_set) {
989 EXPECT_TRUE(cache_->HasOneRef());
991 EXPECT_TRUE(group_->HasOneRef());
996 storage()->FindResponseForMainRequest(kEntryUrl, GURL(), delegate());
997 EXPECT_NE(kEntryUrl, delegate()->found_url_);
1000 void Verify_BasicFindMainResponse() {
1001 EXPECT_EQ(kEntryUrl, delegate()->found_url_);
1002 EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
1003 EXPECT_EQ(1, delegate()->found_cache_id_);
1004 EXPECT_EQ(2, delegate()->found_group_id_);
1005 EXPECT_EQ(1, delegate()->found_entry_.response_id());
1006 EXPECT_TRUE(delegate()->found_entry_.IsExplicit());
1007 EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
1011 // BasicFindMainFallbackResponse -------------------------------
1013 void BasicFindMainFallbackResponseInDatabase() {
1014 BasicFindMainFallbackResponse(true);
1017 void BasicFindMainFallbackResponseInWorkingSet() {
1018 BasicFindMainFallbackResponse(false);
1021 void BasicFindMainFallbackResponse(bool drop_from_working_set) {
1022 PushNextTask(base::Bind(
1023 &AppCacheStorageImplTest::Verify_BasicFindMainFallbackResponse,
1024 base::Unretained(this)));
1026 // Setup some preconditions. Create a complete cache with a
1027 // fallback namespace and entry.
1028 MakeCacheAndGroup(kManifestUrl, 2, 1, true);
1029 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::FALLBACK, 1));
1030 cache_->AddEntry(kEntryUrl2, AppCacheEntry(AppCacheEntry::FALLBACK, 2));
1031 cache_->fallback_namespaces_.push_back(
1032 Namespace(FALLBACK_NAMESPACE, kFallbackNamespace2, kEntryUrl2, false));
1033 cache_->fallback_namespaces_.push_back(
1034 Namespace(FALLBACK_NAMESPACE, kFallbackNamespace, kEntryUrl, false));
1035 AppCacheDatabase::CacheRecord cache_record;
1036 std::vector<AppCacheDatabase::EntryRecord> entries;
1037 std::vector<AppCacheDatabase::NamespaceRecord> intercepts;
1038 std::vector<AppCacheDatabase::NamespaceRecord> fallbacks;
1039 std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists;
1040 cache_->ToDatabaseRecords(group_.get(),
1047 std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter =
1049 while (iter != entries.end()) {
1050 // MakeCacheAndGroup has inserted the default entry record already.
1051 if (iter->url != kDefaultEntryUrl)
1052 EXPECT_TRUE(database()->InsertEntry(&(*iter)));
1056 EXPECT_TRUE(database()->InsertNamespaceRecords(fallbacks));
1057 EXPECT_TRUE(database()->InsertOnlineWhiteListRecords(whitelists));
1058 if (drop_from_working_set) {
1059 EXPECT_TRUE(cache_->HasOneRef());
1061 EXPECT_TRUE(group_->HasOneRef());
1065 // Conduct the test. The test url is in both fallback namespace urls,
1066 // but should match the longer of the two.
1067 storage()->FindResponseForMainRequest(kFallbackTestUrl, GURL(), delegate());
1068 EXPECT_NE(kFallbackTestUrl, delegate()->found_url_);
1071 void Verify_BasicFindMainFallbackResponse() {
1072 EXPECT_EQ(kFallbackTestUrl, delegate()->found_url_);
1073 EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
1074 EXPECT_EQ(1, delegate()->found_cache_id_);
1075 EXPECT_EQ(2, delegate()->found_group_id_);
1076 EXPECT_FALSE(delegate()->found_entry_.has_response_id());
1077 EXPECT_EQ(2, delegate()->found_fallback_entry_.response_id());
1078 EXPECT_EQ(kEntryUrl2, delegate()->found_namespace_entry_url_);
1079 EXPECT_TRUE(delegate()->found_fallback_entry_.IsFallback());
1083 // BasicFindMainInterceptResponse -------------------------------
1085 void BasicFindMainInterceptResponseInDatabase() {
1086 BasicFindMainInterceptResponse(true);
1089 void BasicFindMainInterceptResponseInWorkingSet() {
1090 BasicFindMainInterceptResponse(false);
1093 void BasicFindMainInterceptResponse(bool drop_from_working_set) {
1094 PushNextTask(base::Bind(
1095 &AppCacheStorageImplTest::Verify_BasicFindMainInterceptResponse,
1096 base::Unretained(this)));
1098 // Setup some preconditions. Create a complete cache with an
1099 // intercept namespace and entry.
1100 MakeCacheAndGroup(kManifestUrl, 2, 1, true);
1101 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::INTERCEPT, 1));
1102 cache_->AddEntry(kEntryUrl2, AppCacheEntry(AppCacheEntry::INTERCEPT, 2));
1103 cache_->intercept_namespaces_.push_back(
1104 Namespace(INTERCEPT_NAMESPACE, kInterceptNamespace2,
1105 kEntryUrl2, false));
1106 cache_->intercept_namespaces_.push_back(
1107 Namespace(INTERCEPT_NAMESPACE, kInterceptNamespace,
1109 AppCacheDatabase::CacheRecord cache_record;
1110 std::vector<AppCacheDatabase::EntryRecord> entries;
1111 std::vector<AppCacheDatabase::NamespaceRecord> intercepts;
1112 std::vector<AppCacheDatabase::NamespaceRecord> fallbacks;
1113 std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists;
1114 cache_->ToDatabaseRecords(group_.get(),
1121 std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter =
1123 while (iter != entries.end()) {
1124 // MakeCacheAndGroup has inserted the default entry record already
1125 if (iter->url != kDefaultEntryUrl)
1126 EXPECT_TRUE(database()->InsertEntry(&(*iter)));
1130 EXPECT_TRUE(database()->InsertNamespaceRecords(intercepts));
1131 EXPECT_TRUE(database()->InsertOnlineWhiteListRecords(whitelists));
1132 if (drop_from_working_set) {
1133 EXPECT_TRUE(cache_->HasOneRef());
1135 EXPECT_TRUE(group_->HasOneRef());
1139 // Conduct the test. The test url is in both intercept namespaces,
1140 // but should match the longer of the two.
1141 storage()->FindResponseForMainRequest(
1142 kInterceptTestUrl, GURL(), delegate());
1143 EXPECT_NE(kInterceptTestUrl, delegate()->found_url_);
1146 void Verify_BasicFindMainInterceptResponse() {
1147 EXPECT_EQ(kInterceptTestUrl, delegate()->found_url_);
1148 EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
1149 EXPECT_EQ(1, delegate()->found_cache_id_);
1150 EXPECT_EQ(2, delegate()->found_group_id_);
1151 EXPECT_EQ(2, delegate()->found_entry_.response_id());
1152 EXPECT_TRUE(delegate()->found_entry_.IsIntercept());
1153 EXPECT_EQ(kEntryUrl2, delegate()->found_namespace_entry_url_);
1154 EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
1158 // FindInterceptPatternMatch ----------------------------------------
1160 void FindInterceptPatternMatchInDatabase() {
1161 FindInterceptPatternMatch(true);
1164 void FindInterceptPatternMatchInWorkingSet() {
1165 FindInterceptPatternMatch(false);
1168 void FindInterceptPatternMatch(bool drop_from_working_set) {
1169 // Setup some preconditions. Create a complete cache with an
1170 // pattern matching intercept namespace and entry.
1171 MakeCacheAndGroup(kManifestUrl, 2, 1, true);
1172 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::INTERCEPT, 1));
1173 cache_->intercept_namespaces_.push_back(
1174 Namespace(INTERCEPT_NAMESPACE, kInterceptPatternNamespace,
1176 AppCacheDatabase::CacheRecord cache_record;
1177 std::vector<AppCacheDatabase::EntryRecord> entries;
1178 std::vector<AppCacheDatabase::NamespaceRecord> intercepts;
1179 std::vector<AppCacheDatabase::NamespaceRecord> fallbacks;
1180 std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists;
1181 cache_->ToDatabaseRecords(group_.get(),
1188 std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter =
1190 while (iter != entries.end()) {
1191 // MakeCacheAndGroup has inserted the default entry record already
1192 if (iter->url != kDefaultEntryUrl)
1193 EXPECT_TRUE(database()->InsertEntry(&(*iter)));
1197 EXPECT_TRUE(database()->InsertNamespaceRecords(intercepts));
1198 if (drop_from_working_set) {
1199 EXPECT_TRUE(cache_->HasOneRef());
1201 EXPECT_TRUE(group_->HasOneRef());
1205 // First test something that does not match the pattern.
1206 PushNextTask(base::Bind(
1207 &AppCacheStorageImplTest::Verify_FindInterceptPatternMatchNegative,
1208 base::Unretained(this)));
1209 storage()->FindResponseForMainRequest(
1210 kInterceptPatternTestNegativeUrl, GURL(), delegate());
1211 EXPECT_EQ(GURL(), delegate()->found_url_); // Is always async.
1214 void Verify_FindInterceptPatternMatchNegative() {
1215 EXPECT_EQ(kInterceptPatternTestNegativeUrl, delegate()->found_url_);
1216 EXPECT_TRUE(delegate()->found_manifest_url_.is_empty());
1217 EXPECT_EQ(kNoCacheId, delegate()->found_cache_id_);
1218 EXPECT_EQ(kNoResponseId, delegate()->found_entry_.response_id());
1219 EXPECT_EQ(kNoResponseId, delegate()->found_fallback_entry_.response_id());
1220 EXPECT_TRUE(delegate()->found_namespace_entry_url_.is_empty());
1221 EXPECT_EQ(0, delegate()->found_entry_.types());
1222 EXPECT_EQ(0, delegate()->found_fallback_entry_.types());
1224 // Then test something that matches.
1225 PushNextTask(base::Bind(
1226 &AppCacheStorageImplTest::Verify_FindInterceptPatternMatchPositive,
1227 base::Unretained(this)));
1228 storage()->FindResponseForMainRequest(
1229 kInterceptPatternTestPositiveUrl, GURL(), delegate());
1232 void Verify_FindInterceptPatternMatchPositive() {
1233 EXPECT_EQ(kInterceptPatternTestPositiveUrl, delegate()->found_url_);
1234 EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
1235 EXPECT_EQ(1, delegate()->found_cache_id_);
1236 EXPECT_EQ(2, delegate()->found_group_id_);
1237 EXPECT_EQ(1, delegate()->found_entry_.response_id());
1238 EXPECT_TRUE(delegate()->found_entry_.IsIntercept());
1239 EXPECT_EQ(kEntryUrl, delegate()->found_namespace_entry_url_);
1240 EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
1244 // FindFallbackPatternMatch -------------------------------
1246 void FindFallbackPatternMatchInDatabase() {
1247 FindFallbackPatternMatch(true);
1250 void FindFallbackPatternMatchInWorkingSet() {
1251 FindFallbackPatternMatch(false);
1254 void FindFallbackPatternMatch(bool drop_from_working_set) {
1255 // Setup some preconditions. Create a complete cache with a
1256 // pattern matching fallback namespace and entry.
1257 MakeCacheAndGroup(kManifestUrl, 2, 1, true);
1258 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::FALLBACK, 1));
1259 cache_->fallback_namespaces_.push_back(
1260 Namespace(FALLBACK_NAMESPACE, kFallbackPatternNamespace,
1262 AppCacheDatabase::CacheRecord cache_record;
1263 std::vector<AppCacheDatabase::EntryRecord> entries;
1264 std::vector<AppCacheDatabase::NamespaceRecord> intercepts;
1265 std::vector<AppCacheDatabase::NamespaceRecord> fallbacks;
1266 std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists;
1267 cache_->ToDatabaseRecords(group_.get(),
1274 std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter =
1276 while (iter != entries.end()) {
1277 // MakeCacheAndGroup has inserted the default entry record already.
1278 if (iter->url != kDefaultEntryUrl)
1279 EXPECT_TRUE(database()->InsertEntry(&(*iter)));
1283 EXPECT_TRUE(database()->InsertNamespaceRecords(fallbacks));
1284 if (drop_from_working_set) {
1285 EXPECT_TRUE(cache_->HasOneRef());
1287 EXPECT_TRUE(group_->HasOneRef());
1291 // First test something that does not match the pattern.
1292 PushNextTask(base::Bind(
1293 &AppCacheStorageImplTest::Verify_FindFallbackPatternMatchNegative,
1294 base::Unretained(this)));
1295 storage()->FindResponseForMainRequest(
1296 kFallbackPatternTestNegativeUrl, GURL(), delegate());
1297 EXPECT_EQ(GURL(), delegate()->found_url_); // Is always async.
1300 void Verify_FindFallbackPatternMatchNegative() {
1301 EXPECT_EQ(kFallbackPatternTestNegativeUrl, delegate()->found_url_);
1302 EXPECT_TRUE(delegate()->found_manifest_url_.is_empty());
1303 EXPECT_EQ(kNoCacheId, delegate()->found_cache_id_);
1304 EXPECT_EQ(kNoResponseId, delegate()->found_entry_.response_id());
1305 EXPECT_EQ(kNoResponseId, delegate()->found_fallback_entry_.response_id());
1306 EXPECT_TRUE(delegate()->found_namespace_entry_url_.is_empty());
1307 EXPECT_EQ(0, delegate()->found_entry_.types());
1308 EXPECT_EQ(0, delegate()->found_fallback_entry_.types());
1310 // Then test something that matches.
1311 PushNextTask(base::Bind(
1312 &AppCacheStorageImplTest::Verify_FindFallbackPatternMatchPositive,
1313 base::Unretained(this)));
1314 storage()->FindResponseForMainRequest(
1315 kFallbackPatternTestPositiveUrl, GURL(), delegate());
1318 void Verify_FindFallbackPatternMatchPositive() {
1319 EXPECT_EQ(kFallbackPatternTestPositiveUrl, delegate()->found_url_);
1320 EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
1321 EXPECT_EQ(1, delegate()->found_cache_id_);
1322 EXPECT_EQ(2, delegate()->found_group_id_);
1323 EXPECT_EQ(1, delegate()->found_fallback_entry_.response_id());
1324 EXPECT_TRUE(delegate()->found_fallback_entry_.IsFallback());
1325 EXPECT_EQ(kEntryUrl, delegate()->found_namespace_entry_url_);
1326 EXPECT_FALSE(delegate()->found_entry_.has_response_id());
1330 // FindMainResponseWithMultipleHits -------------------------------
1332 void FindMainResponseWithMultipleHits() {
1333 PushNextTask(base::Bind(
1334 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits,
1335 base::Unretained(this)));
1337 // Setup some preconditions, create a few caches with an identical set
1338 // of entries and fallback namespaces. Only the last one remains in
1339 // the working set to simulate appearing as "in use".
1340 MakeMultipleHitCacheAndGroup(kManifestUrl, 1);
1341 MakeMultipleHitCacheAndGroup(kManifestUrl2, 2);
1342 MakeMultipleHitCacheAndGroup(kManifestUrl3, 3);
1344 // Conduct the test, we should find the response from the last cache
1345 // since it's "in use".
1346 storage()->FindResponseForMainRequest(kEntryUrl, GURL(), delegate());
1347 EXPECT_NE(kEntryUrl, delegate()->found_url_);
1350 void MakeMultipleHitCacheAndGroup(const GURL& manifest_url, int id) {
1351 MakeCacheAndGroup(manifest_url, id, id, true);
1352 AppCacheDatabase::EntryRecord entry_record;
1354 // Add an entry for kEntryUrl
1355 entry_record.cache_id = id;
1356 entry_record.url = kEntryUrl;
1357 entry_record.flags = AppCacheEntry::EXPLICIT;
1358 entry_record.response_id = id;
1359 EXPECT_TRUE(database()->InsertEntry(&entry_record));
1362 AppCacheEntry(entry_record.flags, entry_record.response_id));
1364 // Add an entry for the manifestUrl
1365 entry_record.cache_id = id;
1366 entry_record.url = manifest_url;
1367 entry_record.flags = AppCacheEntry::MANIFEST;
1368 entry_record.response_id = id + kManifestEntryIdOffset;
1369 EXPECT_TRUE(database()->InsertEntry(&entry_record));
1372 AppCacheEntry(entry_record.flags, entry_record.response_id));
1374 // Add a fallback entry and namespace
1375 entry_record.cache_id = id;
1376 entry_record.url = kEntryUrl2;
1377 entry_record.flags = AppCacheEntry::FALLBACK;
1378 entry_record.response_id = id + kFallbackEntryIdOffset;
1379 EXPECT_TRUE(database()->InsertEntry(&entry_record));
1382 AppCacheEntry(entry_record.flags, entry_record.response_id));
1383 AppCacheDatabase::NamespaceRecord fallback_namespace_record;
1384 fallback_namespace_record.cache_id = id;
1385 fallback_namespace_record.namespace_.target_url = entry_record.url;
1386 fallback_namespace_record.namespace_.namespace_url = kFallbackNamespace;
1387 fallback_namespace_record.origin = manifest_url.GetOrigin();
1388 EXPECT_TRUE(database()->InsertNamespace(&fallback_namespace_record));
1389 cache_->fallback_namespaces_.push_back(
1390 Namespace(FALLBACK_NAMESPACE, kFallbackNamespace, kEntryUrl2, false));
1393 void Verify_FindMainResponseWithMultipleHits() {
1394 EXPECT_EQ(kEntryUrl, delegate()->found_url_);
1395 EXPECT_EQ(kManifestUrl3, delegate()->found_manifest_url_);
1396 EXPECT_EQ(3, delegate()->found_cache_id_);
1397 EXPECT_EQ(3, delegate()->found_group_id_);
1398 EXPECT_EQ(3, delegate()->found_entry_.response_id());
1399 EXPECT_TRUE(delegate()->found_entry_.IsExplicit());
1400 EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
1402 // Conduct another test perferring kManifestUrl
1403 delegate_.reset(new MockStorageDelegate(this));
1404 PushNextTask(base::Bind(
1405 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits2,
1406 base::Unretained(this)));
1407 storage()->FindResponseForMainRequest(kEntryUrl, kManifestUrl, delegate());
1408 EXPECT_NE(kEntryUrl, delegate()->found_url_);
1411 void Verify_FindMainResponseWithMultipleHits2() {
1412 EXPECT_EQ(kEntryUrl, delegate()->found_url_);
1413 EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
1414 EXPECT_EQ(1, delegate()->found_cache_id_);
1415 EXPECT_EQ(1, delegate()->found_group_id_);
1416 EXPECT_EQ(1, delegate()->found_entry_.response_id());
1417 EXPECT_TRUE(delegate()->found_entry_.IsExplicit());
1418 EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
1420 // Conduct the another test perferring kManifestUrl2
1421 delegate_.reset(new MockStorageDelegate(this));
1422 PushNextTask(base::Bind(
1423 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits3,
1424 base::Unretained(this)));
1425 storage()->FindResponseForMainRequest(kEntryUrl, kManifestUrl2, delegate());
1426 EXPECT_NE(kEntryUrl, delegate()->found_url_);
1429 void Verify_FindMainResponseWithMultipleHits3() {
1430 EXPECT_EQ(kEntryUrl, delegate()->found_url_);
1431 EXPECT_EQ(kManifestUrl2, delegate()->found_manifest_url_);
1432 EXPECT_EQ(2, delegate()->found_cache_id_);
1433 EXPECT_EQ(2, delegate()->found_group_id_);
1434 EXPECT_EQ(2, 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 with no preferred manifest that hits the fallback.
1439 delegate_.reset(new MockStorageDelegate(this));
1440 PushNextTask(base::Bind(
1441 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits4,
1442 base::Unretained(this)));
1443 storage()->FindResponseForMainRequest(
1444 kFallbackTestUrl, GURL(), delegate());
1445 EXPECT_NE(kFallbackTestUrl, delegate()->found_url_);
1448 void Verify_FindMainResponseWithMultipleHits4() {
1449 EXPECT_EQ(kFallbackTestUrl, delegate()->found_url_);
1450 EXPECT_EQ(kManifestUrl3, delegate()->found_manifest_url_);
1451 EXPECT_EQ(3, delegate()->found_cache_id_);
1452 EXPECT_EQ(3, delegate()->found_group_id_);
1453 EXPECT_FALSE(delegate()->found_entry_.has_response_id());
1454 EXPECT_EQ(3 + kFallbackEntryIdOffset,
1455 delegate()->found_fallback_entry_.response_id());
1456 EXPECT_TRUE(delegate()->found_fallback_entry_.IsFallback());
1457 EXPECT_EQ(kEntryUrl2, delegate()->found_namespace_entry_url_);
1459 // Conduct another test preferring kManifestUrl2 that hits the fallback.
1460 delegate_.reset(new MockStorageDelegate(this));
1461 PushNextTask(base::Bind(
1462 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits5,
1463 base::Unretained(this)));
1464 storage()->FindResponseForMainRequest(
1465 kFallbackTestUrl, kManifestUrl2, delegate());
1466 EXPECT_NE(kFallbackTestUrl, delegate()->found_url_);
1469 void Verify_FindMainResponseWithMultipleHits5() {
1470 EXPECT_EQ(kFallbackTestUrl, delegate()->found_url_);
1471 EXPECT_EQ(kManifestUrl2, delegate()->found_manifest_url_);
1472 EXPECT_EQ(2, delegate()->found_cache_id_);
1473 EXPECT_EQ(2, delegate()->found_group_id_);
1474 EXPECT_FALSE(delegate()->found_entry_.has_response_id());
1475 EXPECT_EQ(2 + kFallbackEntryIdOffset,
1476 delegate()->found_fallback_entry_.response_id());
1477 EXPECT_TRUE(delegate()->found_fallback_entry_.IsFallback());
1478 EXPECT_EQ(kEntryUrl2, delegate()->found_namespace_entry_url_);
1483 // FindMainResponseExclusions -------------------------------
1485 void FindMainResponseExclusionsInDatabase() {
1486 FindMainResponseExclusions(true);
1489 void FindMainResponseExclusionsInWorkingSet() {
1490 FindMainResponseExclusions(false);
1493 void FindMainResponseExclusions(bool drop_from_working_set) {
1494 // Setup some preconditions. Create a complete cache with a
1495 // foreign entry, an online namespace, and a second online
1496 // namespace nested within a fallback namespace.
1497 MakeCacheAndGroup(kManifestUrl, 1, 1, true);
1498 cache_->AddEntry(kEntryUrl,
1499 AppCacheEntry(AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN, 1));
1500 cache_->AddEntry(kEntryUrl2, AppCacheEntry(AppCacheEntry::FALLBACK, 2));
1501 cache_->fallback_namespaces_.push_back(
1502 Namespace(FALLBACK_NAMESPACE, kFallbackNamespace, kEntryUrl2, false));
1503 cache_->online_whitelist_namespaces_.push_back(
1504 Namespace(NETWORK_NAMESPACE, kOnlineNamespace,
1506 cache_->online_whitelist_namespaces_.push_back(
1507 Namespace(NETWORK_NAMESPACE, kOnlineNamespaceWithinFallback,
1510 AppCacheDatabase::EntryRecord entry_record;
1511 entry_record.cache_id = 1;
1512 entry_record.url = kEntryUrl;
1513 entry_record.flags = AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN;
1514 entry_record.response_id = 1;
1515 EXPECT_TRUE(database()->InsertEntry(&entry_record));
1516 AppCacheDatabase::OnlineWhiteListRecord whitelist_record;
1517 whitelist_record.cache_id = 1;
1518 whitelist_record.namespace_url = kOnlineNamespace;
1519 EXPECT_TRUE(database()->InsertOnlineWhiteList(&whitelist_record));
1520 AppCacheDatabase::NamespaceRecord fallback_namespace_record;
1521 fallback_namespace_record.cache_id = 1;
1522 fallback_namespace_record.namespace_.target_url = kEntryUrl2;
1523 fallback_namespace_record.namespace_.namespace_url = kFallbackNamespace;
1524 fallback_namespace_record.origin = kManifestUrl.GetOrigin();
1525 EXPECT_TRUE(database()->InsertNamespace(&fallback_namespace_record));
1526 whitelist_record.cache_id = 1;
1527 whitelist_record.namespace_url = kOnlineNamespaceWithinFallback;
1528 EXPECT_TRUE(database()->InsertOnlineWhiteList(&whitelist_record));
1529 if (drop_from_working_set) {
1534 // We should not find anything for the foreign entry.
1535 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_ExclusionNotFound,
1536 base::Unretained(this), kEntryUrl, 1));
1537 storage()->FindResponseForMainRequest(kEntryUrl, GURL(), delegate());
1540 void Verify_ExclusionNotFound(GURL expected_url, int phase) {
1541 EXPECT_EQ(expected_url, delegate()->found_url_);
1542 EXPECT_TRUE(delegate()->found_manifest_url_.is_empty());
1543 EXPECT_EQ(kNoCacheId, delegate()->found_cache_id_);
1544 EXPECT_EQ(0, delegate()->found_group_id_);
1545 EXPECT_EQ(kNoResponseId, delegate()->found_entry_.response_id());
1546 EXPECT_EQ(kNoResponseId, delegate()->found_fallback_entry_.response_id());
1547 EXPECT_TRUE(delegate()->found_namespace_entry_url_.is_empty());
1548 EXPECT_EQ(0, delegate()->found_entry_.types());
1549 EXPECT_EQ(0, delegate()->found_fallback_entry_.types());
1552 // We should not find anything for the online namespace.
1554 base::Bind(&AppCacheStorageImplTest::Verify_ExclusionNotFound,
1555 base::Unretained(this), kOnlineNamespace, 2));
1556 storage()->FindResponseForMainRequest(
1557 kOnlineNamespace, GURL(), delegate());
1561 // We should not find anything for the online namespace nested within
1562 // the fallback namespace.
1563 PushNextTask(base::Bind(
1564 &AppCacheStorageImplTest::Verify_ExclusionNotFound,
1565 base::Unretained(this), kOnlineNamespaceWithinFallback, 3));
1566 storage()->FindResponseForMainRequest(
1567 kOnlineNamespaceWithinFallback, GURL(), delegate());
1574 // Reinitialize -------------------------------
1575 // These tests are somewhat of a system integration test.
1576 // They rely on running a mock http server on our IO thread,
1577 // and involves other appcache classes to get some code
1578 // coverage thruout when Reinitialize happens.
1580 class MockServiceObserver : public AppCacheService::Observer {
1582 explicit MockServiceObserver(AppCacheStorageImplTest* test)
1585 virtual void OnServiceReinitialized(
1586 AppCacheStorageReference* old_storage_ref) OVERRIDE {
1587 observed_old_storage_ = old_storage_ref;
1588 test_->ScheduleNextTask();
1591 scoped_refptr<AppCacheStorageReference> observed_old_storage_;
1592 AppCacheStorageImplTest* test_;
1595 class MockAppCacheFrontend : public AppCacheFrontend {
1597 MockAppCacheFrontend() : error_event_was_raised_(false) {}
1599 virtual void OnCacheSelected(
1600 int host_id, const appcache::AppCacheInfo& info) OVERRIDE {}
1601 virtual void OnStatusChanged(const std::vector<int>& host_ids,
1602 Status status) OVERRIDE {}
1603 virtual void OnEventRaised(const std::vector<int>& host_ids,
1604 EventID event_id) OVERRIDE {}
1605 virtual void OnProgressEventRaised(
1606 const std::vector<int>& host_ids,
1608 int num_total, int num_complete) OVERRIDE {}
1609 virtual void OnErrorEventRaised(const std::vector<int>& host_ids,
1610 const std::string& message) OVERRIDE {
1611 error_event_was_raised_ = true;
1613 virtual void OnLogMessage(int host_id, LogLevel log_level,
1614 const std::string& message) OVERRIDE {}
1615 virtual void OnContentBlocked(
1616 int host_id, const GURL& manifest_url) OVERRIDE {}
1618 bool error_event_was_raised_;
1621 enum ReinitTestCase {
1622 CORRUPT_CACHE_ON_INSTALL,
1623 CORRUPT_CACHE_ON_LOAD_EXISTING,
1624 CORRUPT_SQL_ON_INSTALL
1627 void Reinitialize1() {
1628 // Recover from a corrupt disk cache discovered while
1629 // installing a new appcache.
1630 Reinitialize(CORRUPT_CACHE_ON_INSTALL);
1633 void Reinitialize2() {
1634 // Recover from a corrupt disk cache discovered while
1635 // trying to load a resource from an existing appcache.
1636 Reinitialize(CORRUPT_CACHE_ON_LOAD_EXISTING);
1639 void Reinitialize3() {
1640 // Recover from a corrupt sql database discovered while
1641 // installing a new appcache.
1642 Reinitialize(CORRUPT_SQL_ON_INSTALL);
1645 void Reinitialize(ReinitTestCase test_case) {
1646 // Unlike all of the other tests, this one actually read/write files.
1647 ASSERT_TRUE(temp_directory_.CreateUniqueTempDir());
1649 AppCacheDatabase db(temp_directory_.path().AppendASCII("Index"));
1650 EXPECT_TRUE(db.LazyOpen(true));
1652 if (test_case == CORRUPT_CACHE_ON_INSTALL ||
1653 test_case == CORRUPT_CACHE_ON_LOAD_EXISTING) {
1654 // Create a corrupt/unopenable disk_cache index file.
1655 const std::string kCorruptData("deadbeef");
1656 base::FilePath disk_cache_directory =
1657 temp_directory_.path().AppendASCII("Cache");
1658 ASSERT_TRUE(base::CreateDirectory(disk_cache_directory));
1659 base::FilePath index_file = disk_cache_directory.AppendASCII("index");
1660 EXPECT_EQ(static_cast<int>(kCorruptData.length()),
1662 index_file, kCorruptData.data(), kCorruptData.length()));
1665 // Create records for a degenerate cached manifest that only contains
1666 // one entry for the manifest file resource.
1667 if (test_case == CORRUPT_CACHE_ON_LOAD_EXISTING) {
1668 AppCacheDatabase db(temp_directory_.path().AppendASCII("Index"));
1669 GURL manifest_url = MockHttpServer::GetMockUrl("manifest");
1671 AppCacheDatabase::GroupRecord group_record;
1672 group_record.group_id = 1;
1673 group_record.manifest_url = manifest_url;
1674 group_record.origin = manifest_url.GetOrigin();
1675 EXPECT_TRUE(db.InsertGroup(&group_record));
1676 AppCacheDatabase::CacheRecord cache_record;
1677 cache_record.cache_id = 1;
1678 cache_record.group_id = 1;
1679 cache_record.online_wildcard = false;
1680 cache_record.update_time = kZeroTime;
1681 cache_record.cache_size = kDefaultEntrySize;
1682 EXPECT_TRUE(db.InsertCache(&cache_record));
1683 AppCacheDatabase::EntryRecord entry_record;
1684 entry_record.cache_id = 1;
1685 entry_record.url = manifest_url;
1686 entry_record.flags = AppCacheEntry::MANIFEST;
1687 entry_record.response_id = 1;
1688 entry_record.response_size = kDefaultEntrySize;
1689 EXPECT_TRUE(db.InsertEntry(&entry_record));
1692 // Recreate the service to point at the db and corruption on disk.
1693 service_.reset(new AppCacheService(NULL));
1694 service_->set_request_context(io_thread->request_context());
1695 service_->Initialize(
1696 temp_directory_.path(),
1697 db_thread->message_loop_proxy().get(),
1698 db_thread->message_loop_proxy().get());
1699 mock_quota_manager_proxy_ = new MockQuotaManagerProxy();
1700 service_->quota_manager_proxy_ = mock_quota_manager_proxy_;
1701 delegate_.reset(new MockStorageDelegate(this));
1703 // Additional setup to observe reinitailize happens.
1704 observer_.reset(new MockServiceObserver(this));
1705 service_->AddObserver(observer_.get());
1707 // We continue after the init task is complete including the callback
1708 // on the current thread.
1709 FlushDbThreadTasks();
1710 base::MessageLoop::current()->PostTask(
1712 base::Bind(&AppCacheStorageImplTest::Continue_Reinitialize,
1713 base::Unretained(this),
1717 void Continue_Reinitialize(ReinitTestCase test_case) {
1718 const int kMockProcessId = 1;
1719 backend_.reset(new AppCacheBackendImpl);
1720 backend_->Initialize(service_.get(), &frontend_, kMockProcessId);
1722 if (test_case == CORRUPT_SQL_ON_INSTALL) {
1723 // Break the db file
1724 EXPECT_FALSE(database()->was_corruption_detected());
1725 ASSERT_TRUE(sql::test::CorruptSizeInHeader(
1726 temp_directory_.path().AppendASCII("Index")));
1729 if (test_case == CORRUPT_CACHE_ON_INSTALL ||
1730 test_case == CORRUPT_SQL_ON_INSTALL) {
1731 // Try to create a new appcache, the resulting update job will
1732 // eventually fail when it gets to disk cache initialization.
1733 backend_->RegisterHost(1);
1734 AppCacheHost* host1 = backend_->GetHost(1);
1735 const GURL kEmptyPageUrl(MockHttpServer::GetMockUrl("empty.html"));
1736 host1->first_party_url_ = kEmptyPageUrl;
1737 host1->SelectCache(kEmptyPageUrl,
1739 MockHttpServer::GetMockUrl("manifest"));
1741 ASSERT_EQ(CORRUPT_CACHE_ON_LOAD_EXISTING, test_case);
1742 // Try to access the existing cache manifest.
1743 // The URLRequestJob will eventually fail when it gets to disk
1744 // cache initialization.
1745 backend_->RegisterHost(2);
1746 AppCacheHost* host2 = backend_->GetHost(2);
1747 GURL manifest_url = MockHttpServer::GetMockUrl("manifest");
1748 request_ = service()->request_context()->CreateRequest(
1749 manifest_url, net::DEFAULT_PRIORITY, NULL, NULL);
1750 AppCacheInterceptor::SetExtraRequestInfo(
1751 request_.get(), service_.get(),
1752 backend_->process_id(), host2->host_id(),
1753 ResourceType::MAIN_FRAME);
1757 PushNextTask(base::Bind(
1758 &AppCacheStorageImplTest::Verify_Reinitialized,
1759 base::Unretained(this),
1763 void Verify_Reinitialized(ReinitTestCase test_case) {
1764 // Verify we got notified of reinit and a new storage instance is created,
1765 // and that the old data has been deleted.
1766 EXPECT_TRUE(observer_->observed_old_storage_.get());
1767 EXPECT_TRUE(observer_->observed_old_storage_->storage() != storage());
1768 EXPECT_FALSE(PathExists(
1769 temp_directory_.path().AppendASCII("Cache").AppendASCII("index")));
1770 EXPECT_FALSE(PathExists(
1771 temp_directory_.path().AppendASCII("Index")));
1773 if (test_case == CORRUPT_SQL_ON_INSTALL) {
1774 AppCacheStorageImpl* storage = static_cast<AppCacheStorageImpl*>(
1775 observer_->observed_old_storage_->storage());
1776 EXPECT_TRUE(storage->database_->was_corruption_detected());
1779 // Verify that the hosts saw appropriate events.
1780 if (test_case == CORRUPT_CACHE_ON_INSTALL ||
1781 test_case == CORRUPT_SQL_ON_INSTALL) {
1782 EXPECT_TRUE(frontend_.error_event_was_raised_);
1783 AppCacheHost* host1 = backend_->GetHost(1);
1784 EXPECT_FALSE(host1->associated_cache());
1785 EXPECT_FALSE(host1->group_being_updated_);
1786 EXPECT_TRUE(host1->disabled_storage_reference_.get());
1788 ASSERT_EQ(CORRUPT_CACHE_ON_LOAD_EXISTING, test_case);
1789 AppCacheHost* host2 = backend_->GetHost(2);
1790 EXPECT_EQ(1, host2->main_resource_cache_->cache_id());
1791 EXPECT_TRUE(host2->disabled_storage_reference_.get());
1794 // Cleanup and claim victory.
1795 service_->RemoveObserver(observer_.get());
1802 // Test case helpers --------------------------------------------------
1804 AppCacheService* service() {
1805 return service_.get();
1808 AppCacheStorageImpl* storage() {
1809 return static_cast<AppCacheStorageImpl*>(service()->storage());
1812 AppCacheDatabase* database() {
1813 return storage()->database_;
1816 MockStorageDelegate* delegate() {
1817 return delegate_.get();
1820 void MakeCacheAndGroup(
1821 const GURL& manifest_url, int64 group_id, int64 cache_id,
1822 bool add_to_database) {
1823 AppCacheEntry default_entry(
1824 AppCacheEntry::EXPLICIT, cache_id + kDefaultEntryIdOffset,
1826 group_ = new AppCacheGroup(storage(), manifest_url, group_id);
1827 cache_ = new AppCache(storage(), cache_id);
1828 cache_->AddEntry(kDefaultEntryUrl, default_entry);
1829 cache_->set_complete(true);
1830 group_->AddCache(cache_.get());
1831 if (add_to_database) {
1832 AppCacheDatabase::GroupRecord group_record;
1833 group_record.group_id = group_id;
1834 group_record.manifest_url = manifest_url;
1835 group_record.origin = manifest_url.GetOrigin();
1836 EXPECT_TRUE(database()->InsertGroup(&group_record));
1837 AppCacheDatabase::CacheRecord cache_record;
1838 cache_record.cache_id = cache_id;
1839 cache_record.group_id = group_id;
1840 cache_record.online_wildcard = false;
1841 cache_record.update_time = kZeroTime;
1842 cache_record.cache_size = kDefaultEntrySize;
1843 EXPECT_TRUE(database()->InsertCache(&cache_record));
1844 AppCacheDatabase::EntryRecord entry_record;
1845 entry_record.cache_id = cache_id;
1846 entry_record.url = kDefaultEntryUrl;
1847 entry_record.flags = default_entry.types();
1848 entry_record.response_id = default_entry.response_id();
1849 entry_record.response_size = default_entry.response_size();
1850 EXPECT_TRUE(database()->InsertEntry(&entry_record));
1852 storage()->usage_map_[manifest_url.GetOrigin()] =
1853 default_entry.response_size();
1857 // Data members --------------------------------------------------
1859 scoped_ptr<base::WaitableEvent> test_finished_event_;
1860 std::stack<base::Closure> task_stack_;
1861 scoped_ptr<AppCacheService> service_;
1862 scoped_ptr<MockStorageDelegate> delegate_;
1863 scoped_refptr<MockQuotaManagerProxy> mock_quota_manager_proxy_;
1864 scoped_refptr<AppCacheGroup> group_;
1865 scoped_refptr<AppCache> cache_;
1866 scoped_refptr<AppCache> cache2_;
1868 // Specifically for the Reinitalize test.
1869 base::ScopedTempDir temp_directory_;
1870 scoped_ptr<MockServiceObserver> observer_;
1871 MockAppCacheFrontend frontend_;
1872 scoped_ptr<AppCacheBackendImpl> backend_;
1873 scoped_ptr<net::URLRequest> request_;
1877 TEST_F(AppCacheStorageImplTest, LoadCache_Miss) {
1878 RunTestOnIOThread(&AppCacheStorageImplTest::LoadCache_Miss);
1881 TEST_F(AppCacheStorageImplTest, LoadCache_NearHit) {
1882 RunTestOnIOThread(&AppCacheStorageImplTest::LoadCache_NearHit);
1885 TEST_F(AppCacheStorageImplTest, CreateGroupInEmptyOrigin) {
1886 RunTestOnIOThread(&AppCacheStorageImplTest::CreateGroupInEmptyOrigin);
1889 TEST_F(AppCacheStorageImplTest, CreateGroupInPopulatedOrigin) {
1890 RunTestOnIOThread(&AppCacheStorageImplTest::CreateGroupInPopulatedOrigin);
1893 TEST_F(AppCacheStorageImplTest, LoadGroupAndCache_FarHit) {
1894 RunTestOnIOThread(&AppCacheStorageImplTest::LoadGroupAndCache_FarHit);
1897 TEST_F(AppCacheStorageImplTest, StoreNewGroup) {
1898 RunTestOnIOThread(&AppCacheStorageImplTest::StoreNewGroup);
1901 TEST_F(AppCacheStorageImplTest, StoreExistingGroup) {
1902 RunTestOnIOThread(&AppCacheStorageImplTest::StoreExistingGroup);
1905 TEST_F(AppCacheStorageImplTest, StoreExistingGroupExistingCache) {
1906 RunTestOnIOThread(&AppCacheStorageImplTest::StoreExistingGroupExistingCache);
1909 TEST_F(AppCacheStorageImplTest, FailStoreGroup) {
1910 RunTestOnIOThread(&AppCacheStorageImplTest::FailStoreGroup);
1913 TEST_F(AppCacheStorageImplTest, MakeGroupObsolete) {
1914 RunTestOnIOThread(&AppCacheStorageImplTest::MakeGroupObsolete);
1917 TEST_F(AppCacheStorageImplTest, MarkEntryAsForeign) {
1918 RunTestOnIOThread(&AppCacheStorageImplTest::MarkEntryAsForeign);
1921 TEST_F(AppCacheStorageImplTest, MarkEntryAsForeignWithLoadInProgress) {
1923 &AppCacheStorageImplTest::MarkEntryAsForeignWithLoadInProgress);
1926 TEST_F(AppCacheStorageImplTest, FindNoMainResponse) {
1927 RunTestOnIOThread(&AppCacheStorageImplTest::FindNoMainResponse);
1930 TEST_F(AppCacheStorageImplTest, BasicFindMainResponseInDatabase) {
1932 &AppCacheStorageImplTest::BasicFindMainResponseInDatabase);
1935 TEST_F(AppCacheStorageImplTest, BasicFindMainResponseInWorkingSet) {
1937 &AppCacheStorageImplTest::BasicFindMainResponseInWorkingSet);
1940 TEST_F(AppCacheStorageImplTest, BasicFindMainFallbackResponseInDatabase) {
1942 &AppCacheStorageImplTest::BasicFindMainFallbackResponseInDatabase);
1945 TEST_F(AppCacheStorageImplTest, BasicFindMainFallbackResponseInWorkingSet) {
1947 &AppCacheStorageImplTest::BasicFindMainFallbackResponseInWorkingSet);
1950 TEST_F(AppCacheStorageImplTest, BasicFindMainInterceptResponseInDatabase) {
1952 &AppCacheStorageImplTest::BasicFindMainInterceptResponseInDatabase);
1955 TEST_F(AppCacheStorageImplTest, BasicFindMainInterceptResponseInWorkingSet) {
1957 &AppCacheStorageImplTest::BasicFindMainInterceptResponseInWorkingSet);
1960 TEST_F(AppCacheStorageImplTest, FindMainResponseWithMultipleHits) {
1962 &AppCacheStorageImplTest::FindMainResponseWithMultipleHits);
1965 TEST_F(AppCacheStorageImplTest, FindMainResponseExclusionsInDatabase) {
1967 &AppCacheStorageImplTest::FindMainResponseExclusionsInDatabase);
1970 TEST_F(AppCacheStorageImplTest, FindMainResponseExclusionsInWorkingSet) {
1972 &AppCacheStorageImplTest::FindMainResponseExclusionsInWorkingSet);
1975 TEST_F(AppCacheStorageImplTest, FindInterceptPatternMatchInWorkingSet) {
1977 &AppCacheStorageImplTest::FindInterceptPatternMatchInWorkingSet);
1980 TEST_F(AppCacheStorageImplTest, FindInterceptPatternMatchInDatabase) {
1982 &AppCacheStorageImplTest::FindInterceptPatternMatchInDatabase);
1985 TEST_F(AppCacheStorageImplTest, FindFallbackPatternMatchInWorkingSet) {
1987 &AppCacheStorageImplTest::FindFallbackPatternMatchInWorkingSet);
1990 TEST_F(AppCacheStorageImplTest, FindFallbackPatternMatchInDatabase) {
1992 &AppCacheStorageImplTest::FindFallbackPatternMatchInDatabase);
1995 TEST_F(AppCacheStorageImplTest, Reinitialize1) {
1996 RunTestOnIOThread(&AppCacheStorageImplTest::Reinitialize1);
1999 TEST_F(AppCacheStorageImplTest, Reinitialize2) {
2000 RunTestOnIOThread(&AppCacheStorageImplTest::Reinitialize2);
2003 TEST_F(AppCacheStorageImplTest, Reinitialize3) {
2004 RunTestOnIOThread(&AppCacheStorageImplTest::Reinitialize3);
2007 // That's all folks!
2009 } // namespace appcache