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