Home | History | Annotate | Download | only in appcache
      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