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
19namespace content {
20
21class 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
171TEST_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
199TEST_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
232TEST_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
263TEST_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
288TEST_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
325TEST_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
356TEST_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
424TEST_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
458TEST_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
496TEST_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