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. 4 5 #include <stack> 6 7 #include "base/bind.h" 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 "testing/gtest/include/gtest/gtest.h" 24 #include "webkit/browser/appcache/appcache.h" 25 #include "webkit/browser/appcache/appcache_backend_impl.h" 26 #include "webkit/browser/appcache/appcache_database.h" 27 #include "webkit/browser/appcache/appcache_entry.h" 28 #include "webkit/browser/appcache/appcache_group.h" 29 #include "webkit/browser/appcache/appcache_host.h" 30 #include "webkit/browser/appcache/appcache_interceptor.h" 31 #include "webkit/browser/appcache/appcache_request_handler.h" 32 #include "webkit/browser/appcache/appcache_service.h" 33 #include "webkit/browser/appcache/appcache_storage_impl.h" 34 #include "webkit/browser/quota/quota_manager.h" 35 36 namespace appcache { 37 38 namespace { 39 40 const base::Time kZeroTime; 41 const GURL kManifestUrl("http://blah/manifest"); 42 const GURL kManifestUrl2("http://blah/manifest2"); 43 const GURL kManifestUrl3("http://blah/manifest3"); 44 const GURL kEntryUrl("http://blah/entry"); 45 const GURL kEntryUrl2("http://blah/entry2"); 46 const GURL kFallbackNamespace("http://blah/fallback_namespace/"); 47 const GURL kFallbackNamespace2("http://blah/fallback_namespace/longer"); 48 const GURL kFallbackTestUrl("http://blah/fallback_namespace/longer/test"); 49 const GURL kOnlineNamespace("http://blah/online_namespace"); 50 const GURL kOnlineNamespaceWithinFallback( 51 "http://blah/fallback_namespace/online/"); 52 const GURL kInterceptNamespace("http://blah/intercept_namespace/"); 53 const GURL kInterceptNamespace2("http://blah/intercept_namespace/longer/"); 54 const GURL kInterceptTestUrl("http://blah/intercept_namespace/longer/test"); 55 const GURL kInterceptPatternNamespace("http://blah/intercept_pattern/*/bar"); 56 const GURL kInterceptPatternTestPositiveUrl( 57 "http://blah/intercept_pattern/foo/bar"); 58 const GURL kInterceptPatternTestNegativeUrl( 59 "http://blah/intercept_pattern/foo/not_bar"); 60 const GURL kFallbackPatternNamespace("http://blah/fallback_pattern/*/bar"); 61 const GURL kFallbackPatternTestPositiveUrl( 62 "http://blah/fallback_pattern/foo/bar"); 63 const GURL kFallbackPatternTestNegativeUrl( 64 "http://blah/fallback_pattern/foo/not_bar"); 65 const GURL kOrigin(kManifestUrl.GetOrigin()); 66 67 const int kManifestEntryIdOffset = 100; 68 const int kFallbackEntryIdOffset = 1000; 69 70 const GURL kDefaultEntryUrl("http://blah/makecacheandgroup_default_entry"); 71 const int kDefaultEntrySize = 10; 72 const int kDefaultEntryIdOffset = 12345; 73 74 const int kMockQuota = 5000; 75 76 // The Reinitialize test needs some http accessible resources to run, 77 // we mock stuff inprocess for that. 78 class MockHttpServer { 79 public: 80 static GURL GetMockUrl(const std::string& path) { 81 return GURL("http://mockhost/" + path); 82 } 83 84 static net::URLRequestJob* CreateJob( 85 net::URLRequest* request, net::NetworkDelegate* network_delegate) { 86 if (request->url().host() != "mockhost") 87 return new net::URLRequestErrorJob(request, network_delegate, -100); 88 89 std::string headers, body; 90 GetMockResponse(request->url().path(), &headers, &body); 91 return new net::URLRequestTestJob( 92 request, network_delegate, headers, body, true); 93 } 94 95 private: 96 static void GetMockResponse(const std::string& path, 97 std::string* headers, 98 std::string* body) { 99 const char manifest_headers[] = 100 "HTTP/1.1 200 OK\0" 101 "Content-type: text/cache-manifest\0" 102 "\0"; 103 const char page_headers[] = 104 "HTTP/1.1 200 OK\0" 105 "Content-type: text/html\0" 106 "\0"; 107 const char not_found_headers[] = 108 "HTTP/1.1 404 NOT FOUND\0" 109 "\0"; 110 111 if (path == "/manifest") { 112 (*headers) = std::string(manifest_headers, arraysize(manifest_headers)); 113 (*body) = "CACHE MANIFEST\n"; 114 } else if (path == "/empty.html") { 115 (*headers) = std::string(page_headers, arraysize(page_headers)); 116 (*body) = ""; 117 } else { 118 (*headers) = std::string(not_found_headers, 119 arraysize(not_found_headers)); 120 (*body) = ""; 121 } 122 } 123 }; 124 125 class MockHttpServerJobFactory 126 : public net::URLRequestJobFactory::ProtocolHandler { 127 public: 128 virtual net::URLRequestJob* MaybeCreateJob( 129 net::URLRequest* request, 130 net::NetworkDelegate* network_delegate) const OVERRIDE { 131 return MockHttpServer::CreateJob(request, network_delegate); 132 } 133 }; 134 135 class IOThread : public base::Thread { 136 public: 137 explicit IOThread(const char* name) 138 : base::Thread(name) { 139 } 140 141 virtual ~IOThread() { 142 Stop(); 143 } 144 145 net::URLRequestContext* request_context() { 146 return request_context_.get(); 147 } 148 149 virtual void Init() OVERRIDE { 150 scoped_ptr<net::URLRequestJobFactoryImpl> factory( 151 new net::URLRequestJobFactoryImpl()); 152 factory->SetProtocolHandler("http", new MockHttpServerJobFactory); 153 job_factory_ = factory.Pass(); 154 request_context_.reset(new net::TestURLRequestContext()); 155 request_context_->set_job_factory(job_factory_.get()); 156 AppCacheInterceptor::EnsureRegistered(); 157 } 158 159 virtual void CleanUp() OVERRIDE { 160 request_context_.reset(); 161 job_factory_.reset(); 162 } 163 164 private: 165 scoped_ptr<net::URLRequestJobFactory> job_factory_; 166 scoped_ptr<net::URLRequestContext> request_context_; 167 }; 168 169 scoped_ptr<IOThread> io_thread; 170 scoped_ptr<base::Thread> db_thread; 171 172 } // namespace 173 174 class AppCacheStorageImplTest : public testing::Test { 175 public: 176 class MockStorageDelegate : public AppCacheStorage::Delegate { 177 public: 178 explicit MockStorageDelegate(AppCacheStorageImplTest* test) 179 : loaded_cache_id_(0), stored_group_success_(false), 180 would_exceed_quota_(false), obsoleted_success_(false), 181 found_cache_id_(kNoCacheId), test_(test) { 182 } 183 184 virtual void OnCacheLoaded(AppCache* cache, int64 cache_id) OVERRIDE { 185 loaded_cache_ = cache; 186 loaded_cache_id_ = cache_id; 187 test_->ScheduleNextTask(); 188 } 189 190 virtual void OnGroupLoaded(AppCacheGroup* group, 191 const GURL& manifest_url) OVERRIDE { 192 loaded_group_ = group; 193 loaded_manifest_url_ = manifest_url; 194 loaded_groups_newest_cache_ = group ? group->newest_complete_cache() 195 : NULL; 196 test_->ScheduleNextTask(); 197 } 198 199 virtual void OnGroupAndNewestCacheStored( 200 AppCacheGroup* group, AppCache* newest_cache, bool success, 201 bool would_exceed_quota) OVERRIDE { 202 stored_group_ = group; 203 stored_group_success_ = success; 204 would_exceed_quota_ = would_exceed_quota; 205 test_->ScheduleNextTask(); 206 } 207 208 virtual void OnGroupMadeObsolete(AppCacheGroup* group, 209 bool success) OVERRIDE { 210 obsoleted_group_ = group; 211 obsoleted_success_ = success; 212 test_->ScheduleNextTask(); 213 } 214 215 virtual void OnMainResponseFound(const GURL& url, 216 const AppCacheEntry& entry, 217 const GURL& namespace_entry_url, 218 const AppCacheEntry& fallback_entry, 219 int64 cache_id, 220 int64 group_id, 221 const GURL& manifest_url) OVERRIDE { 222 found_url_ = url; 223 found_entry_ = entry; 224 found_namespace_entry_url_ = namespace_entry_url; 225 found_fallback_entry_ = fallback_entry; 226 found_cache_id_ = cache_id; 227 found_group_id_ = group_id; 228 found_manifest_url_ = manifest_url; 229 test_->ScheduleNextTask(); 230 } 231 232 scoped_refptr<AppCache> loaded_cache_; 233 int64 loaded_cache_id_; 234 scoped_refptr<AppCacheGroup> loaded_group_; 235 GURL loaded_manifest_url_; 236 scoped_refptr<AppCache> loaded_groups_newest_cache_; 237 scoped_refptr<AppCacheGroup> stored_group_; 238 bool stored_group_success_; 239 bool would_exceed_quota_; 240 scoped_refptr<AppCacheGroup> obsoleted_group_; 241 bool obsoleted_success_; 242 GURL found_url_; 243 AppCacheEntry found_entry_; 244 GURL found_namespace_entry_url_; 245 AppCacheEntry found_fallback_entry_; 246 int64 found_cache_id_; 247 int64 found_group_id_; 248 GURL found_manifest_url_; 249 AppCacheStorageImplTest* test_; 250 }; 251 252 class MockQuotaManager : public quota::QuotaManager { 253 public: 254 MockQuotaManager() 255 : QuotaManager(true /* is_incognito */, 256 base::FilePath(), 257 io_thread->message_loop_proxy().get(), 258 db_thread->message_loop_proxy().get(), 259 NULL), 260 async_(false) {} 261 262 virtual void GetUsageAndQuota( 263 const GURL& origin, 264 quota::StorageType type, 265 const GetUsageAndQuotaCallback& callback) OVERRIDE { 266 EXPECT_EQ(kOrigin, origin); 267 EXPECT_EQ(quota::kStorageTypeTemporary, type); 268 if (async_) { 269 base::MessageLoop::current()->PostTask( 270 FROM_HERE, 271 base::Bind(&MockQuotaManager::CallCallback, 272 base::Unretained(this), 273 callback)); 274 return; 275 } 276 CallCallback(callback); 277 } 278 279 void CallCallback(const GetUsageAndQuotaCallback& callback) { 280 callback.Run(quota::kQuotaStatusOk, 0, kMockQuota); 281 } 282 283 bool async_; 284 285 protected: 286 virtual ~MockQuotaManager() {} 287 }; 288 289 class MockQuotaManagerProxy : public quota::QuotaManagerProxy { 290 public: 291 MockQuotaManagerProxy() 292 : QuotaManagerProxy(NULL, NULL), 293 notify_storage_accessed_count_(0), 294 notify_storage_modified_count_(0), 295 last_delta_(0), 296 mock_manager_(new MockQuotaManager) { 297 manager_ = mock_manager_.get(); 298 } 299 300 virtual void NotifyStorageAccessed(quota::QuotaClient::ID client_id, 301 const GURL& origin, 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; 307 } 308 309 virtual void NotifyStorageModified(quota::QuotaClient::ID client_id, 310 const GURL& origin, 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; 317 last_delta_ = delta; 318 } 319 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, 325 const GURL& origin, 326 quota::StorageType type, 327 bool enabled) OVERRIDE {} 328 virtual void GetUsageAndQuota( 329 base::SequencedTaskRunner* original_task_runner, 330 const GURL& origin, 331 quota::StorageType type, 332 const GetUsageAndQuotaCallback& callback) OVERRIDE {} 333 334 int notify_storage_accessed_count_; 335 int notify_storage_modified_count_; 336 GURL last_origin_; 337 int last_delta_; 338 scoped_refptr<MockQuotaManager> mock_manager_; 339 340 protected: 341 virtual ~MockQuotaManagerProxy() {} 342 }; 343 344 template <class Method> 345 void RunMethod(Method method) { 346 (this->*method)(); 347 } 348 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) { 353 SetUpTest(); 354 355 // Ensure InitTask execution prior to conducting a test. 356 FlushDbThreadTasks(); 357 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( 362 FROM_HERE, 363 base::Bind(&AppCacheStorageImplTest::RunMethod<Method>, 364 base::Unretained(this), 365 method)); 366 } 367 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)); 376 } 377 378 static void TearDownTestCase() { 379 io_thread.reset(NULL); 380 db_thread.reset(NULL); 381 } 382 383 // Test harness -------------------------------------------------- 384 385 AppCacheStorageImplTest() { 386 } 387 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(); 395 } 396 397 void SetUpTest() { 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)); 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_, 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_, 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()); 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(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()); 958 TestFinished(); 959 } 960 961 // BasicFindMainResponse ------------------------------- 962 963 void BasicFindMainResponseInDatabase() { 964 BasicFindMainResponse(true); 965 } 966 967 void BasicFindMainResponseInWorkingSet() { 968 BasicFindMainResponse(false); 969 } 970 971 void BasicFindMainResponse(bool drop_from_working_set) { 972 PushNextTask(base::Bind( 973 &AppCacheStorageImplTest::Verify_BasicFindMainResponse, 974 base::Unretained(this))); 975 976 // Setup some preconditions. Create a complete cache with an entry 977 // in storage. 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)); 986 987 // Optionally drop the cache/group pair from the working set. 988 if (drop_from_working_set) { 989 EXPECT_TRUE(cache_->HasOneRef()); 990 cache_ = NULL; 991 EXPECT_TRUE(group_->HasOneRef()); 992 group_ = NULL; 993 } 994 995 // Conduct the test. 996 storage()->FindResponseForMainRequest(kEntryUrl, GURL(), delegate()); 997 EXPECT_NE(kEntryUrl, delegate()->found_url_); 998 } 999 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()); 1008 TestFinished(); 1009 } 1010 1011 // BasicFindMainFallbackResponse ------------------------------- 1012 1013 void BasicFindMainFallbackResponseInDatabase() { 1014 BasicFindMainFallbackResponse(true); 1015 } 1016 1017 void BasicFindMainFallbackResponseInWorkingSet() { 1018 BasicFindMainFallbackResponse(false); 1019 } 1020 1021 void BasicFindMainFallbackResponse(bool drop_from_working_set) { 1022 PushNextTask(base::Bind( 1023 &AppCacheStorageImplTest::Verify_BasicFindMainFallbackResponse, 1024 base::Unretained(this))); 1025 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(), 1041 &cache_record, 1042 &entries, 1043 &intercepts, 1044 &fallbacks, 1045 &whitelists); 1046 1047 std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter = 1048 entries.begin(); 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))); 1053 ++iter; 1054 } 1055 1056 EXPECT_TRUE(database()->InsertNamespaceRecords(fallbacks)); 1057 EXPECT_TRUE(database()->InsertOnlineWhiteListRecords(whitelists)); 1058 if (drop_from_working_set) { 1059 EXPECT_TRUE(cache_->HasOneRef()); 1060 cache_ = NULL; 1061 EXPECT_TRUE(group_->HasOneRef()); 1062 group_ = NULL; 1063 } 1064 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_); 1069 } 1070 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()); 1080 TestFinished(); 1081 } 1082 1083 // BasicFindMainInterceptResponse ------------------------------- 1084 1085 void BasicFindMainInterceptResponseInDatabase() { 1086 BasicFindMainInterceptResponse(true); 1087 } 1088 1089 void BasicFindMainInterceptResponseInWorkingSet() { 1090 BasicFindMainInterceptResponse(false); 1091 } 1092 1093 void BasicFindMainInterceptResponse(bool drop_from_working_set) { 1094 PushNextTask(base::Bind( 1095 &AppCacheStorageImplTest::Verify_BasicFindMainInterceptResponse, 1096 base::Unretained(this))); 1097 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, 1108 kEntryUrl, false)); 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(), 1115 &cache_record, 1116 &entries, 1117 &intercepts, 1118 &fallbacks, 1119 &whitelists); 1120 1121 std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter = 1122 entries.begin(); 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))); 1127 ++iter; 1128 } 1129 1130 EXPECT_TRUE(database()->InsertNamespaceRecords(intercepts)); 1131 EXPECT_TRUE(database()->InsertOnlineWhiteListRecords(whitelists)); 1132 if (drop_from_working_set) { 1133 EXPECT_TRUE(cache_->HasOneRef()); 1134 cache_ = NULL; 1135 EXPECT_TRUE(group_->HasOneRef()); 1136 group_ = NULL; 1137 } 1138 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_); 1144 } 1145 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()); 1155 TestFinished(); 1156 } 1157 1158 // FindInterceptPatternMatch ---------------------------------------- 1159 1160 void FindInterceptPatternMatchInDatabase() { 1161 FindInterceptPatternMatch(true); 1162 } 1163 1164 void FindInterceptPatternMatchInWorkingSet() { 1165 FindInterceptPatternMatch(false); 1166 } 1167 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, 1175 kEntryUrl, true)); 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(), 1182 &cache_record, 1183 &entries, 1184 &intercepts, 1185 &fallbacks, 1186 &whitelists); 1187 1188 std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter = 1189 entries.begin(); 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))); 1194 ++iter; 1195 } 1196 1197 EXPECT_TRUE(database()->InsertNamespaceRecords(intercepts)); 1198 if (drop_from_working_set) { 1199 EXPECT_TRUE(cache_->HasOneRef()); 1200 cache_ = NULL; 1201 EXPECT_TRUE(group_->HasOneRef()); 1202 group_ = NULL; 1203 } 1204 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. 1212 } 1213 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()); 1223 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()); 1230 } 1231 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()); 1241 TestFinished(); 1242 } 1243 1244 // FindFallbackPatternMatch ------------------------------- 1245 1246 void FindFallbackPatternMatchInDatabase() { 1247 FindFallbackPatternMatch(true); 1248 } 1249 1250 void FindFallbackPatternMatchInWorkingSet() { 1251 FindFallbackPatternMatch(false); 1252 } 1253 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, 1261 kEntryUrl, true)); 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(), 1268 &cache_record, 1269 &entries, 1270 &intercepts, 1271 &fallbacks, 1272 &whitelists); 1273 1274 std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter = 1275 entries.begin(); 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))); 1280 ++iter; 1281 } 1282 1283 EXPECT_TRUE(database()->InsertNamespaceRecords(fallbacks)); 1284 if (drop_from_working_set) { 1285 EXPECT_TRUE(cache_->HasOneRef()); 1286 cache_ = NULL; 1287 EXPECT_TRUE(group_->HasOneRef()); 1288 group_ = NULL; 1289 } 1290 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. 1298 } 1299 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()); 1309 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()); 1316 } 1317 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()); 1327 TestFinished(); 1328 } 1329 1330 // FindMainResponseWithMultipleHits ------------------------------- 1331 1332 void FindMainResponseWithMultipleHits() { 1333 PushNextTask(base::Bind( 1334 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits, 1335 base::Unretained(this))); 1336 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); 1343 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_); 1348 } 1349 1350 void MakeMultipleHitCacheAndGroup(const GURL& manifest_url, int id) { 1351 MakeCacheAndGroup(manifest_url, id, id, true); 1352 AppCacheDatabase::EntryRecord entry_record; 1353 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)); 1360 cache_->AddEntry( 1361 entry_record.url, 1362 AppCacheEntry(entry_record.flags, entry_record.response_id)); 1363 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)); 1370 cache_->AddEntry( 1371 entry_record.url, 1372 AppCacheEntry(entry_record.flags, entry_record.response_id)); 1373 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)); 1380 cache_->AddEntry( 1381 entry_record.url, 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)); 1391 } 1392 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()); 1401 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_); 1409 } 1410 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()); 1419 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_); 1427 } 1428 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()); 1437 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_); 1446 } 1447 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_); 1458 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_); 1467 } 1468 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_); 1479 1480 TestFinished(); 1481 } 1482 1483 // FindMainResponseExclusions ------------------------------- 1484 1485 void FindMainResponseExclusionsInDatabase() { 1486 FindMainResponseExclusions(true); 1487 } 1488 1489 void FindMainResponseExclusionsInWorkingSet() { 1490 FindMainResponseExclusions(false); 1491 } 1492 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, 1505 GURL(), false)); 1506 cache_->online_whitelist_namespaces_.push_back( 1507 Namespace(NETWORK_NAMESPACE, kOnlineNamespaceWithinFallback, 1508 GURL(), false)); 1509 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) { 1530 cache_ = NULL; 1531 group_ = NULL; 1532 } 1533 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()); 1538 } 1539 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()); 1550 1551 if (phase == 1) { 1552 // We should not find anything for the online namespace. 1553 PushNextTask( 1554 base::Bind(&AppCacheStorageImplTest::Verify_ExclusionNotFound, 1555 base::Unretained(this), kOnlineNamespace, 2)); 1556 storage()->FindResponseForMainRequest( 1557 kOnlineNamespace, GURL(), delegate()); 1558 return; 1559 } 1560 if (phase == 2) { 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()); 1568 return; 1569 } 1570 1571 TestFinished(); 1572 } 1573 1574 // Reinitialize ------------------------------- 1575 // This test is somewhat of a system integration test. 1576 // It relies 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. 1579 1580 class MockServiceObserver : public AppCacheService::Observer { 1581 public: 1582 explicit MockServiceObserver(AppCacheStorageImplTest* test) 1583 : test_(test) {} 1584 1585 virtual void OnServiceReinitialized( 1586 AppCacheStorageReference* old_storage_ref) OVERRIDE { 1587 observed_old_storage_ = old_storage_ref; 1588 test_->ScheduleNextTask(); 1589 } 1590 1591 scoped_refptr<AppCacheStorageReference> observed_old_storage_; 1592 AppCacheStorageImplTest* test_; 1593 }; 1594 1595 class MockAppCacheFrontend : public AppCacheFrontend { 1596 public: 1597 MockAppCacheFrontend() : error_event_was_raised_(false) {} 1598 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, 1607 const GURL& url, 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; 1612 } 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 {} 1617 1618 bool error_event_was_raised_; 1619 }; 1620 1621 void Reinitialize1() { 1622 Reinitialize(1); 1623 } 1624 1625 void Reinitialize2() { 1626 Reinitialize(2); 1627 } 1628 1629 void Reinitialize(int test_case) { 1630 // Unlike all of the other tests, this one actually read/write files. 1631 ASSERT_TRUE(temp_directory_.CreateUniqueTempDir()); 1632 1633 // Create a corrupt/unopenable disk_cache index file. 1634 const std::string kCorruptData("deadbeef"); 1635 base::FilePath disk_cache_directory = 1636 temp_directory_.path().AppendASCII("Cache"); 1637 ASSERT_TRUE(base::CreateDirectory(disk_cache_directory)); 1638 base::FilePath index_file = disk_cache_directory.AppendASCII("index"); 1639 EXPECT_EQ(static_cast<int>(kCorruptData.length()), 1640 file_util::WriteFile( 1641 index_file, kCorruptData.data(), kCorruptData.length())); 1642 1643 // Create records for a degenerate cached manifest that only contains 1644 // one entry for the manifest file resource. 1645 if (test_case == 2) { 1646 AppCacheDatabase db(temp_directory_.path().AppendASCII("Index")); 1647 GURL manifest_url = MockHttpServer::GetMockUrl("manifest"); 1648 1649 AppCacheDatabase::GroupRecord group_record; 1650 group_record.group_id = 1; 1651 group_record.manifest_url = manifest_url; 1652 group_record.origin = manifest_url.GetOrigin(); 1653 EXPECT_TRUE(db.InsertGroup(&group_record)); 1654 AppCacheDatabase::CacheRecord cache_record; 1655 cache_record.cache_id = 1; 1656 cache_record.group_id = 1; 1657 cache_record.online_wildcard = false; 1658 cache_record.update_time = kZeroTime; 1659 cache_record.cache_size = kDefaultEntrySize; 1660 EXPECT_TRUE(db.InsertCache(&cache_record)); 1661 AppCacheDatabase::EntryRecord entry_record; 1662 entry_record.cache_id = 1; 1663 entry_record.url = manifest_url; 1664 entry_record.flags = AppCacheEntry::MANIFEST; 1665 entry_record.response_id = 1; 1666 entry_record.response_size = kDefaultEntrySize; 1667 EXPECT_TRUE(db.InsertEntry(&entry_record)); 1668 } 1669 1670 // Recreate the service to point at the db and corruption on disk. 1671 service_.reset(new AppCacheService(NULL)); 1672 service_->set_request_context(io_thread->request_context()); 1673 service_->Initialize( 1674 temp_directory_.path(), 1675 db_thread->message_loop_proxy().get(), 1676 db_thread->message_loop_proxy().get()); 1677 mock_quota_manager_proxy_ = new MockQuotaManagerProxy(); 1678 service_->quota_manager_proxy_ = mock_quota_manager_proxy_; 1679 delegate_.reset(new MockStorageDelegate(this)); 1680 1681 // Additional setup to observe reinitailize happens. 1682 observer_.reset(new MockServiceObserver(this)); 1683 service_->AddObserver(observer_.get()); 1684 1685 // We continue after the init task is complete including the callback 1686 // on the current thread. 1687 FlushDbThreadTasks(); 1688 base::MessageLoop::current()->PostTask( 1689 FROM_HERE, 1690 base::Bind(&AppCacheStorageImplTest::Continue_Reinitialize, 1691 base::Unretained(this), 1692 test_case)); 1693 } 1694 1695 void Continue_Reinitialize(int test_case) { 1696 const int kMockProcessId = 1; 1697 backend_.reset(new AppCacheBackendImpl); 1698 backend_->Initialize(service_.get(), &frontend_, kMockProcessId); 1699 1700 if (test_case == 1) { 1701 // Try to create a new appcache, the resulting update job will 1702 // eventually fail when it gets to disk cache initialization. 1703 backend_->RegisterHost(1); 1704 AppCacheHost* host1 = backend_->GetHost(1); 1705 const GURL kEmptyPageUrl(MockHttpServer::GetMockUrl("empty.html")); 1706 host1->first_party_url_ = kEmptyPageUrl; 1707 host1->SelectCache(kEmptyPageUrl, 1708 kNoCacheId, 1709 MockHttpServer::GetMockUrl("manifest")); 1710 } else { 1711 ASSERT_EQ(2, test_case); 1712 // Try to access the existing cache manifest. 1713 // The URLRequestJob will eventually fail when it gets to disk 1714 // cache initialization. 1715 backend_->RegisterHost(2); 1716 AppCacheHost* host2 = backend_->GetHost(2); 1717 GURL manifest_url = MockHttpServer::GetMockUrl("manifest"); 1718 request_ = service()->request_context()->CreateRequest( 1719 manifest_url, net::DEFAULT_PRIORITY, NULL); 1720 AppCacheInterceptor::SetExtraRequestInfo( 1721 request_.get(), service_.get(), 1722 backend_->process_id(), host2->host_id(), 1723 ResourceType::MAIN_FRAME); 1724 request_->Start(); 1725 } 1726 1727 PushNextTask(base::Bind( 1728 &AppCacheStorageImplTest::Verify_Reinitialized, 1729 base::Unretained(this), 1730 test_case)); 1731 } 1732 1733 void Verify_Reinitialized(int test_case) { 1734 // Verify we got notified of reinit and a new storage instance is created, 1735 // and that the old data has been deleted. 1736 EXPECT_TRUE(observer_->observed_old_storage_.get()); 1737 EXPECT_TRUE(observer_->observed_old_storage_->storage() != storage()); 1738 EXPECT_FALSE(PathExists( 1739 temp_directory_.path().AppendASCII("Cache").AppendASCII("index"))); 1740 EXPECT_FALSE(PathExists( 1741 temp_directory_.path().AppendASCII("Index"))); 1742 1743 // Verify that the hosts saw appropriate events. 1744 if (test_case == 1) { 1745 EXPECT_TRUE(frontend_.error_event_was_raised_); 1746 AppCacheHost* host1 = backend_->GetHost(1); 1747 EXPECT_FALSE(host1->associated_cache()); 1748 EXPECT_FALSE(host1->group_being_updated_); 1749 EXPECT_TRUE(host1->disabled_storage_reference_.get()); 1750 } else { 1751 ASSERT_EQ(2, test_case); 1752 AppCacheHost* host2 = backend_->GetHost(2); 1753 EXPECT_EQ(1, host2->main_resource_cache_->cache_id()); 1754 EXPECT_TRUE(host2->disabled_storage_reference_.get()); 1755 } 1756 1757 // Cleanup and claim victory. 1758 service_->RemoveObserver(observer_.get()); 1759 request_.reset(); 1760 backend_.reset(); 1761 observer_.reset(); 1762 TestFinished(); 1763 } 1764 1765 // Test case helpers -------------------------------------------------- 1766 1767 AppCacheService* service() { 1768 return service_.get(); 1769 } 1770 1771 AppCacheStorageImpl* storage() { 1772 return static_cast<AppCacheStorageImpl*>(service()->storage()); 1773 } 1774 1775 AppCacheDatabase* database() { 1776 return storage()->database_; 1777 } 1778 1779 MockStorageDelegate* delegate() { 1780 return delegate_.get(); 1781 } 1782 1783 void MakeCacheAndGroup( 1784 const GURL& manifest_url, int64 group_id, int64 cache_id, 1785 bool add_to_database) { 1786 AppCacheEntry default_entry( 1787 AppCacheEntry::EXPLICIT, cache_id + kDefaultEntryIdOffset, 1788 kDefaultEntrySize); 1789 group_ = new AppCacheGroup(storage(), manifest_url, group_id); 1790 cache_ = new AppCache(storage(), cache_id); 1791 cache_->AddEntry(kDefaultEntryUrl, default_entry); 1792 cache_->set_complete(true); 1793 group_->AddCache(cache_.get()); 1794 if (add_to_database) { 1795 AppCacheDatabase::GroupRecord group_record; 1796 group_record.group_id = group_id; 1797 group_record.manifest_url = manifest_url; 1798 group_record.origin = manifest_url.GetOrigin(); 1799 EXPECT_TRUE(database()->InsertGroup(&group_record)); 1800 AppCacheDatabase::CacheRecord cache_record; 1801 cache_record.cache_id = cache_id; 1802 cache_record.group_id = group_id; 1803 cache_record.online_wildcard = false; 1804 cache_record.update_time = kZeroTime; 1805 cache_record.cache_size = kDefaultEntrySize; 1806 EXPECT_TRUE(database()->InsertCache(&cache_record)); 1807 AppCacheDatabase::EntryRecord entry_record; 1808 entry_record.cache_id = cache_id; 1809 entry_record.url = kDefaultEntryUrl; 1810 entry_record.flags = default_entry.types(); 1811 entry_record.response_id = default_entry.response_id(); 1812 entry_record.response_size = default_entry.response_size(); 1813 EXPECT_TRUE(database()->InsertEntry(&entry_record)); 1814 1815 storage()->usage_map_[manifest_url.GetOrigin()] = 1816 default_entry.response_size(); 1817 } 1818 } 1819 1820 // Data members -------------------------------------------------- 1821 1822 scoped_ptr<base::WaitableEvent> test_finished_event_; 1823 std::stack<base::Closure> task_stack_; 1824 scoped_ptr<AppCacheService> service_; 1825 scoped_ptr<MockStorageDelegate> delegate_; 1826 scoped_refptr<MockQuotaManagerProxy> mock_quota_manager_proxy_; 1827 scoped_refptr<AppCacheGroup> group_; 1828 scoped_refptr<AppCache> cache_; 1829 scoped_refptr<AppCache> cache2_; 1830 1831 // Specifically for the Reinitalize test. 1832 base::ScopedTempDir temp_directory_; 1833 scoped_ptr<MockServiceObserver> observer_; 1834 MockAppCacheFrontend frontend_; 1835 scoped_ptr<AppCacheBackendImpl> backend_; 1836 scoped_ptr<net::URLRequest> request_; 1837 }; 1838 1839 1840 TEST_F(AppCacheStorageImplTest, LoadCache_Miss) { 1841 RunTestOnIOThread(&AppCacheStorageImplTest::LoadCache_Miss); 1842 } 1843 1844 TEST_F(AppCacheStorageImplTest, LoadCache_NearHit) { 1845 RunTestOnIOThread(&AppCacheStorageImplTest::LoadCache_NearHit); 1846 } 1847 1848 TEST_F(AppCacheStorageImplTest, CreateGroupInEmptyOrigin) { 1849 RunTestOnIOThread(&AppCacheStorageImplTest::CreateGroupInEmptyOrigin); 1850 } 1851 1852 TEST_F(AppCacheStorageImplTest, CreateGroupInPopulatedOrigin) { 1853 RunTestOnIOThread(&AppCacheStorageImplTest::CreateGroupInPopulatedOrigin); 1854 } 1855 1856 TEST_F(AppCacheStorageImplTest, LoadGroupAndCache_FarHit) { 1857 RunTestOnIOThread(&AppCacheStorageImplTest::LoadGroupAndCache_FarHit); 1858 } 1859 1860 TEST_F(AppCacheStorageImplTest, StoreNewGroup) { 1861 RunTestOnIOThread(&AppCacheStorageImplTest::StoreNewGroup); 1862 } 1863 1864 TEST_F(AppCacheStorageImplTest, StoreExistingGroup) { 1865 RunTestOnIOThread(&AppCacheStorageImplTest::StoreExistingGroup); 1866 } 1867 1868 TEST_F(AppCacheStorageImplTest, StoreExistingGroupExistingCache) { 1869 RunTestOnIOThread(&AppCacheStorageImplTest::StoreExistingGroupExistingCache); 1870 } 1871 1872 TEST_F(AppCacheStorageImplTest, FailStoreGroup) { 1873 RunTestOnIOThread(&AppCacheStorageImplTest::FailStoreGroup); 1874 } 1875 1876 TEST_F(AppCacheStorageImplTest, MakeGroupObsolete) { 1877 RunTestOnIOThread(&AppCacheStorageImplTest::MakeGroupObsolete); 1878 } 1879 1880 TEST_F(AppCacheStorageImplTest, MarkEntryAsForeign) { 1881 RunTestOnIOThread(&AppCacheStorageImplTest::MarkEntryAsForeign); 1882 } 1883 1884 TEST_F(AppCacheStorageImplTest, MarkEntryAsForeignWithLoadInProgress) { 1885 RunTestOnIOThread( 1886 &AppCacheStorageImplTest::MarkEntryAsForeignWithLoadInProgress); 1887 } 1888 1889 TEST_F(AppCacheStorageImplTest, FindNoMainResponse) { 1890 RunTestOnIOThread(&AppCacheStorageImplTest::FindNoMainResponse); 1891 } 1892 1893 TEST_F(AppCacheStorageImplTest, BasicFindMainResponseInDatabase) { 1894 RunTestOnIOThread( 1895 &AppCacheStorageImplTest::BasicFindMainResponseInDatabase); 1896 } 1897 1898 TEST_F(AppCacheStorageImplTest, BasicFindMainResponseInWorkingSet) { 1899 RunTestOnIOThread( 1900 &AppCacheStorageImplTest::BasicFindMainResponseInWorkingSet); 1901 } 1902 1903 TEST_F(AppCacheStorageImplTest, BasicFindMainFallbackResponseInDatabase) { 1904 RunTestOnIOThread( 1905 &AppCacheStorageImplTest::BasicFindMainFallbackResponseInDatabase); 1906 } 1907 1908 TEST_F(AppCacheStorageImplTest, BasicFindMainFallbackResponseInWorkingSet) { 1909 RunTestOnIOThread( 1910 &AppCacheStorageImplTest::BasicFindMainFallbackResponseInWorkingSet); 1911 } 1912 1913 TEST_F(AppCacheStorageImplTest, BasicFindMainInterceptResponseInDatabase) { 1914 RunTestOnIOThread( 1915 &AppCacheStorageImplTest::BasicFindMainInterceptResponseInDatabase); 1916 } 1917 1918 TEST_F(AppCacheStorageImplTest, BasicFindMainInterceptResponseInWorkingSet) { 1919 RunTestOnIOThread( 1920 &AppCacheStorageImplTest::BasicFindMainInterceptResponseInWorkingSet); 1921 } 1922 1923 TEST_F(AppCacheStorageImplTest, FindMainResponseWithMultipleHits) { 1924 RunTestOnIOThread( 1925 &AppCacheStorageImplTest::FindMainResponseWithMultipleHits); 1926 } 1927 1928 TEST_F(AppCacheStorageImplTest, FindMainResponseExclusionsInDatabase) { 1929 RunTestOnIOThread( 1930 &AppCacheStorageImplTest::FindMainResponseExclusionsInDatabase); 1931 } 1932 1933 TEST_F(AppCacheStorageImplTest, FindMainResponseExclusionsInWorkingSet) { 1934 RunTestOnIOThread( 1935 &AppCacheStorageImplTest::FindMainResponseExclusionsInWorkingSet); 1936 } 1937 1938 TEST_F(AppCacheStorageImplTest, FindInterceptPatternMatchInWorkingSet) { 1939 RunTestOnIOThread( 1940 &AppCacheStorageImplTest::FindInterceptPatternMatchInWorkingSet); 1941 } 1942 1943 TEST_F(AppCacheStorageImplTest, FindInterceptPatternMatchInDatabase) { 1944 RunTestOnIOThread( 1945 &AppCacheStorageImplTest::FindInterceptPatternMatchInDatabase); 1946 } 1947 1948 TEST_F(AppCacheStorageImplTest, FindFallbackPatternMatchInWorkingSet) { 1949 RunTestOnIOThread( 1950 &AppCacheStorageImplTest::FindFallbackPatternMatchInWorkingSet); 1951 } 1952 1953 TEST_F(AppCacheStorageImplTest, FindFallbackPatternMatchInDatabase) { 1954 RunTestOnIOThread( 1955 &AppCacheStorageImplTest::FindFallbackPatternMatchInDatabase); 1956 } 1957 1958 TEST_F(AppCacheStorageImplTest, Reinitialize1) { 1959 RunTestOnIOThread(&AppCacheStorageImplTest::Reinitialize1); 1960 } 1961 1962 TEST_F(AppCacheStorageImplTest, Reinitialize2) { 1963 RunTestOnIOThread(&AppCacheStorageImplTest::Reinitialize2); 1964 } 1965 1966 // That's all folks! 1967 1968 } // namespace appcache 1969