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. 4 5 #include <stack> 6 7 #include "base/bind.h" 8 #include "base/bind_helpers.h" 9 #include "base/callback.h" 10 #include "base/files/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.h" 17 #include "content/browser/appcache/appcache_backend_impl.h" 18 #include "content/browser/appcache/appcache_database.h" 19 #include "content/browser/appcache/appcache_entry.h" 20 #include "content/browser/appcache/appcache_group.h" 21 #include "content/browser/appcache/appcache_host.h" 22 #include "content/browser/appcache/appcache_interceptor.h" 23 #include "content/browser/appcache/appcache_request_handler.h" 24 #include "content/browser/appcache/appcache_service_impl.h" 25 #include "content/browser/appcache/appcache_storage_impl.h" 26 #include "net/base/net_errors.h" 27 #include "net/base/request_priority.h" 28 #include "net/http/http_response_headers.h" 29 #include "net/url_request/url_request_error_job.h" 30 #include "net/url_request/url_request_job_factory_impl.h" 31 #include "net/url_request/url_request_test_job.h" 32 #include "net/url_request/url_request_test_util.h" 33 #include "sql/test/test_helpers.h" 34 #include "storage/browser/quota/quota_manager.h" 35 #include "testing/gtest/include/gtest/gtest.h" 36 37 namespace content { 38 39 namespace { 40 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()); 67 68 const int kManifestEntryIdOffset = 100; 69 const int kFallbackEntryIdOffset = 1000; 70 71 const GURL kDefaultEntryUrl("http://blah/makecacheandgroup_default_entry"); 72 const int kDefaultEntrySize = 10; 73 const int kDefaultEntryIdOffset = 12345; 74 75 const int kMockQuota = 5000; 76 77 // The Reinitialize test needs some http accessible resources to run, 78 // we mock stuff inprocess for that. 79 class MockHttpServer { 80 public: 81 static GURL GetMockUrl(const std::string& path) { 82 return GURL("http://mockhost/" + path); 83 } 84 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); 89 90 std::string headers, body; 91 GetMockResponse(request->url().path(), &headers, &body); 92 return new net::URLRequestTestJob( 93 request, network_delegate, headers, body, true); 94 } 95 96 private: 97 static void GetMockResponse(const std::string& path, 98 std::string* headers, 99 std::string* body) { 100 const char manifest_headers[] = 101 "HTTP/1.1 200 OK\0" 102 "Content-type: text/cache-manifest\0" 103 "\0"; 104 const char page_headers[] = 105 "HTTP/1.1 200 OK\0" 106 "Content-type: text/html\0" 107 "\0"; 108 const char not_found_headers[] = 109 "HTTP/1.1 404 NOT FOUND\0" 110 "\0"; 111 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)); 117 (*body) = ""; 118 } else { 119 (*headers) = std::string(not_found_headers, 120 arraysize(not_found_headers)); 121 (*body) = ""; 122 } 123 } 124 }; 125 126 class MockHttpServerJobFactory 127 : public net::URLRequestJobFactory::ProtocolHandler { 128 public: 129 virtual net::URLRequestJob* MaybeCreateJob( 130 net::URLRequest* request, 131 net::NetworkDelegate* network_delegate) const OVERRIDE { 132 return MockHttpServer::CreateJob(request, network_delegate); 133 } 134 }; 135 136 class IOThread : public base::Thread { 137 public: 138 explicit IOThread(const char* name) 139 : base::Thread(name) { 140 } 141 142 virtual ~IOThread() { 143 Stop(); 144 } 145 146 net::URLRequestContext* request_context() { 147 return request_context_.get(); 148 } 149 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(); 158 } 159 160 virtual void CleanUp() OVERRIDE { 161 request_context_.reset(); 162 job_factory_.reset(); 163 } 164 165 private: 166 scoped_ptr<net::URLRequestJobFactory> job_factory_; 167 scoped_ptr<net::URLRequestContext> request_context_; 168 }; 169 170 scoped_ptr<IOThread> io_thread; 171 scoped_ptr<base::Thread> db_thread; 172 173 } // namespace 174 175 class AppCacheStorageImplTest : public testing::Test { 176 public: 177 class MockStorageDelegate : public AppCacheStorage::Delegate { 178 public: 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_(kAppCacheNoCacheId), test_(test) { 183 } 184 185 virtual void OnCacheLoaded(AppCache* cache, int64 cache_id) OVERRIDE { 186 loaded_cache_ = cache; 187 loaded_cache_id_ = cache_id; 188 test_->ScheduleNextTask(); 189 } 190 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() 196 : NULL; 197 test_->ScheduleNextTask(); 198 } 199 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(); 207 } 208 209 virtual void OnGroupMadeObsolete(AppCacheGroup* group, 210 bool success, 211 int response_code) OVERRIDE { 212 obsoleted_group_ = group; 213 obsoleted_success_ = success; 214 test_->ScheduleNextTask(); 215 } 216 217 virtual void OnMainResponseFound(const GURL& url, 218 const AppCacheEntry& entry, 219 const GURL& namespace_entry_url, 220 const AppCacheEntry& fallback_entry, 221 int64 cache_id, 222 int64 group_id, 223 const GURL& manifest_url) OVERRIDE { 224 found_url_ = url; 225 found_entry_ = entry; 226 found_namespace_entry_url_ = namespace_entry_url; 227 found_fallback_entry_ = fallback_entry; 228 found_cache_id_ = cache_id; 229 found_group_id_ = group_id; 230 found_manifest_url_ = manifest_url; 231 test_->ScheduleNextTask(); 232 } 233 234 scoped_refptr<AppCache> loaded_cache_; 235 int64 loaded_cache_id_; 236 scoped_refptr<AppCacheGroup> loaded_group_; 237 GURL loaded_manifest_url_; 238 scoped_refptr<AppCache> loaded_groups_newest_cache_; 239 scoped_refptr<AppCacheGroup> stored_group_; 240 bool stored_group_success_; 241 bool would_exceed_quota_; 242 scoped_refptr<AppCacheGroup> obsoleted_group_; 243 bool obsoleted_success_; 244 GURL found_url_; 245 AppCacheEntry found_entry_; 246 GURL found_namespace_entry_url_; 247 AppCacheEntry found_fallback_entry_; 248 int64 found_cache_id_; 249 int64 found_group_id_; 250 GURL found_manifest_url_; 251 AppCacheStorageImplTest* test_; 252 }; 253 254 class MockQuotaManager : public storage::QuotaManager { 255 public: 256 MockQuotaManager() 257 : QuotaManager(true /* is_incognito */, 258 base::FilePath(), 259 io_thread->message_loop_proxy().get(), 260 db_thread->message_loop_proxy().get(), 261 NULL), 262 async_(false) {} 263 264 virtual void GetUsageAndQuota( 265 const GURL& origin, 266 storage::StorageType type, 267 const GetUsageAndQuotaCallback& callback) OVERRIDE { 268 EXPECT_EQ(storage::kStorageTypeTemporary, type); 269 if (async_) { 270 base::MessageLoop::current()->PostTask( 271 FROM_HERE, 272 base::Bind(&MockQuotaManager::CallCallback, 273 base::Unretained(this), 274 callback)); 275 return; 276 } 277 CallCallback(callback); 278 } 279 280 void CallCallback(const GetUsageAndQuotaCallback& callback) { 281 callback.Run(storage::kQuotaStatusOk, 0, kMockQuota); 282 } 283 284 bool async_; 285 286 protected: 287 virtual ~MockQuotaManager() {} 288 }; 289 290 class MockQuotaManagerProxy : public storage::QuotaManagerProxy { 291 public: 292 MockQuotaManagerProxy() 293 : QuotaManagerProxy(NULL, NULL), 294 notify_storage_accessed_count_(0), 295 notify_storage_modified_count_(0), 296 last_delta_(0), 297 mock_manager_(new MockQuotaManager) { 298 manager_ = mock_manager_.get(); 299 } 300 301 virtual void NotifyStorageAccessed(storage::QuotaClient::ID client_id, 302 const GURL& origin, 303 storage::StorageType type) OVERRIDE { 304 EXPECT_EQ(storage::QuotaClient::kAppcache, client_id); 305 EXPECT_EQ(storage::kStorageTypeTemporary, type); 306 ++notify_storage_accessed_count_; 307 last_origin_ = origin; 308 } 309 310 virtual void NotifyStorageModified(storage::QuotaClient::ID client_id, 311 const GURL& origin, 312 storage::StorageType type, 313 int64 delta) OVERRIDE { 314 EXPECT_EQ(storage::QuotaClient::kAppcache, client_id); 315 EXPECT_EQ(storage::kStorageTypeTemporary, type); 316 ++notify_storage_modified_count_; 317 last_origin_ = origin; 318 last_delta_ = delta; 319 } 320 321 // Not needed for our tests. 322 virtual void RegisterClient(storage::QuotaClient* client) OVERRIDE {} 323 virtual void NotifyOriginInUse(const GURL& origin) OVERRIDE {} 324 virtual void NotifyOriginNoLongerInUse(const GURL& origin) OVERRIDE {} 325 virtual void SetUsageCacheEnabled(storage::QuotaClient::ID client_id, 326 const GURL& origin, 327 storage::StorageType type, 328 bool enabled) OVERRIDE {} 329 virtual void GetUsageAndQuota( 330 base::SequencedTaskRunner* original_task_runner, 331 const GURL& origin, 332 storage::StorageType type, 333 const GetUsageAndQuotaCallback& callback) OVERRIDE {} 334 335 int notify_storage_accessed_count_; 336 int notify_storage_modified_count_; 337 GURL last_origin_; 338 int last_delta_; 339 scoped_refptr<MockQuotaManager> mock_manager_; 340 341 protected: 342 virtual ~MockQuotaManagerProxy() {} 343 }; 344 345 template <class Method> 346 void RunMethod(Method method) { 347 (this->*method)(); 348 } 349 350 // Helper callback to run a test on our io_thread. The io_thread is spun up 351 // once and reused for all tests. 352 template <class Method> 353 void MethodWrapper(Method method) { 354 SetUpTest(); 355 356 // Ensure InitTask execution prior to conducting a test. 357 FlushDbThreadTasks(); 358 359 // We also have to wait for InitTask completion call to be performed 360 // on the IO thread prior to running the test. Its guaranteed to be 361 // queued by this time. 362 base::MessageLoop::current()->PostTask( 363 FROM_HERE, 364 base::Bind(&AppCacheStorageImplTest::RunMethod<Method>, 365 base::Unretained(this), 366 method)); 367 } 368 369 static void SetUpTestCase() { 370 // We start both threads as TYPE_IO because we also use the db_thead 371 // for the disk_cache which needs to be of TYPE_IO. 372 base::Thread::Options options(base::MessageLoop::TYPE_IO, 0); 373 io_thread.reset(new IOThread("AppCacheTest.IOThread")); 374 ASSERT_TRUE(io_thread->StartWithOptions(options)); 375 db_thread.reset(new base::Thread("AppCacheTest::DBThread")); 376 ASSERT_TRUE(db_thread->StartWithOptions(options)); 377 } 378 379 static void TearDownTestCase() { 380 io_thread.reset(NULL); 381 db_thread.reset(NULL); 382 } 383 384 // Test harness -------------------------------------------------- 385 386 AppCacheStorageImplTest() { 387 } 388 389 template <class Method> 390 void RunTestOnIOThread(Method method) { 391 test_finished_event_ .reset(new base::WaitableEvent(false, false)); 392 io_thread->message_loop()->PostTask( 393 FROM_HERE, base::Bind(&AppCacheStorageImplTest::MethodWrapper<Method>, 394 base::Unretained(this), method)); 395 test_finished_event_->Wait(); 396 } 397 398 void SetUpTest() { 399 DCHECK(base::MessageLoop::current() == io_thread->message_loop()); 400 service_.reset(new AppCacheServiceImpl(NULL)); 401 service_->Initialize(base::FilePath(), db_thread->task_runner(), NULL); 402 mock_quota_manager_proxy_ = new MockQuotaManagerProxy(); 403 service_->quota_manager_proxy_ = mock_quota_manager_proxy_; 404 delegate_.reset(new MockStorageDelegate(this)); 405 } 406 407 void TearDownTest() { 408 DCHECK(base::MessageLoop::current() == io_thread->message_loop()); 409 storage()->CancelDelegateCallbacks(delegate()); 410 group_ = NULL; 411 cache_ = NULL; 412 cache2_ = NULL; 413 mock_quota_manager_proxy_ = NULL; 414 delegate_.reset(); 415 service_.reset(); 416 FlushDbThreadTasks(); 417 } 418 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( 424 FROM_HERE, 425 base::Bind(&AppCacheStorageImplTest::TestFinishedUnwound, 426 base::Unretained(this))); 427 } 428 429 void TestFinishedUnwound() { 430 TearDownTest(); 431 test_finished_event_->Signal(); 432 } 433 434 void PushNextTask(const base::Closure& task) { 435 task_stack_.push(task); 436 } 437 438 void ScheduleNextTask() { 439 DCHECK(base::MessageLoop::current() == io_thread->message_loop()); 440 if (task_stack_.empty()) { 441 return; 442 } 443 base::MessageLoop::current()->PostTask(FROM_HERE, task_stack_.top()); 444 task_stack_.pop(); 445 } 446 447 static void SignalEvent(base::WaitableEvent* event) { 448 event->Signal(); 449 } 450 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)); 457 event.Wait(); 458 } 459 460 // LoadCache_Miss ---------------------------------------------------- 461 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))); 467 468 storage()->LoadCache(111, delegate()); 469 EXPECT_NE(111, delegate()->loaded_cache_id_); 470 } 471 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_); 477 TestFinished(); 478 } 479 480 // LoadCache_NearHit ------------------------------------------------- 481 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. 486 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)); 491 492 // Conduct the test. 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_); 498 TestFinished(); 499 } 500 501 // CreateGroup -------------------------------------------- 502 503 void CreateGroupInEmptyOrigin() { 504 // Attempt to load a group that doesn't exist, one should 505 // be created for us, but not stored. 506 507 // Since the origin has no groups, the storage class will respond 508 // syncly. 509 storage()->LoadOrCreateGroup(kManifestUrl, delegate()); 510 Verify_CreateGroup(); 511 } 512 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))); 518 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; 522 523 storage()->LoadOrCreateGroup(kManifestUrl, delegate()); 524 EXPECT_FALSE(delegate()->loaded_group_.get()); 525 } 526 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()); 532 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)); 537 538 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_accessed_count_); 539 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_); 540 541 TestFinished(); 542 } 543 544 // LoadGroupAndCache_FarHit -------------------------------------- 545 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))); 552 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); 556 group_ = NULL; 557 cache_ = NULL; 558 559 // Conduct the cache load test, completes async 560 storage()->LoadCache(1, delegate()); 561 } 562 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_); 567 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()); 572 573 EXPECT_EQ(1, mock_quota_manager_proxy_->notify_storage_accessed_count_); 574 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_); 575 576 // Drop things from the working set. 577 delegate()->loaded_cache_ = NULL; 578 EXPECT_FALSE(delegate()->loaded_group_.get()); 579 580 // Conduct the group load test, also complete asynchronously. 581 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_LoadGroup_Far_Hit, 582 base::Unretained(this))); 583 584 storage()->LoadOrCreateGroup(kManifestUrl, delegate()); 585 } 586 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_); 595 TestFinished(); 596 } 597 598 // StoreNewGroup -------------------------------------- 599 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))); 604 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, 611 kDefaultEntrySize)); 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. 614 615 // Have the quota manager retrun asynchronously for this test. 616 mock_quota_manager_proxy_->mock_manager_->async_ = true; 617 618 // Conduct the store test. 619 storage()->StoreGroupAndNewestCache(group_.get(), cache_.get(), delegate()); 620 EXPECT_FALSE(delegate()->stored_group_success_); 621 } 622 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()); 628 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)); 634 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_); 640 641 TestFinished(); 642 } 643 644 // StoreExistingGroup -------------------------------------- 645 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))); 650 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]); 655 656 // And a newest unstored complete cache. 657 cache2_ = new AppCache(storage(), 2); 658 cache2_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::MASTER, 1, 659 kDefaultEntrySize + 100)); 660 661 // Conduct the test. 662 storage()->StoreGroupAndNewestCache( 663 group_.get(), cache2_.get(), delegate()); 664 EXPECT_FALSE(delegate()->stored_group_success_); 665 } 666 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()); 672 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)); 678 679 // The old cache should have been deleted 680 EXPECT_FALSE(database()->FindCache(1, &cache_record)); 681 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_); 687 688 TestFinished(); 689 } 690 691 // StoreExistingGroupExistingCache ------------------------------- 692 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". 697 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]); 702 703 // Change the cache. 704 base::Time now = base::Time::Now(); 705 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::MASTER, 1, 100)); 706 cache_->set_update_time(now); 707 708 PushNextTask(base::Bind( 709 &AppCacheStorageImplTest::Verify_StoreExistingGroupExistingCache, 710 base::Unretained(this), now)); 711 712 // Conduct the test. 713 EXPECT_EQ(cache_.get(), group_->newest_complete_cache()); 714 storage()->StoreGroupAndNewestCache(group_.get(), cache_.get(), delegate()); 715 EXPECT_FALSE(delegate()->stored_group_success_); 716 } 717 718 void Verify_StoreExistingGroupExistingCache( 719 base::Time expected_update_time) { 720 EXPECT_TRUE(delegate()->stored_group_success_); 721 EXPECT_EQ(cache_.get(), group_->newest_complete_cache()); 722 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); 730 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); 741 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_); 747 748 TestFinished(); 749 } 750 751 // FailStoreGroup -------------------------------------- 752 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))); 757 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. 768 769 // Conduct the store test. 770 storage()->StoreGroupAndNewestCache(group_.get(), cache_.get(), delegate()); 771 EXPECT_FALSE(delegate()->stored_group_success_); // Expected to be async. 772 } 773 774 void Verify_FailStoreGroup() { 775 EXPECT_FALSE(delegate()->stored_group_success_); 776 EXPECT_TRUE(delegate()->would_exceed_quota_); 777 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)); 783 784 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_accessed_count_); 785 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_); 786 787 TestFinished(); 788 } 789 790 // MakeGroupObsolete ------------------------------- 791 792 void MakeGroupObsolete() { 793 // Make a group obsolete, should complete asynchronously. 794 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_MakeGroupObsolete, 795 base::Unretained(this))); 796 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]); 801 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)); 809 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)); 816 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)); 821 822 // Conduct the test. 823 storage()->MakeGroupObsolete(group_.get(), delegate(), 0); 824 EXPECT_FALSE(group_->is_obsolete()); 825 } 826 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()); 832 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)); 838 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()); 851 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_); 857 858 TestFinished(); 859 } 860 861 // MarkEntryAsForeign ------------------------------- 862 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()); 875 876 // Conduct the test. 877 storage()->MarkEntryAsForeign(kEntryUrl, 1); 878 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()); 882 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); 890 TestFinished(); 891 } 892 893 // MarkEntryAsForeignWithLoadInProgress ------------------------------- 894 895 void MarkEntryAsForeignWithLoadInProgress() { 896 PushNextTask(base::Bind( 897 &AppCacheStorageImplTest::Verify_MarkEntryAsForeignWithLoadInProgress, 898 base::Unretained(this))); 899 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()); 912 cache_ = NULL; 913 group_ = NULL; 914 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); 919 } 920 921 void Verify_MarkEntryAsForeignWithLoadInProgress() { 922 EXPECT_EQ(1, delegate()->loaded_cache_id_); 923 EXPECT_TRUE(delegate()->loaded_cache_.get()); 924 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()); 928 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, 934 entry_record.flags); 935 TestFinished(); 936 } 937 938 // FindNoMainResponse ------------------------------- 939 940 void FindNoMainResponse() { 941 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_FindNoMainResponse, 942 base::Unretained(this))); 943 944 // Conduct the test. 945 storage()->FindResponseForMainRequest(kEntryUrl, GURL(), delegate()); 946 EXPECT_NE(kEntryUrl, delegate()->found_url_); 947 } 948 949 void Verify_FindNoMainResponse() { 950 EXPECT_EQ(kEntryUrl, delegate()->found_url_); 951 EXPECT_TRUE(delegate()->found_manifest_url_.is_empty()); 952 EXPECT_EQ(kAppCacheNoCacheId, delegate()->found_cache_id_); 953 EXPECT_EQ(kAppCacheNoResponseId, delegate()->found_entry_.response_id()); 954 EXPECT_EQ(kAppCacheNoResponseId, 955 delegate()->found_fallback_entry_.response_id()); 956 EXPECT_TRUE(delegate()->found_namespace_entry_url_.is_empty()); 957 EXPECT_EQ(0, delegate()->found_entry_.types()); 958 EXPECT_EQ(0, delegate()->found_fallback_entry_.types()); 959 TestFinished(); 960 } 961 962 // BasicFindMainResponse ------------------------------- 963 964 void BasicFindMainResponseInDatabase() { 965 BasicFindMainResponse(true); 966 } 967 968 void BasicFindMainResponseInWorkingSet() { 969 BasicFindMainResponse(false); 970 } 971 972 void BasicFindMainResponse(bool drop_from_working_set) { 973 PushNextTask(base::Bind( 974 &AppCacheStorageImplTest::Verify_BasicFindMainResponse, 975 base::Unretained(this))); 976 977 // Setup some preconditions. Create a complete cache with an entry 978 // in storage. 979 MakeCacheAndGroup(kManifestUrl, 2, 1, true); 980 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT, 1)); 981 AppCacheDatabase::EntryRecord entry_record; 982 entry_record.cache_id = 1; 983 entry_record.url = kEntryUrl; 984 entry_record.flags = AppCacheEntry::EXPLICIT; 985 entry_record.response_id = 1; 986 EXPECT_TRUE(database()->InsertEntry(&entry_record)); 987 988 // Optionally drop the cache/group pair from the working set. 989 if (drop_from_working_set) { 990 EXPECT_TRUE(cache_->HasOneRef()); 991 cache_ = NULL; 992 EXPECT_TRUE(group_->HasOneRef()); 993 group_ = NULL; 994 } 995 996 // Conduct the test. 997 storage()->FindResponseForMainRequest(kEntryUrl, GURL(), delegate()); 998 EXPECT_NE(kEntryUrl, delegate()->found_url_); 999 } 1000 1001 void Verify_BasicFindMainResponse() { 1002 EXPECT_EQ(kEntryUrl, delegate()->found_url_); 1003 EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_); 1004 EXPECT_EQ(1, delegate()->found_cache_id_); 1005 EXPECT_EQ(2, delegate()->found_group_id_); 1006 EXPECT_EQ(1, delegate()->found_entry_.response_id()); 1007 EXPECT_TRUE(delegate()->found_entry_.IsExplicit()); 1008 EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id()); 1009 TestFinished(); 1010 } 1011 1012 // BasicFindMainFallbackResponse ------------------------------- 1013 1014 void BasicFindMainFallbackResponseInDatabase() { 1015 BasicFindMainFallbackResponse(true); 1016 } 1017 1018 void BasicFindMainFallbackResponseInWorkingSet() { 1019 BasicFindMainFallbackResponse(false); 1020 } 1021 1022 void BasicFindMainFallbackResponse(bool drop_from_working_set) { 1023 PushNextTask(base::Bind( 1024 &AppCacheStorageImplTest::Verify_BasicFindMainFallbackResponse, 1025 base::Unretained(this))); 1026 1027 // Setup some preconditions. Create a complete cache with a 1028 // fallback namespace and entry. 1029 MakeCacheAndGroup(kManifestUrl, 2, 1, true); 1030 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::FALLBACK, 1)); 1031 cache_->AddEntry(kEntryUrl2, AppCacheEntry(AppCacheEntry::FALLBACK, 2)); 1032 cache_->fallback_namespaces_.push_back( 1033 AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE, 1034 kFallbackNamespace2, 1035 kEntryUrl2, 1036 false)); 1037 cache_->fallback_namespaces_.push_back( 1038 AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE, 1039 kFallbackNamespace, 1040 kEntryUrl, 1041 false)); 1042 AppCacheDatabase::CacheRecord cache_record; 1043 std::vector<AppCacheDatabase::EntryRecord> entries; 1044 std::vector<AppCacheDatabase::NamespaceRecord> intercepts; 1045 std::vector<AppCacheDatabase::NamespaceRecord> fallbacks; 1046 std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists; 1047 cache_->ToDatabaseRecords(group_.get(), 1048 &cache_record, 1049 &entries, 1050 &intercepts, 1051 &fallbacks, 1052 &whitelists); 1053 1054 std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter = 1055 entries.begin(); 1056 while (iter != entries.end()) { 1057 // MakeCacheAndGroup has inserted the default entry record already. 1058 if (iter->url != kDefaultEntryUrl) 1059 EXPECT_TRUE(database()->InsertEntry(&(*iter))); 1060 ++iter; 1061 } 1062 1063 EXPECT_TRUE(database()->InsertNamespaceRecords(fallbacks)); 1064 EXPECT_TRUE(database()->InsertOnlineWhiteListRecords(whitelists)); 1065 if (drop_from_working_set) { 1066 EXPECT_TRUE(cache_->HasOneRef()); 1067 cache_ = NULL; 1068 EXPECT_TRUE(group_->HasOneRef()); 1069 group_ = NULL; 1070 } 1071 1072 // Conduct the test. The test url is in both fallback namespace urls, 1073 // but should match the longer of the two. 1074 storage()->FindResponseForMainRequest(kFallbackTestUrl, GURL(), delegate()); 1075 EXPECT_NE(kFallbackTestUrl, delegate()->found_url_); 1076 } 1077 1078 void Verify_BasicFindMainFallbackResponse() { 1079 EXPECT_EQ(kFallbackTestUrl, delegate()->found_url_); 1080 EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_); 1081 EXPECT_EQ(1, delegate()->found_cache_id_); 1082 EXPECT_EQ(2, delegate()->found_group_id_); 1083 EXPECT_FALSE(delegate()->found_entry_.has_response_id()); 1084 EXPECT_EQ(2, delegate()->found_fallback_entry_.response_id()); 1085 EXPECT_EQ(kEntryUrl2, delegate()->found_namespace_entry_url_); 1086 EXPECT_TRUE(delegate()->found_fallback_entry_.IsFallback()); 1087 TestFinished(); 1088 } 1089 1090 // BasicFindMainInterceptResponse ------------------------------- 1091 1092 void BasicFindMainInterceptResponseInDatabase() { 1093 BasicFindMainInterceptResponse(true); 1094 } 1095 1096 void BasicFindMainInterceptResponseInWorkingSet() { 1097 BasicFindMainInterceptResponse(false); 1098 } 1099 1100 void BasicFindMainInterceptResponse(bool drop_from_working_set) { 1101 PushNextTask(base::Bind( 1102 &AppCacheStorageImplTest::Verify_BasicFindMainInterceptResponse, 1103 base::Unretained(this))); 1104 1105 // Setup some preconditions. Create a complete cache with an 1106 // intercept namespace and entry. 1107 MakeCacheAndGroup(kManifestUrl, 2, 1, true); 1108 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::INTERCEPT, 1)); 1109 cache_->AddEntry(kEntryUrl2, AppCacheEntry(AppCacheEntry::INTERCEPT, 2)); 1110 cache_->intercept_namespaces_.push_back( 1111 AppCacheNamespace(APPCACHE_INTERCEPT_NAMESPACE, kInterceptNamespace2, 1112 kEntryUrl2, false)); 1113 cache_->intercept_namespaces_.push_back( 1114 AppCacheNamespace(APPCACHE_INTERCEPT_NAMESPACE, kInterceptNamespace, 1115 kEntryUrl, false)); 1116 AppCacheDatabase::CacheRecord cache_record; 1117 std::vector<AppCacheDatabase::EntryRecord> entries; 1118 std::vector<AppCacheDatabase::NamespaceRecord> intercepts; 1119 std::vector<AppCacheDatabase::NamespaceRecord> fallbacks; 1120 std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists; 1121 cache_->ToDatabaseRecords(group_.get(), 1122 &cache_record, 1123 &entries, 1124 &intercepts, 1125 &fallbacks, 1126 &whitelists); 1127 1128 std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter = 1129 entries.begin(); 1130 while (iter != entries.end()) { 1131 // MakeCacheAndGroup has inserted the default entry record already 1132 if (iter->url != kDefaultEntryUrl) 1133 EXPECT_TRUE(database()->InsertEntry(&(*iter))); 1134 ++iter; 1135 } 1136 1137 EXPECT_TRUE(database()->InsertNamespaceRecords(intercepts)); 1138 EXPECT_TRUE(database()->InsertOnlineWhiteListRecords(whitelists)); 1139 if (drop_from_working_set) { 1140 EXPECT_TRUE(cache_->HasOneRef()); 1141 cache_ = NULL; 1142 EXPECT_TRUE(group_->HasOneRef()); 1143 group_ = NULL; 1144 } 1145 1146 // Conduct the test. The test url is in both intercept namespaces, 1147 // but should match the longer of the two. 1148 storage()->FindResponseForMainRequest( 1149 kInterceptTestUrl, GURL(), delegate()); 1150 EXPECT_NE(kInterceptTestUrl, delegate()->found_url_); 1151 } 1152 1153 void Verify_BasicFindMainInterceptResponse() { 1154 EXPECT_EQ(kInterceptTestUrl, delegate()->found_url_); 1155 EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_); 1156 EXPECT_EQ(1, delegate()->found_cache_id_); 1157 EXPECT_EQ(2, delegate()->found_group_id_); 1158 EXPECT_EQ(2, delegate()->found_entry_.response_id()); 1159 EXPECT_TRUE(delegate()->found_entry_.IsIntercept()); 1160 EXPECT_EQ(kEntryUrl2, delegate()->found_namespace_entry_url_); 1161 EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id()); 1162 TestFinished(); 1163 } 1164 1165 // FindInterceptPatternMatch ---------------------------------------- 1166 1167 void FindInterceptPatternMatchInDatabase() { 1168 FindInterceptPatternMatch(true); 1169 } 1170 1171 void FindInterceptPatternMatchInWorkingSet() { 1172 FindInterceptPatternMatch(false); 1173 } 1174 1175 void FindInterceptPatternMatch(bool drop_from_working_set) { 1176 // Setup some preconditions. Create a complete cache with an 1177 // pattern matching intercept namespace and entry. 1178 MakeCacheAndGroup(kManifestUrl, 2, 1, true); 1179 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::INTERCEPT, 1)); 1180 cache_->intercept_namespaces_.push_back( 1181 AppCacheNamespace(APPCACHE_INTERCEPT_NAMESPACE, 1182 kInterceptPatternNamespace, kEntryUrl, true)); 1183 AppCacheDatabase::CacheRecord cache_record; 1184 std::vector<AppCacheDatabase::EntryRecord> entries; 1185 std::vector<AppCacheDatabase::NamespaceRecord> intercepts; 1186 std::vector<AppCacheDatabase::NamespaceRecord> fallbacks; 1187 std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists; 1188 cache_->ToDatabaseRecords(group_.get(), 1189 &cache_record, 1190 &entries, 1191 &intercepts, 1192 &fallbacks, 1193 &whitelists); 1194 1195 std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter = 1196 entries.begin(); 1197 while (iter != entries.end()) { 1198 // MakeCacheAndGroup has inserted the default entry record already 1199 if (iter->url != kDefaultEntryUrl) 1200 EXPECT_TRUE(database()->InsertEntry(&(*iter))); 1201 ++iter; 1202 } 1203 1204 EXPECT_TRUE(database()->InsertNamespaceRecords(intercepts)); 1205 if (drop_from_working_set) { 1206 EXPECT_TRUE(cache_->HasOneRef()); 1207 cache_ = NULL; 1208 EXPECT_TRUE(group_->HasOneRef()); 1209 group_ = NULL; 1210 } 1211 1212 // First test something that does not match the pattern. 1213 PushNextTask(base::Bind( 1214 &AppCacheStorageImplTest::Verify_FindInterceptPatternMatchNegative, 1215 base::Unretained(this))); 1216 storage()->FindResponseForMainRequest( 1217 kInterceptPatternTestNegativeUrl, GURL(), delegate()); 1218 EXPECT_EQ(GURL(), delegate()->found_url_); // Is always async. 1219 } 1220 1221 void Verify_FindInterceptPatternMatchNegative() { 1222 EXPECT_EQ(kInterceptPatternTestNegativeUrl, delegate()->found_url_); 1223 EXPECT_TRUE(delegate()->found_manifest_url_.is_empty()); 1224 EXPECT_EQ(kAppCacheNoCacheId, delegate()->found_cache_id_); 1225 EXPECT_EQ(kAppCacheNoResponseId, delegate()->found_entry_.response_id()); 1226 EXPECT_EQ(kAppCacheNoResponseId, 1227 delegate()->found_fallback_entry_.response_id()); 1228 EXPECT_TRUE(delegate()->found_namespace_entry_url_.is_empty()); 1229 EXPECT_EQ(0, delegate()->found_entry_.types()); 1230 EXPECT_EQ(0, delegate()->found_fallback_entry_.types()); 1231 1232 // Then test something that matches. 1233 PushNextTask(base::Bind( 1234 &AppCacheStorageImplTest::Verify_FindInterceptPatternMatchPositive, 1235 base::Unretained(this))); 1236 storage()->FindResponseForMainRequest( 1237 kInterceptPatternTestPositiveUrl, GURL(), delegate()); 1238 } 1239 1240 void Verify_FindInterceptPatternMatchPositive() { 1241 EXPECT_EQ(kInterceptPatternTestPositiveUrl, delegate()->found_url_); 1242 EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_); 1243 EXPECT_EQ(1, delegate()->found_cache_id_); 1244 EXPECT_EQ(2, delegate()->found_group_id_); 1245 EXPECT_EQ(1, delegate()->found_entry_.response_id()); 1246 EXPECT_TRUE(delegate()->found_entry_.IsIntercept()); 1247 EXPECT_EQ(kEntryUrl, delegate()->found_namespace_entry_url_); 1248 EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id()); 1249 TestFinished(); 1250 } 1251 1252 // FindFallbackPatternMatch ------------------------------- 1253 1254 void FindFallbackPatternMatchInDatabase() { 1255 FindFallbackPatternMatch(true); 1256 } 1257 1258 void FindFallbackPatternMatchInWorkingSet() { 1259 FindFallbackPatternMatch(false); 1260 } 1261 1262 void FindFallbackPatternMatch(bool drop_from_working_set) { 1263 // Setup some preconditions. Create a complete cache with a 1264 // pattern matching fallback namespace and entry. 1265 MakeCacheAndGroup(kManifestUrl, 2, 1, true); 1266 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::FALLBACK, 1)); 1267 cache_->fallback_namespaces_.push_back( 1268 AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE, 1269 kFallbackPatternNamespace, kEntryUrl, true)); 1270 AppCacheDatabase::CacheRecord cache_record; 1271 std::vector<AppCacheDatabase::EntryRecord> entries; 1272 std::vector<AppCacheDatabase::NamespaceRecord> intercepts; 1273 std::vector<AppCacheDatabase::NamespaceRecord> fallbacks; 1274 std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists; 1275 cache_->ToDatabaseRecords(group_.get(), 1276 &cache_record, 1277 &entries, 1278 &intercepts, 1279 &fallbacks, 1280 &whitelists); 1281 1282 std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter = 1283 entries.begin(); 1284 while (iter != entries.end()) { 1285 // MakeCacheAndGroup has inserted the default entry record already. 1286 if (iter->url != kDefaultEntryUrl) 1287 EXPECT_TRUE(database()->InsertEntry(&(*iter))); 1288 ++iter; 1289 } 1290 1291 EXPECT_TRUE(database()->InsertNamespaceRecords(fallbacks)); 1292 if (drop_from_working_set) { 1293 EXPECT_TRUE(cache_->HasOneRef()); 1294 cache_ = NULL; 1295 EXPECT_TRUE(group_->HasOneRef()); 1296 group_ = NULL; 1297 } 1298 1299 // First test something that does not match the pattern. 1300 PushNextTask(base::Bind( 1301 &AppCacheStorageImplTest::Verify_FindFallbackPatternMatchNegative, 1302 base::Unretained(this))); 1303 storage()->FindResponseForMainRequest( 1304 kFallbackPatternTestNegativeUrl, GURL(), delegate()); 1305 EXPECT_EQ(GURL(), delegate()->found_url_); // Is always async. 1306 } 1307 1308 void Verify_FindFallbackPatternMatchNegative() { 1309 EXPECT_EQ(kFallbackPatternTestNegativeUrl, delegate()->found_url_); 1310 EXPECT_TRUE(delegate()->found_manifest_url_.is_empty()); 1311 EXPECT_EQ(kAppCacheNoCacheId, delegate()->found_cache_id_); 1312 EXPECT_EQ(kAppCacheNoResponseId, delegate()->found_entry_.response_id()); 1313 EXPECT_EQ(kAppCacheNoResponseId, 1314 delegate()->found_fallback_entry_.response_id()); 1315 EXPECT_TRUE(delegate()->found_namespace_entry_url_.is_empty()); 1316 EXPECT_EQ(0, delegate()->found_entry_.types()); 1317 EXPECT_EQ(0, delegate()->found_fallback_entry_.types()); 1318 1319 // Then test something that matches. 1320 PushNextTask(base::Bind( 1321 &AppCacheStorageImplTest::Verify_FindFallbackPatternMatchPositive, 1322 base::Unretained(this))); 1323 storage()->FindResponseForMainRequest( 1324 kFallbackPatternTestPositiveUrl, GURL(), delegate()); 1325 } 1326 1327 void Verify_FindFallbackPatternMatchPositive() { 1328 EXPECT_EQ(kFallbackPatternTestPositiveUrl, delegate()->found_url_); 1329 EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_); 1330 EXPECT_EQ(1, delegate()->found_cache_id_); 1331 EXPECT_EQ(2, delegate()->found_group_id_); 1332 EXPECT_EQ(1, delegate()->found_fallback_entry_.response_id()); 1333 EXPECT_TRUE(delegate()->found_fallback_entry_.IsFallback()); 1334 EXPECT_EQ(kEntryUrl, delegate()->found_namespace_entry_url_); 1335 EXPECT_FALSE(delegate()->found_entry_.has_response_id()); 1336 TestFinished(); 1337 } 1338 1339 // FindMainResponseWithMultipleHits ------------------------------- 1340 1341 void FindMainResponseWithMultipleHits() { 1342 PushNextTask(base::Bind( 1343 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits, 1344 base::Unretained(this))); 1345 1346 // Setup some preconditions, create a few caches with an identical set 1347 // of entries and fallback namespaces. Only the last one remains in 1348 // the working set to simulate appearing as "in use". 1349 MakeMultipleHitCacheAndGroup(kManifestUrl, 1); 1350 MakeMultipleHitCacheAndGroup(kManifestUrl2, 2); 1351 MakeMultipleHitCacheAndGroup(kManifestUrl3, 3); 1352 1353 // Conduct the test, we should find the response from the last cache 1354 // since it's "in use". 1355 storage()->FindResponseForMainRequest(kEntryUrl, GURL(), delegate()); 1356 EXPECT_NE(kEntryUrl, delegate()->found_url_); 1357 } 1358 1359 void MakeMultipleHitCacheAndGroup(const GURL& manifest_url, int id) { 1360 MakeCacheAndGroup(manifest_url, id, id, true); 1361 AppCacheDatabase::EntryRecord entry_record; 1362 1363 // Add an entry for kEntryUrl 1364 entry_record.cache_id = id; 1365 entry_record.url = kEntryUrl; 1366 entry_record.flags = AppCacheEntry::EXPLICIT; 1367 entry_record.response_id = id; 1368 EXPECT_TRUE(database()->InsertEntry(&entry_record)); 1369 cache_->AddEntry( 1370 entry_record.url, 1371 AppCacheEntry(entry_record.flags, entry_record.response_id)); 1372 1373 // Add an entry for the manifestUrl 1374 entry_record.cache_id = id; 1375 entry_record.url = manifest_url; 1376 entry_record.flags = AppCacheEntry::MANIFEST; 1377 entry_record.response_id = id + kManifestEntryIdOffset; 1378 EXPECT_TRUE(database()->InsertEntry(&entry_record)); 1379 cache_->AddEntry( 1380 entry_record.url, 1381 AppCacheEntry(entry_record.flags, entry_record.response_id)); 1382 1383 // Add a fallback entry and namespace 1384 entry_record.cache_id = id; 1385 entry_record.url = kEntryUrl2; 1386 entry_record.flags = AppCacheEntry::FALLBACK; 1387 entry_record.response_id = id + kFallbackEntryIdOffset; 1388 EXPECT_TRUE(database()->InsertEntry(&entry_record)); 1389 cache_->AddEntry( 1390 entry_record.url, 1391 AppCacheEntry(entry_record.flags, entry_record.response_id)); 1392 AppCacheDatabase::NamespaceRecord fallback_namespace_record; 1393 fallback_namespace_record.cache_id = id; 1394 fallback_namespace_record.namespace_.target_url = entry_record.url; 1395 fallback_namespace_record.namespace_.namespace_url = kFallbackNamespace; 1396 fallback_namespace_record.origin = manifest_url.GetOrigin(); 1397 EXPECT_TRUE(database()->InsertNamespace(&fallback_namespace_record)); 1398 cache_->fallback_namespaces_.push_back( 1399 AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE, 1400 kFallbackNamespace, 1401 kEntryUrl2, 1402 false)); 1403 } 1404 1405 void Verify_FindMainResponseWithMultipleHits() { 1406 EXPECT_EQ(kEntryUrl, delegate()->found_url_); 1407 EXPECT_EQ(kManifestUrl3, delegate()->found_manifest_url_); 1408 EXPECT_EQ(3, delegate()->found_cache_id_); 1409 EXPECT_EQ(3, delegate()->found_group_id_); 1410 EXPECT_EQ(3, delegate()->found_entry_.response_id()); 1411 EXPECT_TRUE(delegate()->found_entry_.IsExplicit()); 1412 EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id()); 1413 1414 // Conduct another test preferring kManifestUrl 1415 delegate_.reset(new MockStorageDelegate(this)); 1416 PushNextTask(base::Bind( 1417 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits2, 1418 base::Unretained(this))); 1419 storage()->FindResponseForMainRequest(kEntryUrl, kManifestUrl, delegate()); 1420 EXPECT_NE(kEntryUrl, delegate()->found_url_); 1421 } 1422 1423 void Verify_FindMainResponseWithMultipleHits2() { 1424 EXPECT_EQ(kEntryUrl, delegate()->found_url_); 1425 EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_); 1426 EXPECT_EQ(1, delegate()->found_cache_id_); 1427 EXPECT_EQ(1, delegate()->found_group_id_); 1428 EXPECT_EQ(1, delegate()->found_entry_.response_id()); 1429 EXPECT_TRUE(delegate()->found_entry_.IsExplicit()); 1430 EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id()); 1431 1432 // Conduct the another test preferring kManifestUrl2 1433 delegate_.reset(new MockStorageDelegate(this)); 1434 PushNextTask(base::Bind( 1435 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits3, 1436 base::Unretained(this))); 1437 storage()->FindResponseForMainRequest(kEntryUrl, kManifestUrl2, delegate()); 1438 EXPECT_NE(kEntryUrl, delegate()->found_url_); 1439 } 1440 1441 void Verify_FindMainResponseWithMultipleHits3() { 1442 EXPECT_EQ(kEntryUrl, delegate()->found_url_); 1443 EXPECT_EQ(kManifestUrl2, delegate()->found_manifest_url_); 1444 EXPECT_EQ(2, delegate()->found_cache_id_); 1445 EXPECT_EQ(2, delegate()->found_group_id_); 1446 EXPECT_EQ(2, delegate()->found_entry_.response_id()); 1447 EXPECT_TRUE(delegate()->found_entry_.IsExplicit()); 1448 EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id()); 1449 1450 // Conduct another test with no preferred manifest that hits the fallback. 1451 delegate_.reset(new MockStorageDelegate(this)); 1452 PushNextTask(base::Bind( 1453 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits4, 1454 base::Unretained(this))); 1455 storage()->FindResponseForMainRequest( 1456 kFallbackTestUrl, GURL(), delegate()); 1457 EXPECT_NE(kFallbackTestUrl, delegate()->found_url_); 1458 } 1459 1460 void Verify_FindMainResponseWithMultipleHits4() { 1461 EXPECT_EQ(kFallbackTestUrl, delegate()->found_url_); 1462 EXPECT_EQ(kManifestUrl3, delegate()->found_manifest_url_); 1463 EXPECT_EQ(3, delegate()->found_cache_id_); 1464 EXPECT_EQ(3, delegate()->found_group_id_); 1465 EXPECT_FALSE(delegate()->found_entry_.has_response_id()); 1466 EXPECT_EQ(3 + kFallbackEntryIdOffset, 1467 delegate()->found_fallback_entry_.response_id()); 1468 EXPECT_TRUE(delegate()->found_fallback_entry_.IsFallback()); 1469 EXPECT_EQ(kEntryUrl2, delegate()->found_namespace_entry_url_); 1470 1471 // Conduct another test preferring kManifestUrl2 that hits the fallback. 1472 delegate_.reset(new MockStorageDelegate(this)); 1473 PushNextTask(base::Bind( 1474 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits5, 1475 base::Unretained(this))); 1476 storage()->FindResponseForMainRequest( 1477 kFallbackTestUrl, kManifestUrl2, delegate()); 1478 EXPECT_NE(kFallbackTestUrl, delegate()->found_url_); 1479 } 1480 1481 void Verify_FindMainResponseWithMultipleHits5() { 1482 EXPECT_EQ(kFallbackTestUrl, delegate()->found_url_); 1483 EXPECT_EQ(kManifestUrl2, delegate()->found_manifest_url_); 1484 EXPECT_EQ(2, delegate()->found_cache_id_); 1485 EXPECT_EQ(2, delegate()->found_group_id_); 1486 EXPECT_FALSE(delegate()->found_entry_.has_response_id()); 1487 EXPECT_EQ(2 + kFallbackEntryIdOffset, 1488 delegate()->found_fallback_entry_.response_id()); 1489 EXPECT_TRUE(delegate()->found_fallback_entry_.IsFallback()); 1490 EXPECT_EQ(kEntryUrl2, delegate()->found_namespace_entry_url_); 1491 1492 TestFinished(); 1493 } 1494 1495 // FindMainResponseExclusions ------------------------------- 1496 1497 void FindMainResponseExclusionsInDatabase() { 1498 FindMainResponseExclusions(true); 1499 } 1500 1501 void FindMainResponseExclusionsInWorkingSet() { 1502 FindMainResponseExclusions(false); 1503 } 1504 1505 void FindMainResponseExclusions(bool drop_from_working_set) { 1506 // Setup some preconditions. Create a complete cache with a 1507 // foreign entry, an online namespace, and a second online 1508 // namespace nested within a fallback namespace. 1509 MakeCacheAndGroup(kManifestUrl, 1, 1, true); 1510 cache_->AddEntry(kEntryUrl, 1511 AppCacheEntry(AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN, 1)); 1512 cache_->AddEntry(kEntryUrl2, AppCacheEntry(AppCacheEntry::FALLBACK, 2)); 1513 cache_->fallback_namespaces_.push_back( 1514 AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE, 1515 kFallbackNamespace, 1516 kEntryUrl2, 1517 false)); 1518 cache_->online_whitelist_namespaces_.push_back( 1519 AppCacheNamespace(APPCACHE_NETWORK_NAMESPACE, kOnlineNamespace, 1520 GURL(), false)); 1521 cache_->online_whitelist_namespaces_.push_back( 1522 AppCacheNamespace(APPCACHE_NETWORK_NAMESPACE, 1523 kOnlineNamespaceWithinFallback, GURL(), false)); 1524 1525 AppCacheDatabase::EntryRecord entry_record; 1526 entry_record.cache_id = 1; 1527 entry_record.url = kEntryUrl; 1528 entry_record.flags = AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN; 1529 entry_record.response_id = 1; 1530 EXPECT_TRUE(database()->InsertEntry(&entry_record)); 1531 AppCacheDatabase::OnlineWhiteListRecord whitelist_record; 1532 whitelist_record.cache_id = 1; 1533 whitelist_record.namespace_url = kOnlineNamespace; 1534 EXPECT_TRUE(database()->InsertOnlineWhiteList(&whitelist_record)); 1535 AppCacheDatabase::NamespaceRecord fallback_namespace_record; 1536 fallback_namespace_record.cache_id = 1; 1537 fallback_namespace_record.namespace_.target_url = kEntryUrl2; 1538 fallback_namespace_record.namespace_.namespace_url = kFallbackNamespace; 1539 fallback_namespace_record.origin = kManifestUrl.GetOrigin(); 1540 EXPECT_TRUE(database()->InsertNamespace(&fallback_namespace_record)); 1541 whitelist_record.cache_id = 1; 1542 whitelist_record.namespace_url = kOnlineNamespaceWithinFallback; 1543 EXPECT_TRUE(database()->InsertOnlineWhiteList(&whitelist_record)); 1544 if (drop_from_working_set) { 1545 cache_ = NULL; 1546 group_ = NULL; 1547 } 1548 1549 // We should not find anything for the foreign entry. 1550 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_ExclusionNotFound, 1551 base::Unretained(this), kEntryUrl, 1)); 1552 storage()->FindResponseForMainRequest(kEntryUrl, GURL(), delegate()); 1553 } 1554 1555 void Verify_ExclusionNotFound(GURL expected_url, int phase) { 1556 EXPECT_EQ(expected_url, delegate()->found_url_); 1557 EXPECT_TRUE(delegate()->found_manifest_url_.is_empty()); 1558 EXPECT_EQ(kAppCacheNoCacheId, delegate()->found_cache_id_); 1559 EXPECT_EQ(0, delegate()->found_group_id_); 1560 EXPECT_EQ(kAppCacheNoResponseId, delegate()->found_entry_.response_id()); 1561 EXPECT_EQ(kAppCacheNoResponseId, 1562 delegate()->found_fallback_entry_.response_id()); 1563 EXPECT_TRUE(delegate()->found_namespace_entry_url_.is_empty()); 1564 EXPECT_EQ(0, delegate()->found_entry_.types()); 1565 EXPECT_EQ(0, delegate()->found_fallback_entry_.types()); 1566 1567 if (phase == 1) { 1568 // We should not find anything for the online namespace. 1569 PushNextTask( 1570 base::Bind(&AppCacheStorageImplTest::Verify_ExclusionNotFound, 1571 base::Unretained(this), kOnlineNamespace, 2)); 1572 storage()->FindResponseForMainRequest( 1573 kOnlineNamespace, GURL(), delegate()); 1574 return; 1575 } 1576 if (phase == 2) { 1577 // We should not find anything for the online namespace nested within 1578 // the fallback namespace. 1579 PushNextTask(base::Bind( 1580 &AppCacheStorageImplTest::Verify_ExclusionNotFound, 1581 base::Unretained(this), kOnlineNamespaceWithinFallback, 3)); 1582 storage()->FindResponseForMainRequest( 1583 kOnlineNamespaceWithinFallback, GURL(), delegate()); 1584 return; 1585 } 1586 1587 TestFinished(); 1588 } 1589 1590 // Reinitialize ------------------------------- 1591 // These tests are somewhat of a system integration test. 1592 // They rely on running a mock http server on our IO thread, 1593 // and involves other appcache classes to get some code 1594 // coverage thruout when Reinitialize happens. 1595 1596 class MockServiceObserver : public AppCacheServiceImpl::Observer { 1597 public: 1598 explicit MockServiceObserver(AppCacheStorageImplTest* test) 1599 : test_(test) {} 1600 1601 virtual void OnServiceReinitialized( 1602 AppCacheStorageReference* old_storage_ref) OVERRIDE { 1603 observed_old_storage_ = old_storage_ref; 1604 test_->ScheduleNextTask(); 1605 } 1606 1607 scoped_refptr<AppCacheStorageReference> observed_old_storage_; 1608 AppCacheStorageImplTest* test_; 1609 }; 1610 1611 class MockAppCacheFrontend : public AppCacheFrontend { 1612 public: 1613 MockAppCacheFrontend() : error_event_was_raised_(false) {} 1614 1615 virtual void OnCacheSelected( 1616 int host_id, const AppCacheInfo& info) OVERRIDE {} 1617 virtual void OnStatusChanged(const std::vector<int>& host_ids, 1618 AppCacheStatus status) OVERRIDE {} 1619 virtual void OnEventRaised(const std::vector<int>& host_ids, 1620 AppCacheEventID event_id) OVERRIDE {} 1621 virtual void OnProgressEventRaised( 1622 const std::vector<int>& host_ids, 1623 const GURL& url, 1624 int num_total, int num_complete) OVERRIDE {} 1625 virtual void OnErrorEventRaised(const std::vector<int>& host_ids, 1626 const AppCacheErrorDetails& details) 1627 OVERRIDE { 1628 error_event_was_raised_ = true; 1629 } 1630 virtual void OnLogMessage(int host_id, AppCacheLogLevel log_level, 1631 const std::string& message) OVERRIDE {} 1632 virtual void OnContentBlocked( 1633 int host_id, const GURL& manifest_url) OVERRIDE {} 1634 1635 bool error_event_was_raised_; 1636 }; 1637 1638 enum ReinitTestCase { 1639 CORRUPT_CACHE_ON_INSTALL, 1640 CORRUPT_CACHE_ON_LOAD_EXISTING, 1641 CORRUPT_SQL_ON_INSTALL 1642 }; 1643 1644 void Reinitialize1() { 1645 // Recover from a corrupt disk cache discovered while 1646 // installing a new appcache. 1647 Reinitialize(CORRUPT_CACHE_ON_INSTALL); 1648 } 1649 1650 void Reinitialize2() { 1651 // Recover from a corrupt disk cache discovered while 1652 // trying to load a resource from an existing appcache. 1653 Reinitialize(CORRUPT_CACHE_ON_LOAD_EXISTING); 1654 } 1655 1656 void Reinitialize3() { 1657 // Recover from a corrupt sql database discovered while 1658 // installing a new appcache. 1659 Reinitialize(CORRUPT_SQL_ON_INSTALL); 1660 } 1661 1662 void Reinitialize(ReinitTestCase test_case) { 1663 // Unlike all of the other tests, this one actually read/write files. 1664 ASSERT_TRUE(temp_directory_.CreateUniqueTempDir()); 1665 1666 AppCacheDatabase db(temp_directory_.path().AppendASCII("Index")); 1667 EXPECT_TRUE(db.LazyOpen(true)); 1668 1669 if (test_case == CORRUPT_CACHE_ON_INSTALL || 1670 test_case == CORRUPT_CACHE_ON_LOAD_EXISTING) { 1671 // Create a corrupt/unopenable disk_cache index file. 1672 const std::string kCorruptData("deadbeef"); 1673 base::FilePath disk_cache_directory = 1674 temp_directory_.path().AppendASCII("Cache"); 1675 ASSERT_TRUE(base::CreateDirectory(disk_cache_directory)); 1676 base::FilePath index_file = disk_cache_directory.AppendASCII("index"); 1677 EXPECT_EQ(static_cast<int>(kCorruptData.length()), 1678 base::WriteFile( 1679 index_file, kCorruptData.data(), kCorruptData.length())); 1680 } 1681 1682 // Create records for a degenerate cached manifest that only contains 1683 // one entry for the manifest file resource. 1684 if (test_case == CORRUPT_CACHE_ON_LOAD_EXISTING) { 1685 AppCacheDatabase db(temp_directory_.path().AppendASCII("Index")); 1686 GURL manifest_url = MockHttpServer::GetMockUrl("manifest"); 1687 1688 AppCacheDatabase::GroupRecord group_record; 1689 group_record.group_id = 1; 1690 group_record.manifest_url = manifest_url; 1691 group_record.origin = manifest_url.GetOrigin(); 1692 EXPECT_TRUE(db.InsertGroup(&group_record)); 1693 AppCacheDatabase::CacheRecord cache_record; 1694 cache_record.cache_id = 1; 1695 cache_record.group_id = 1; 1696 cache_record.online_wildcard = false; 1697 cache_record.update_time = kZeroTime; 1698 cache_record.cache_size = kDefaultEntrySize; 1699 EXPECT_TRUE(db.InsertCache(&cache_record)); 1700 AppCacheDatabase::EntryRecord entry_record; 1701 entry_record.cache_id = 1; 1702 entry_record.url = manifest_url; 1703 entry_record.flags = AppCacheEntry::MANIFEST; 1704 entry_record.response_id = 1; 1705 entry_record.response_size = kDefaultEntrySize; 1706 EXPECT_TRUE(db.InsertEntry(&entry_record)); 1707 } 1708 1709 // Recreate the service to point at the db and corruption on disk. 1710 service_.reset(new AppCacheServiceImpl(NULL)); 1711 service_->set_request_context(io_thread->request_context()); 1712 service_->Initialize(temp_directory_.path(), 1713 db_thread->task_runner(), 1714 db_thread->task_runner()); 1715 mock_quota_manager_proxy_ = new MockQuotaManagerProxy(); 1716 service_->quota_manager_proxy_ = mock_quota_manager_proxy_; 1717 delegate_.reset(new MockStorageDelegate(this)); 1718 1719 // Additional setup to observe reinitailize happens. 1720 observer_.reset(new MockServiceObserver(this)); 1721 service_->AddObserver(observer_.get()); 1722 1723 // We continue after the init task is complete including the callback 1724 // on the current thread. 1725 FlushDbThreadTasks(); 1726 base::MessageLoop::current()->PostTask( 1727 FROM_HERE, 1728 base::Bind(&AppCacheStorageImplTest::Continue_Reinitialize, 1729 base::Unretained(this), 1730 test_case)); 1731 } 1732 1733 void Continue_Reinitialize(ReinitTestCase test_case) { 1734 const int kMockProcessId = 1; 1735 backend_.reset(new AppCacheBackendImpl); 1736 backend_->Initialize(service_.get(), &frontend_, kMockProcessId); 1737 1738 if (test_case == CORRUPT_SQL_ON_INSTALL) { 1739 // Break the db file 1740 EXPECT_FALSE(database()->was_corruption_detected()); 1741 ASSERT_TRUE(sql::test::CorruptSizeInHeader( 1742 temp_directory_.path().AppendASCII("Index"))); 1743 } 1744 1745 if (test_case == CORRUPT_CACHE_ON_INSTALL || 1746 test_case == CORRUPT_SQL_ON_INSTALL) { 1747 // Try to create a new appcache, the resulting update job will 1748 // eventually fail when it gets to disk cache initialization. 1749 backend_->RegisterHost(1); 1750 AppCacheHost* host1 = backend_->GetHost(1); 1751 const GURL kEmptyPageUrl(MockHttpServer::GetMockUrl("empty.html")); 1752 host1->first_party_url_ = kEmptyPageUrl; 1753 host1->SelectCache(kEmptyPageUrl, 1754 kAppCacheNoCacheId, 1755 MockHttpServer::GetMockUrl("manifest")); 1756 } else { 1757 ASSERT_EQ(CORRUPT_CACHE_ON_LOAD_EXISTING, test_case); 1758 // Try to access the existing cache manifest. 1759 // The URLRequestJob will eventually fail when it gets to disk 1760 // cache initialization. 1761 backend_->RegisterHost(2); 1762 AppCacheHost* host2 = backend_->GetHost(2); 1763 GURL manifest_url = MockHttpServer::GetMockUrl("manifest"); 1764 request_ = service()->request_context()->CreateRequest( 1765 manifest_url, net::DEFAULT_PRIORITY, NULL, NULL); 1766 AppCacheInterceptor::SetExtraRequestInfo( 1767 request_.get(), service_.get(), 1768 backend_->process_id(), host2->host_id(), 1769 RESOURCE_TYPE_MAIN_FRAME); 1770 request_->Start(); 1771 } 1772 1773 PushNextTask(base::Bind( 1774 &AppCacheStorageImplTest::Verify_Reinitialized, 1775 base::Unretained(this), 1776 test_case)); 1777 } 1778 1779 void Verify_Reinitialized(ReinitTestCase test_case) { 1780 // Verify we got notified of reinit and a new storage instance is created, 1781 // and that the old data has been deleted. 1782 EXPECT_TRUE(observer_->observed_old_storage_.get()); 1783 EXPECT_TRUE(observer_->observed_old_storage_->storage() != storage()); 1784 EXPECT_FALSE(PathExists( 1785 temp_directory_.path().AppendASCII("Cache").AppendASCII("index"))); 1786 EXPECT_FALSE(PathExists( 1787 temp_directory_.path().AppendASCII("Index"))); 1788 1789 if (test_case == CORRUPT_SQL_ON_INSTALL) { 1790 AppCacheStorageImpl* storage = static_cast<AppCacheStorageImpl*>( 1791 observer_->observed_old_storage_->storage()); 1792 EXPECT_TRUE(storage->database_->was_corruption_detected()); 1793 } 1794 1795 // Verify that the hosts saw appropriate events. 1796 if (test_case == CORRUPT_CACHE_ON_INSTALL || 1797 test_case == CORRUPT_SQL_ON_INSTALL) { 1798 EXPECT_TRUE(frontend_.error_event_was_raised_); 1799 AppCacheHost* host1 = backend_->GetHost(1); 1800 EXPECT_FALSE(host1->associated_cache()); 1801 EXPECT_FALSE(host1->group_being_updated_.get()); 1802 EXPECT_TRUE(host1->disabled_storage_reference_.get()); 1803 } else { 1804 ASSERT_EQ(CORRUPT_CACHE_ON_LOAD_EXISTING, test_case); 1805 AppCacheHost* host2 = backend_->GetHost(2); 1806 EXPECT_EQ(1, host2->main_resource_cache_->cache_id()); 1807 EXPECT_TRUE(host2->disabled_storage_reference_.get()); 1808 } 1809 1810 // Cleanup and claim victory. 1811 service_->RemoveObserver(observer_.get()); 1812 request_.reset(); 1813 backend_.reset(); 1814 observer_.reset(); 1815 TestFinished(); 1816 } 1817 1818 // Test case helpers -------------------------------------------------- 1819 1820 AppCacheServiceImpl* service() { 1821 return service_.get(); 1822 } 1823 1824 AppCacheStorageImpl* storage() { 1825 return static_cast<AppCacheStorageImpl*>(service()->storage()); 1826 } 1827 1828 AppCacheDatabase* database() { 1829 return storage()->database_; 1830 } 1831 1832 MockStorageDelegate* delegate() { 1833 return delegate_.get(); 1834 } 1835 1836 void MakeCacheAndGroup( 1837 const GURL& manifest_url, int64 group_id, int64 cache_id, 1838 bool add_to_database) { 1839 AppCacheEntry default_entry( 1840 AppCacheEntry::EXPLICIT, cache_id + kDefaultEntryIdOffset, 1841 kDefaultEntrySize); 1842 group_ = new AppCacheGroup(storage(), manifest_url, group_id); 1843 cache_ = new AppCache(storage(), cache_id); 1844 cache_->AddEntry(kDefaultEntryUrl, default_entry); 1845 cache_->set_complete(true); 1846 group_->AddCache(cache_.get()); 1847 if (add_to_database) { 1848 AppCacheDatabase::GroupRecord group_record; 1849 group_record.group_id = group_id; 1850 group_record.manifest_url = manifest_url; 1851 group_record.origin = manifest_url.GetOrigin(); 1852 EXPECT_TRUE(database()->InsertGroup(&group_record)); 1853 AppCacheDatabase::CacheRecord cache_record; 1854 cache_record.cache_id = cache_id; 1855 cache_record.group_id = group_id; 1856 cache_record.online_wildcard = false; 1857 cache_record.update_time = kZeroTime; 1858 cache_record.cache_size = kDefaultEntrySize; 1859 EXPECT_TRUE(database()->InsertCache(&cache_record)); 1860 AppCacheDatabase::EntryRecord entry_record; 1861 entry_record.cache_id = cache_id; 1862 entry_record.url = kDefaultEntryUrl; 1863 entry_record.flags = default_entry.types(); 1864 entry_record.response_id = default_entry.response_id(); 1865 entry_record.response_size = default_entry.response_size(); 1866 EXPECT_TRUE(database()->InsertEntry(&entry_record)); 1867 1868 storage()->usage_map_[manifest_url.GetOrigin()] = 1869 default_entry.response_size(); 1870 } 1871 } 1872 1873 // Data members -------------------------------------------------- 1874 1875 scoped_ptr<base::WaitableEvent> test_finished_event_; 1876 std::stack<base::Closure> task_stack_; 1877 scoped_ptr<AppCacheServiceImpl> service_; 1878 scoped_ptr<MockStorageDelegate> delegate_; 1879 scoped_refptr<MockQuotaManagerProxy> mock_quota_manager_proxy_; 1880 scoped_refptr<AppCacheGroup> group_; 1881 scoped_refptr<AppCache> cache_; 1882 scoped_refptr<AppCache> cache2_; 1883 1884 // Specifically for the Reinitalize test. 1885 base::ScopedTempDir temp_directory_; 1886 scoped_ptr<MockServiceObserver> observer_; 1887 MockAppCacheFrontend frontend_; 1888 scoped_ptr<AppCacheBackendImpl> backend_; 1889 scoped_ptr<net::URLRequest> request_; 1890 }; 1891 1892 1893 TEST_F(AppCacheStorageImplTest, LoadCache_Miss) { 1894 RunTestOnIOThread(&AppCacheStorageImplTest::LoadCache_Miss); 1895 } 1896 1897 TEST_F(AppCacheStorageImplTest, LoadCache_NearHit) { 1898 RunTestOnIOThread(&AppCacheStorageImplTest::LoadCache_NearHit); 1899 } 1900 1901 TEST_F(AppCacheStorageImplTest, CreateGroupInEmptyOrigin) { 1902 RunTestOnIOThread(&AppCacheStorageImplTest::CreateGroupInEmptyOrigin); 1903 } 1904 1905 TEST_F(AppCacheStorageImplTest, CreateGroupInPopulatedOrigin) { 1906 RunTestOnIOThread(&AppCacheStorageImplTest::CreateGroupInPopulatedOrigin); 1907 } 1908 1909 TEST_F(AppCacheStorageImplTest, LoadGroupAndCache_FarHit) { 1910 RunTestOnIOThread(&AppCacheStorageImplTest::LoadGroupAndCache_FarHit); 1911 } 1912 1913 TEST_F(AppCacheStorageImplTest, StoreNewGroup) { 1914 RunTestOnIOThread(&AppCacheStorageImplTest::StoreNewGroup); 1915 } 1916 1917 TEST_F(AppCacheStorageImplTest, StoreExistingGroup) { 1918 RunTestOnIOThread(&AppCacheStorageImplTest::StoreExistingGroup); 1919 } 1920 1921 TEST_F(AppCacheStorageImplTest, StoreExistingGroupExistingCache) { 1922 RunTestOnIOThread(&AppCacheStorageImplTest::StoreExistingGroupExistingCache); 1923 } 1924 1925 TEST_F(AppCacheStorageImplTest, FailStoreGroup) { 1926 RunTestOnIOThread(&AppCacheStorageImplTest::FailStoreGroup); 1927 } 1928 1929 TEST_F(AppCacheStorageImplTest, MakeGroupObsolete) { 1930 RunTestOnIOThread(&AppCacheStorageImplTest::MakeGroupObsolete); 1931 } 1932 1933 TEST_F(AppCacheStorageImplTest, MarkEntryAsForeign) { 1934 RunTestOnIOThread(&AppCacheStorageImplTest::MarkEntryAsForeign); 1935 } 1936 1937 TEST_F(AppCacheStorageImplTest, MarkEntryAsForeignWithLoadInProgress) { 1938 RunTestOnIOThread( 1939 &AppCacheStorageImplTest::MarkEntryAsForeignWithLoadInProgress); 1940 } 1941 1942 TEST_F(AppCacheStorageImplTest, FindNoMainResponse) { 1943 RunTestOnIOThread(&AppCacheStorageImplTest::FindNoMainResponse); 1944 } 1945 1946 TEST_F(AppCacheStorageImplTest, BasicFindMainResponseInDatabase) { 1947 RunTestOnIOThread( 1948 &AppCacheStorageImplTest::BasicFindMainResponseInDatabase); 1949 } 1950 1951 TEST_F(AppCacheStorageImplTest, BasicFindMainResponseInWorkingSet) { 1952 RunTestOnIOThread( 1953 &AppCacheStorageImplTest::BasicFindMainResponseInWorkingSet); 1954 } 1955 1956 TEST_F(AppCacheStorageImplTest, BasicFindMainFallbackResponseInDatabase) { 1957 RunTestOnIOThread( 1958 &AppCacheStorageImplTest::BasicFindMainFallbackResponseInDatabase); 1959 } 1960 1961 TEST_F(AppCacheStorageImplTest, BasicFindMainFallbackResponseInWorkingSet) { 1962 RunTestOnIOThread( 1963 &AppCacheStorageImplTest::BasicFindMainFallbackResponseInWorkingSet); 1964 } 1965 1966 TEST_F(AppCacheStorageImplTest, BasicFindMainInterceptResponseInDatabase) { 1967 RunTestOnIOThread( 1968 &AppCacheStorageImplTest::BasicFindMainInterceptResponseInDatabase); 1969 } 1970 1971 TEST_F(AppCacheStorageImplTest, BasicFindMainInterceptResponseInWorkingSet) { 1972 RunTestOnIOThread( 1973 &AppCacheStorageImplTest::BasicFindMainInterceptResponseInWorkingSet); 1974 } 1975 1976 TEST_F(AppCacheStorageImplTest, FindMainResponseWithMultipleHits) { 1977 RunTestOnIOThread( 1978 &AppCacheStorageImplTest::FindMainResponseWithMultipleHits); 1979 } 1980 1981 TEST_F(AppCacheStorageImplTest, FindMainResponseExclusionsInDatabase) { 1982 RunTestOnIOThread( 1983 &AppCacheStorageImplTest::FindMainResponseExclusionsInDatabase); 1984 } 1985 1986 TEST_F(AppCacheStorageImplTest, FindMainResponseExclusionsInWorkingSet) { 1987 RunTestOnIOThread( 1988 &AppCacheStorageImplTest::FindMainResponseExclusionsInWorkingSet); 1989 } 1990 1991 TEST_F(AppCacheStorageImplTest, FindInterceptPatternMatchInWorkingSet) { 1992 RunTestOnIOThread( 1993 &AppCacheStorageImplTest::FindInterceptPatternMatchInWorkingSet); 1994 } 1995 1996 TEST_F(AppCacheStorageImplTest, FindInterceptPatternMatchInDatabase) { 1997 RunTestOnIOThread( 1998 &AppCacheStorageImplTest::FindInterceptPatternMatchInDatabase); 1999 } 2000 2001 TEST_F(AppCacheStorageImplTest, FindFallbackPatternMatchInWorkingSet) { 2002 RunTestOnIOThread( 2003 &AppCacheStorageImplTest::FindFallbackPatternMatchInWorkingSet); 2004 } 2005 2006 TEST_F(AppCacheStorageImplTest, FindFallbackPatternMatchInDatabase) { 2007 RunTestOnIOThread( 2008 &AppCacheStorageImplTest::FindFallbackPatternMatchInDatabase); 2009 } 2010 2011 TEST_F(AppCacheStorageImplTest, Reinitialize1) { 2012 RunTestOnIOThread(&AppCacheStorageImplTest::Reinitialize1); 2013 } 2014 2015 TEST_F(AppCacheStorageImplTest, Reinitialize2) { 2016 RunTestOnIOThread(&AppCacheStorageImplTest::Reinitialize2); 2017 } 2018 2019 TEST_F(AppCacheStorageImplTest, Reinitialize3) { 2020 RunTestOnIOThread(&AppCacheStorageImplTest::Reinitialize3); 2021 } 2022 2023 // That's all folks! 2024 2025 } // namespace content 2026