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