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 "base/bind.h" 6 #include "base/bind_helpers.h" 7 #include "base/memory/scoped_ptr.h" 8 #include "base/message_loop/message_loop.h" 9 #include "content/browser/appcache/mock_appcache_policy.h" 10 #include "content/browser/appcache/mock_appcache_service.h" 11 #include "net/url_request/url_request.h" 12 #include "testing/gtest/include/gtest/gtest.h" 13 #include "webkit/browser/appcache/appcache.h" 14 #include "webkit/browser/appcache/appcache_backend_impl.h" 15 #include "webkit/browser/appcache/appcache_group.h" 16 #include "webkit/browser/appcache/appcache_host.h" 17 #include "webkit/browser/quota/quota_manager.h" 18 19 using appcache::AppCache; 20 using appcache::AppCacheBackendImpl; 21 using appcache::AppCacheEntry; 22 using appcache::AppCacheFrontend; 23 using appcache::AppCacheGroup; 24 using appcache::AppCacheHost; 25 using appcache::kAppCacheNoCacheId; 26 using appcache::APPCACHE_ERROR_EVENT; 27 using appcache::APPCACHE_STATUS_OBSOLETE; 28 using appcache::APPCACHE_OBSOLETE_EVENT; 29 using appcache::APPCACHE_PROGRESS_EVENT; 30 using appcache::AppCacheStatus; 31 using appcache::APPCACHE_STATUS_UNCACHED; 32 33 namespace content { 34 35 class AppCacheHostTest : public testing::Test { 36 public: 37 AppCacheHostTest() { 38 get_status_callback_ = 39 base::Bind(&AppCacheHostTest::GetStatusCallback, 40 base::Unretained(this)); 41 start_update_callback_ = 42 base::Bind(&AppCacheHostTest::StartUpdateCallback, 43 base::Unretained(this)); 44 swap_cache_callback_ = 45 base::Bind(&AppCacheHostTest::SwapCacheCallback, 46 base::Unretained(this)); 47 } 48 49 class MockFrontend : public AppCacheFrontend { 50 public: 51 MockFrontend() 52 : last_host_id_(-222), last_cache_id_(-222), 53 last_status_(appcache::APPCACHE_STATUS_OBSOLETE), 54 last_status_changed_(appcache::APPCACHE_STATUS_OBSOLETE), 55 last_event_id_(appcache::APPCACHE_OBSOLETE_EVENT), 56 content_blocked_(false) { 57 } 58 59 virtual void OnCacheSelected( 60 int host_id, const appcache::AppCacheInfo& info) OVERRIDE { 61 last_host_id_ = host_id; 62 last_cache_id_ = info.cache_id; 63 last_status_ = info.status; 64 } 65 66 virtual void OnStatusChanged(const std::vector<int>& host_ids, 67 appcache::AppCacheStatus status) OVERRIDE { 68 last_status_changed_ = status; 69 } 70 71 virtual void OnEventRaised(const std::vector<int>& host_ids, 72 appcache::AppCacheEventID event_id) OVERRIDE { 73 last_event_id_ = event_id; 74 } 75 76 virtual void OnErrorEventRaised( 77 const std::vector<int>& host_ids, 78 const appcache::AppCacheErrorDetails& details) OVERRIDE { 79 last_event_id_ = APPCACHE_ERROR_EVENT; 80 } 81 82 virtual void OnProgressEventRaised(const std::vector<int>& host_ids, 83 const GURL& url, 84 int num_total, 85 int num_complete) OVERRIDE { 86 last_event_id_ = APPCACHE_PROGRESS_EVENT; 87 } 88 89 virtual void OnLogMessage(int host_id, 90 appcache::AppCacheLogLevel log_level, 91 const std::string& message) OVERRIDE { 92 } 93 94 virtual void OnContentBlocked(int host_id, 95 const GURL& manifest_url) OVERRIDE { 96 content_blocked_ = true; 97 } 98 99 int last_host_id_; 100 int64 last_cache_id_; 101 appcache::AppCacheStatus last_status_; 102 appcache::AppCacheStatus last_status_changed_; 103 appcache::AppCacheEventID last_event_id_; 104 bool content_blocked_; 105 }; 106 107 class MockQuotaManagerProxy : public quota::QuotaManagerProxy { 108 public: 109 MockQuotaManagerProxy() : QuotaManagerProxy(NULL, NULL) {} 110 111 // Not needed for our tests. 112 virtual void RegisterClient(quota::QuotaClient* client) OVERRIDE {} 113 virtual void NotifyStorageAccessed(quota::QuotaClient::ID client_id, 114 const GURL& origin, 115 quota::StorageType type) OVERRIDE {} 116 virtual void NotifyStorageModified(quota::QuotaClient::ID client_id, 117 const GURL& origin, 118 quota::StorageType type, 119 int64 delta) OVERRIDE {} 120 virtual void SetUsageCacheEnabled(quota::QuotaClient::ID client_id, 121 const GURL& origin, 122 quota::StorageType type, 123 bool enabled) OVERRIDE {} 124 virtual void GetUsageAndQuota( 125 base::SequencedTaskRunner* original_task_runner, 126 const GURL& origin, 127 quota::StorageType type, 128 const GetUsageAndQuotaCallback& callback) OVERRIDE {} 129 130 virtual void NotifyOriginInUse(const GURL& origin) OVERRIDE { 131 inuse_[origin] += 1; 132 } 133 134 virtual void NotifyOriginNoLongerInUse(const GURL& origin) OVERRIDE { 135 inuse_[origin] -= 1; 136 } 137 138 int GetInUseCount(const GURL& origin) { 139 return inuse_[origin]; 140 } 141 142 void reset() { 143 inuse_.clear(); 144 } 145 146 // Map from origin to count of inuse notifications. 147 std::map<GURL, int> inuse_; 148 149 protected: 150 virtual ~MockQuotaManagerProxy() {} 151 }; 152 153 void GetStatusCallback(AppCacheStatus status, void* param) { 154 last_status_result_ = status; 155 last_callback_param_ = param; 156 } 157 158 void StartUpdateCallback(bool result, void* param) { 159 last_start_result_ = result; 160 last_callback_param_ = param; 161 } 162 163 void SwapCacheCallback(bool result, void* param) { 164 last_swap_result_ = result; 165 last_callback_param_ = param; 166 } 167 168 base::MessageLoop message_loop_; 169 170 // Mock classes for the 'host' to work with 171 MockAppCacheService service_; 172 MockFrontend mock_frontend_; 173 174 // Mock callbacks we expect to receive from the 'host' 175 appcache::GetStatusCallback get_status_callback_; 176 appcache::StartUpdateCallback start_update_callback_; 177 appcache::SwapCacheCallback swap_cache_callback_; 178 179 AppCacheStatus last_status_result_; 180 bool last_swap_result_; 181 bool last_start_result_; 182 void* last_callback_param_; 183 }; 184 185 TEST_F(AppCacheHostTest, Basic) { 186 // Construct a host and test what state it appears to be in. 187 AppCacheHost host(1, &mock_frontend_, &service_); 188 EXPECT_EQ(1, host.host_id()); 189 EXPECT_EQ(&service_, host.service()); 190 EXPECT_EQ(&mock_frontend_, host.frontend()); 191 EXPECT_EQ(NULL, host.associated_cache()); 192 EXPECT_FALSE(host.is_selection_pending()); 193 194 // See that the callbacks are delivered immediately 195 // and respond as if there is no cache selected. 196 last_status_result_ = APPCACHE_STATUS_OBSOLETE; 197 host.GetStatusWithCallback(get_status_callback_, reinterpret_cast<void*>(1)); 198 EXPECT_EQ(APPCACHE_STATUS_UNCACHED, last_status_result_); 199 EXPECT_EQ(reinterpret_cast<void*>(1), last_callback_param_); 200 201 last_start_result_ = true; 202 host.StartUpdateWithCallback(start_update_callback_, 203 reinterpret_cast<void*>(2)); 204 EXPECT_FALSE(last_start_result_); 205 EXPECT_EQ(reinterpret_cast<void*>(2), last_callback_param_); 206 207 last_swap_result_ = true; 208 host.SwapCacheWithCallback(swap_cache_callback_, reinterpret_cast<void*>(3)); 209 EXPECT_FALSE(last_swap_result_); 210 EXPECT_EQ(reinterpret_cast<void*>(3), last_callback_param_); 211 } 212 213 TEST_F(AppCacheHostTest, SelectNoCache) { 214 scoped_refptr<MockQuotaManagerProxy> mock_quota_proxy( 215 new MockQuotaManagerProxy); 216 service_.set_quota_manager_proxy(mock_quota_proxy.get()); 217 218 // Reset our mock frontend 219 mock_frontend_.last_cache_id_ = -333; 220 mock_frontend_.last_host_id_ = -333; 221 mock_frontend_.last_status_ = APPCACHE_STATUS_OBSOLETE; 222 223 const GURL kDocAndOriginUrl(GURL("http://whatever/").GetOrigin()); 224 { 225 AppCacheHost host(1, &mock_frontend_, &service_); 226 host.SelectCache(kDocAndOriginUrl, kAppCacheNoCacheId, GURL()); 227 EXPECT_EQ(1, mock_quota_proxy->GetInUseCount(kDocAndOriginUrl)); 228 229 // We should have received an OnCacheSelected msg 230 EXPECT_EQ(1, mock_frontend_.last_host_id_); 231 EXPECT_EQ(kAppCacheNoCacheId, mock_frontend_.last_cache_id_); 232 EXPECT_EQ(APPCACHE_STATUS_UNCACHED, mock_frontend_.last_status_); 233 234 // Otherwise, see that it respond as if there is no cache selected. 235 EXPECT_EQ(1, host.host_id()); 236 EXPECT_EQ(&service_, host.service()); 237 EXPECT_EQ(&mock_frontend_, host.frontend()); 238 EXPECT_EQ(NULL, host.associated_cache()); 239 EXPECT_FALSE(host.is_selection_pending()); 240 EXPECT_TRUE(host.preferred_manifest_url().is_empty()); 241 } 242 EXPECT_EQ(0, mock_quota_proxy->GetInUseCount(kDocAndOriginUrl)); 243 service_.set_quota_manager_proxy(NULL); 244 } 245 246 TEST_F(AppCacheHostTest, ForeignEntry) { 247 // Reset our mock frontend 248 mock_frontend_.last_cache_id_ = -333; 249 mock_frontend_.last_host_id_ = -333; 250 mock_frontend_.last_status_ = APPCACHE_STATUS_OBSOLETE; 251 252 // Precondition, a cache with an entry that is not marked as foreign. 253 const int kCacheId = 22; 254 const GURL kDocumentURL("http://origin/document"); 255 scoped_refptr<AppCache> cache = new AppCache(service_.storage(), kCacheId); 256 cache->AddEntry(kDocumentURL, AppCacheEntry(AppCacheEntry::EXPLICIT)); 257 258 AppCacheHost host(1, &mock_frontend_, &service_); 259 host.MarkAsForeignEntry(kDocumentURL, kCacheId); 260 261 // We should have received an OnCacheSelected msg for kAppCacheNoCacheId. 262 EXPECT_EQ(1, mock_frontend_.last_host_id_); 263 EXPECT_EQ(kAppCacheNoCacheId, mock_frontend_.last_cache_id_); 264 EXPECT_EQ(APPCACHE_STATUS_UNCACHED, mock_frontend_.last_status_); 265 266 // See that it respond as if there is no cache selected. 267 EXPECT_EQ(1, host.host_id()); 268 EXPECT_EQ(&service_, host.service()); 269 EXPECT_EQ(&mock_frontend_, host.frontend()); 270 EXPECT_EQ(NULL, host.associated_cache()); 271 EXPECT_FALSE(host.is_selection_pending()); 272 273 // See that the entry was marked as foreign. 274 EXPECT_TRUE(cache->GetEntry(kDocumentURL)->IsForeign()); 275 } 276 277 TEST_F(AppCacheHostTest, ForeignFallbackEntry) { 278 // Reset our mock frontend 279 mock_frontend_.last_cache_id_ = -333; 280 mock_frontend_.last_host_id_ = -333; 281 mock_frontend_.last_status_ = APPCACHE_STATUS_OBSOLETE; 282 283 // Precondition, a cache with a fallback entry that is not marked as foreign. 284 const int kCacheId = 22; 285 const GURL kFallbackURL("http://origin/fallback_resource"); 286 scoped_refptr<AppCache> cache = new AppCache(service_.storage(), kCacheId); 287 cache->AddEntry(kFallbackURL, AppCacheEntry(AppCacheEntry::FALLBACK)); 288 289 AppCacheHost host(1, &mock_frontend_, &service_); 290 host.NotifyMainResourceIsNamespaceEntry(kFallbackURL); 291 host.MarkAsForeignEntry(GURL("http://origin/missing_document"), kCacheId); 292 293 // We should have received an OnCacheSelected msg for kAppCacheNoCacheId. 294 EXPECT_EQ(1, mock_frontend_.last_host_id_); 295 EXPECT_EQ(kAppCacheNoCacheId, mock_frontend_.last_cache_id_); 296 EXPECT_EQ(APPCACHE_STATUS_UNCACHED, mock_frontend_.last_status_); 297 298 // See that the fallback entry was marked as foreign. 299 EXPECT_TRUE(cache->GetEntry(kFallbackURL)->IsForeign()); 300 } 301 302 TEST_F(AppCacheHostTest, FailedCacheLoad) { 303 // Reset our mock frontend 304 mock_frontend_.last_cache_id_ = -333; 305 mock_frontend_.last_host_id_ = -333; 306 mock_frontend_.last_status_ = APPCACHE_STATUS_OBSOLETE; 307 308 AppCacheHost host(1, &mock_frontend_, &service_); 309 EXPECT_FALSE(host.is_selection_pending()); 310 311 const int kMockCacheId = 333; 312 313 // Put it in a state where we're waiting on a cache 314 // load prior to finishing cache selection. 315 host.pending_selected_cache_id_ = kMockCacheId; 316 EXPECT_TRUE(host.is_selection_pending()); 317 318 // The callback should not occur until we finish cache selection. 319 last_status_result_ = APPCACHE_STATUS_OBSOLETE; 320 last_callback_param_ = reinterpret_cast<void*>(-1); 321 host.GetStatusWithCallback(get_status_callback_, reinterpret_cast<void*>(1)); 322 EXPECT_EQ(APPCACHE_STATUS_OBSOLETE, last_status_result_); 323 EXPECT_EQ(reinterpret_cast<void*>(-1), last_callback_param_); 324 325 // Satisfy the load with NULL, a failure. 326 host.OnCacheLoaded(NULL, kMockCacheId); 327 328 // Cache selection should have finished 329 EXPECT_FALSE(host.is_selection_pending()); 330 EXPECT_EQ(1, mock_frontend_.last_host_id_); 331 EXPECT_EQ(kAppCacheNoCacheId, mock_frontend_.last_cache_id_); 332 EXPECT_EQ(APPCACHE_STATUS_UNCACHED, mock_frontend_.last_status_); 333 334 // Callback should have fired upon completing the cache load too. 335 EXPECT_EQ(APPCACHE_STATUS_UNCACHED, last_status_result_); 336 EXPECT_EQ(reinterpret_cast<void*>(1), last_callback_param_); 337 } 338 339 TEST_F(AppCacheHostTest, FailedGroupLoad) { 340 AppCacheHost host(1, &mock_frontend_, &service_); 341 342 const GURL kMockManifestUrl("http://foo.bar/baz"); 343 344 // Put it in a state where we're waiting on a cache 345 // load prior to finishing cache selection. 346 host.pending_selected_manifest_url_ = kMockManifestUrl; 347 EXPECT_TRUE(host.is_selection_pending()); 348 349 // The callback should not occur until we finish cache selection. 350 last_status_result_ = APPCACHE_STATUS_OBSOLETE; 351 last_callback_param_ = reinterpret_cast<void*>(-1); 352 host.GetStatusWithCallback(get_status_callback_, reinterpret_cast<void*>(1)); 353 EXPECT_EQ(APPCACHE_STATUS_OBSOLETE, last_status_result_); 354 EXPECT_EQ(reinterpret_cast<void*>(-1), last_callback_param_); 355 356 // Satisfy the load will NULL, a failure. 357 host.OnGroupLoaded(NULL, kMockManifestUrl); 358 359 // Cache selection should have finished 360 EXPECT_FALSE(host.is_selection_pending()); 361 EXPECT_EQ(1, mock_frontend_.last_host_id_); 362 EXPECT_EQ(kAppCacheNoCacheId, mock_frontend_.last_cache_id_); 363 EXPECT_EQ(APPCACHE_STATUS_UNCACHED, mock_frontend_.last_status_); 364 365 // Callback should have fired upon completing the group load. 366 EXPECT_EQ(APPCACHE_STATUS_UNCACHED, last_status_result_); 367 EXPECT_EQ(reinterpret_cast<void*>(1), last_callback_param_); 368 } 369 370 TEST_F(AppCacheHostTest, SetSwappableCache) { 371 AppCacheHost host(1, &mock_frontend_, &service_); 372 host.SetSwappableCache(NULL); 373 EXPECT_FALSE(host.swappable_cache_.get()); 374 375 scoped_refptr<AppCacheGroup> group1(new AppCacheGroup( 376 service_.storage(), GURL(), service_.storage()->NewGroupId())); 377 host.SetSwappableCache(group1.get()); 378 EXPECT_FALSE(host.swappable_cache_.get()); 379 380 AppCache* cache1 = new AppCache(service_.storage(), 111); 381 cache1->set_complete(true); 382 group1->AddCache(cache1); 383 host.SetSwappableCache(group1.get()); 384 EXPECT_EQ(cache1, host.swappable_cache_.get()); 385 386 mock_frontend_.last_host_id_ = -222; // to verify we received OnCacheSelected 387 388 host.AssociateCompleteCache(cache1); 389 EXPECT_FALSE(host.swappable_cache_.get()); // was same as associated cache 390 EXPECT_EQ(appcache::APPCACHE_STATUS_IDLE, host.GetStatus()); 391 // verify OnCacheSelected was called 392 EXPECT_EQ(host.host_id(), mock_frontend_.last_host_id_); 393 EXPECT_EQ(cache1->cache_id(), mock_frontend_.last_cache_id_); 394 EXPECT_EQ(appcache::APPCACHE_STATUS_IDLE, mock_frontend_.last_status_); 395 396 AppCache* cache2 = new AppCache(service_.storage(), 222); 397 cache2->set_complete(true); 398 group1->AddCache(cache2); 399 EXPECT_EQ(cache2, host.swappable_cache_.get()); // updated to newest 400 401 scoped_refptr<AppCacheGroup> group2( 402 new AppCacheGroup(service_.storage(), GURL("http://foo.com"), 403 service_.storage()->NewGroupId())); 404 AppCache* cache3 = new AppCache(service_.storage(), 333); 405 cache3->set_complete(true); 406 group2->AddCache(cache3); 407 408 AppCache* cache4 = new AppCache(service_.storage(), 444); 409 cache4->set_complete(true); 410 group2->AddCache(cache4); 411 EXPECT_EQ(cache2, host.swappable_cache_.get()); // unchanged 412 413 host.AssociateCompleteCache(cache3); 414 EXPECT_EQ(cache4, host.swappable_cache_.get()); // newest cache in group2 415 EXPECT_FALSE(group1->HasCache()); // both caches in group1 have refcount 0 416 417 host.AssociateNoCache(GURL()); 418 EXPECT_FALSE(host.swappable_cache_.get()); 419 EXPECT_FALSE(group2->HasCache()); // both caches in group2 have refcount 0 420 421 // Host adds reference to newest cache when an update is complete. 422 AppCache* cache5 = new AppCache(service_.storage(), 555); 423 cache5->set_complete(true); 424 group2->AddCache(cache5); 425 host.group_being_updated_ = group2; 426 host.OnUpdateComplete(group2.get()); 427 EXPECT_FALSE(host.group_being_updated_.get()); 428 EXPECT_EQ(cache5, host.swappable_cache_.get()); 429 430 group2->RemoveCache(cache5); 431 EXPECT_FALSE(group2->HasCache()); 432 host.group_being_updated_ = group2; 433 host.OnUpdateComplete(group2.get()); 434 EXPECT_FALSE(host.group_being_updated_.get()); 435 EXPECT_FALSE(host.swappable_cache_.get()); // group2 had no newest cache 436 } 437 438 TEST_F(AppCacheHostTest, ForDedicatedWorker) { 439 const int kMockProcessId = 1; 440 const int kParentHostId = 1; 441 const int kWorkerHostId = 2; 442 443 AppCacheBackendImpl backend_impl; 444 backend_impl.Initialize(&service_, &mock_frontend_, kMockProcessId); 445 backend_impl.RegisterHost(kParentHostId); 446 backend_impl.RegisterHost(kWorkerHostId); 447 448 AppCacheHost* parent_host = backend_impl.GetHost(kParentHostId); 449 EXPECT_FALSE(parent_host->is_for_dedicated_worker()); 450 451 AppCacheHost* worker_host = backend_impl.GetHost(kWorkerHostId); 452 worker_host->SelectCacheForWorker(kParentHostId, kMockProcessId); 453 EXPECT_TRUE(worker_host->is_for_dedicated_worker()); 454 EXPECT_EQ(parent_host, worker_host->GetParentAppCacheHost()); 455 456 // We should have received an OnCacheSelected msg for the worker_host. 457 // The host for workers always indicates 'no cache selected' regardless 458 // of its parent's state. This is OK because the worker cannot access 459 // the scriptable interface, the only function available is resource 460 // loading (see appcache_request_handler_unittests those tests). 461 EXPECT_EQ(kWorkerHostId, mock_frontend_.last_host_id_); 462 EXPECT_EQ(kAppCacheNoCacheId, mock_frontend_.last_cache_id_); 463 EXPECT_EQ(APPCACHE_STATUS_UNCACHED, mock_frontend_.last_status_); 464 465 // Simulate the parent being torn down. 466 backend_impl.UnregisterHost(kParentHostId); 467 parent_host = NULL; 468 EXPECT_EQ(NULL, backend_impl.GetHost(kParentHostId)); 469 EXPECT_EQ(NULL, worker_host->GetParentAppCacheHost()); 470 } 471 472 TEST_F(AppCacheHostTest, SelectCacheAllowed) { 473 scoped_refptr<MockQuotaManagerProxy> mock_quota_proxy( 474 new MockQuotaManagerProxy); 475 MockAppCachePolicy mock_appcache_policy; 476 mock_appcache_policy.can_create_return_value_ = true; 477 service_.set_quota_manager_proxy(mock_quota_proxy.get()); 478 service_.set_appcache_policy(&mock_appcache_policy); 479 480 // Reset our mock frontend 481 mock_frontend_.last_cache_id_ = -333; 482 mock_frontend_.last_host_id_ = -333; 483 mock_frontend_.last_status_ = APPCACHE_STATUS_OBSOLETE; 484 mock_frontend_.last_event_id_ = APPCACHE_OBSOLETE_EVENT; 485 mock_frontend_.content_blocked_ = false; 486 487 const GURL kDocAndOriginUrl(GURL("http://whatever/").GetOrigin()); 488 const GURL kManifestUrl(GURL("http://whatever/cache.manifest")); 489 { 490 AppCacheHost host(1, &mock_frontend_, &service_); 491 host.first_party_url_ = kDocAndOriginUrl; 492 host.SelectCache(kDocAndOriginUrl, kAppCacheNoCacheId, kManifestUrl); 493 EXPECT_EQ(1, mock_quota_proxy->GetInUseCount(kDocAndOriginUrl)); 494 495 // MockAppCacheService::LoadOrCreateGroup is asynchronous, so we shouldn't 496 // have received an OnCacheSelected msg yet. 497 EXPECT_EQ(-333, mock_frontend_.last_host_id_); 498 EXPECT_EQ(-333, mock_frontend_.last_cache_id_); 499 EXPECT_EQ(APPCACHE_STATUS_OBSOLETE, mock_frontend_.last_status_); 500 // No error events either 501 EXPECT_EQ(APPCACHE_OBSOLETE_EVENT, mock_frontend_.last_event_id_); 502 EXPECT_FALSE(mock_frontend_.content_blocked_); 503 504 EXPECT_TRUE(host.is_selection_pending()); 505 } 506 EXPECT_EQ(0, mock_quota_proxy->GetInUseCount(kDocAndOriginUrl)); 507 service_.set_quota_manager_proxy(NULL); 508 } 509 510 TEST_F(AppCacheHostTest, SelectCacheBlocked) { 511 scoped_refptr<MockQuotaManagerProxy> mock_quota_proxy( 512 new MockQuotaManagerProxy); 513 MockAppCachePolicy mock_appcache_policy; 514 mock_appcache_policy.can_create_return_value_ = false; 515 service_.set_quota_manager_proxy(mock_quota_proxy.get()); 516 service_.set_appcache_policy(&mock_appcache_policy); 517 518 // Reset our mock frontend 519 mock_frontend_.last_cache_id_ = -333; 520 mock_frontend_.last_host_id_ = -333; 521 mock_frontend_.last_status_ = APPCACHE_STATUS_OBSOLETE; 522 mock_frontend_.last_event_id_ = APPCACHE_OBSOLETE_EVENT; 523 mock_frontend_.content_blocked_ = false; 524 525 const GURL kDocAndOriginUrl(GURL("http://whatever/").GetOrigin()); 526 const GURL kManifestUrl(GURL("http://whatever/cache.manifest")); 527 { 528 AppCacheHost host(1, &mock_frontend_, &service_); 529 host.first_party_url_ = kDocAndOriginUrl; 530 host.SelectCache(kDocAndOriginUrl, kAppCacheNoCacheId, kManifestUrl); 531 EXPECT_EQ(1, mock_quota_proxy->GetInUseCount(kDocAndOriginUrl)); 532 533 // We should have received an OnCacheSelected msg 534 EXPECT_EQ(1, mock_frontend_.last_host_id_); 535 EXPECT_EQ(kAppCacheNoCacheId, mock_frontend_.last_cache_id_); 536 EXPECT_EQ(APPCACHE_STATUS_UNCACHED, mock_frontend_.last_status_); 537 538 // Also, an error event was raised 539 EXPECT_EQ(APPCACHE_ERROR_EVENT, mock_frontend_.last_event_id_); 540 EXPECT_TRUE(mock_frontend_.content_blocked_); 541 542 // Otherwise, see that it respond as if there is no cache selected. 543 EXPECT_EQ(1, host.host_id()); 544 EXPECT_EQ(&service_, host.service()); 545 EXPECT_EQ(&mock_frontend_, host.frontend()); 546 EXPECT_EQ(NULL, host.associated_cache()); 547 EXPECT_FALSE(host.is_selection_pending()); 548 EXPECT_TRUE(host.preferred_manifest_url().is_empty()); 549 } 550 EXPECT_EQ(0, mock_quota_proxy->GetInUseCount(kDocAndOriginUrl)); 551 service_.set_quota_manager_proxy(NULL); 552 } 553 554 } // namespace content 555