• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <string>
6 
7 #include "base/message_loop/message_loop.h"
8 #include "content/browser/appcache/appcache.h"
9 #include "content/browser/appcache/appcache_group.h"
10 #include "content/browser/appcache/appcache_host.h"
11 #include "content/browser/appcache/appcache_update_job.h"
12 #include "content/browser/appcache/mock_appcache_service.h"
13 #include "content/common/appcache_interfaces.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 
16 namespace {
17 
18 class TestAppCacheFrontend : public content::AppCacheFrontend {
19  public:
TestAppCacheFrontend()20   TestAppCacheFrontend()
21       : last_host_id_(-1), last_cache_id_(-1),
22         last_status_(content::APPCACHE_STATUS_OBSOLETE) {
23   }
24 
OnCacheSelected(int host_id,const content::AppCacheInfo & info)25   virtual void OnCacheSelected(
26       int host_id, const content::AppCacheInfo& info) OVERRIDE {
27     last_host_id_ = host_id;
28     last_cache_id_ = info.cache_id;
29     last_status_ = info.status;
30   }
31 
OnStatusChanged(const std::vector<int> & host_ids,content::AppCacheStatus status)32   virtual void OnStatusChanged(const std::vector<int>& host_ids,
33                                content::AppCacheStatus status) OVERRIDE {
34   }
35 
OnEventRaised(const std::vector<int> & host_ids,content::AppCacheEventID event_id)36   virtual void OnEventRaised(const std::vector<int>& host_ids,
37                              content::AppCacheEventID event_id) OVERRIDE {
38   }
39 
OnErrorEventRaised(const std::vector<int> & host_ids,const content::AppCacheErrorDetails & details)40   virtual void OnErrorEventRaised(const std::vector<int>& host_ids,
41                                   const content::AppCacheErrorDetails& details)
42       OVERRIDE {}
43 
OnProgressEventRaised(const std::vector<int> & host_ids,const GURL & url,int num_total,int num_complete)44   virtual void OnProgressEventRaised(const std::vector<int>& host_ids,
45                                      const GURL& url,
46                                      int num_total, int num_complete) OVERRIDE {
47   }
48 
OnLogMessage(int host_id,content::AppCacheLogLevel log_level,const std::string & message)49   virtual void OnLogMessage(int host_id, content::AppCacheLogLevel log_level,
50                             const std::string& message) OVERRIDE {
51   }
52 
OnContentBlocked(int host_id,const GURL & manifest_url)53   virtual void OnContentBlocked(int host_id,
54                                 const GURL& manifest_url) OVERRIDE {
55   }
56 
57   int last_host_id_;
58   int64 last_cache_id_;
59   content::AppCacheStatus last_status_;
60 };
61 
62 }  // namespace anon
63 
64 namespace content {
65 
66 class TestUpdateObserver : public AppCacheGroup::UpdateObserver {
67  public:
TestUpdateObserver()68   TestUpdateObserver() : update_completed_(false), group_has_cache_(false) {
69   }
70 
OnUpdateComplete(AppCacheGroup * group)71   virtual void OnUpdateComplete(AppCacheGroup* group) OVERRIDE {
72     update_completed_ = true;
73     group_has_cache_ = group->HasCache();
74   }
75 
OnContentBlocked(AppCacheGroup * group)76   virtual void OnContentBlocked(AppCacheGroup* group) {
77   }
78 
79   bool update_completed_;
80   bool group_has_cache_;
81 };
82 
83 class TestAppCacheHost : public AppCacheHost {
84  public:
TestAppCacheHost(int host_id,AppCacheFrontend * frontend,AppCacheServiceImpl * service)85   TestAppCacheHost(int host_id, AppCacheFrontend* frontend,
86                    AppCacheServiceImpl* service)
87       : AppCacheHost(host_id, frontend, service),
88         update_completed_(false) {
89   }
90 
OnUpdateComplete(AppCacheGroup * group)91   virtual void OnUpdateComplete(AppCacheGroup* group) OVERRIDE {
92     update_completed_ = true;
93   }
94 
95   bool update_completed_;
96 };
97 
98 class AppCacheGroupTest : public testing::Test {
99  private:
100   base::MessageLoop message_loop_;
101 };
102 
TEST_F(AppCacheGroupTest,AddRemoveCache)103 TEST_F(AppCacheGroupTest, AddRemoveCache) {
104   MockAppCacheService service;
105   scoped_refptr<AppCacheGroup> group(
106       new AppCacheGroup(service.storage(), GURL("http://foo.com"), 111));
107 
108   base::Time now = base::Time::Now();
109 
110   scoped_refptr<AppCache> cache1(new AppCache(service.storage(), 111));
111   cache1->set_complete(true);
112   cache1->set_update_time(now);
113   group->AddCache(cache1.get());
114   EXPECT_EQ(cache1.get(), group->newest_complete_cache());
115 
116   // Adding older cache does not change newest complete cache.
117   scoped_refptr<AppCache> cache2(new AppCache(service.storage(), 222));
118   cache2->set_complete(true);
119   cache2->set_update_time(now - base::TimeDelta::FromDays(1));
120   group->AddCache(cache2.get());
121   EXPECT_EQ(cache1.get(), group->newest_complete_cache());
122 
123   // Adding newer cache does change newest complete cache.
124   scoped_refptr<AppCache> cache3(new AppCache(service.storage(), 333));
125   cache3->set_complete(true);
126   cache3->set_update_time(now + base::TimeDelta::FromDays(1));
127   group->AddCache(cache3.get());
128   EXPECT_EQ(cache3.get(), group->newest_complete_cache());
129 
130   // Adding cache with same update time uses one with larger ID.
131   scoped_refptr<AppCache> cache4(new AppCache(service.storage(), 444));
132   cache4->set_complete(true);
133   cache4->set_update_time(now + base::TimeDelta::FromDays(1));  // same as 3
134   group->AddCache(cache4.get());
135   EXPECT_EQ(cache4.get(), group->newest_complete_cache());
136 
137   // smaller id
138   scoped_refptr<AppCache> cache5(new AppCache(service.storage(), 55));
139   cache5->set_complete(true);
140   cache5->set_update_time(now + base::TimeDelta::FromDays(1));  // same as 4
141   group->AddCache(cache5.get());
142   EXPECT_EQ(cache4.get(), group->newest_complete_cache());  // no change
143 
144   // Old caches can always be removed.
145   group->RemoveCache(cache1.get());
146   EXPECT_FALSE(cache1->owning_group());
147   EXPECT_EQ(cache4.get(), group->newest_complete_cache());  // newest unchanged
148 
149   // Remove rest of caches.
150   group->RemoveCache(cache2.get());
151   EXPECT_FALSE(cache2->owning_group());
152   EXPECT_EQ(cache4.get(), group->newest_complete_cache());  // newest unchanged
153   group->RemoveCache(cache3.get());
154   EXPECT_FALSE(cache3->owning_group());
155   EXPECT_EQ(cache4.get(), group->newest_complete_cache());  // newest unchanged
156   group->RemoveCache(cache5.get());
157   EXPECT_FALSE(cache5->owning_group());
158   EXPECT_EQ(cache4.get(), group->newest_complete_cache());  // newest unchanged
159   group->RemoveCache(cache4.get());                   // newest removed
160   EXPECT_FALSE(cache4->owning_group());
161   EXPECT_FALSE(group->newest_complete_cache());       // no more newest cache
162 
163   // Can remove newest cache if there are older caches.
164   group->AddCache(cache1.get());
165   EXPECT_EQ(cache1.get(), group->newest_complete_cache());
166   group->AddCache(cache4.get());
167   EXPECT_EQ(cache4.get(), group->newest_complete_cache());
168   group->RemoveCache(cache4.get());  // remove newest
169   EXPECT_FALSE(cache4->owning_group());
170   EXPECT_FALSE(group->newest_complete_cache());  // newest removed
171 }
172 
TEST_F(AppCacheGroupTest,CleanupUnusedGroup)173 TEST_F(AppCacheGroupTest, CleanupUnusedGroup) {
174   MockAppCacheService service;
175   TestAppCacheFrontend frontend;
176   AppCacheGroup* group =
177       new AppCacheGroup(service.storage(), GURL("http://foo.com"), 111);
178 
179   AppCacheHost host1(1, &frontend, &service);
180   AppCacheHost host2(2, &frontend, &service);
181 
182   base::Time now = base::Time::Now();
183 
184   AppCache* cache1 = new AppCache(service.storage(), 111);
185   cache1->set_complete(true);
186   cache1->set_update_time(now);
187   group->AddCache(cache1);
188   EXPECT_EQ(cache1, group->newest_complete_cache());
189 
190   host1.AssociateCompleteCache(cache1);
191   EXPECT_EQ(frontend.last_host_id_, host1.host_id());
192   EXPECT_EQ(frontend.last_cache_id_, cache1->cache_id());
193   EXPECT_EQ(frontend.last_status_, APPCACHE_STATUS_IDLE);
194 
195   host2.AssociateCompleteCache(cache1);
196   EXPECT_EQ(frontend.last_host_id_, host2.host_id());
197   EXPECT_EQ(frontend.last_cache_id_, cache1->cache_id());
198   EXPECT_EQ(frontend.last_status_, APPCACHE_STATUS_IDLE);
199 
200   AppCache* cache2 = new AppCache(service.storage(), 222);
201   cache2->set_complete(true);
202   cache2->set_update_time(now + base::TimeDelta::FromDays(1));
203   group->AddCache(cache2);
204   EXPECT_EQ(cache2, group->newest_complete_cache());
205 
206   // Unassociate all hosts from older cache.
207   host1.AssociateNoCache(GURL());
208   host2.AssociateNoCache(GURL());
209   EXPECT_EQ(frontend.last_host_id_, host2.host_id());
210   EXPECT_EQ(frontend.last_cache_id_, kAppCacheNoCacheId);
211   EXPECT_EQ(frontend.last_status_, APPCACHE_STATUS_UNCACHED);
212 }
213 
TEST_F(AppCacheGroupTest,StartUpdate)214 TEST_F(AppCacheGroupTest, StartUpdate) {
215   MockAppCacheService service;
216   scoped_refptr<AppCacheGroup> group(
217       new AppCacheGroup(service.storage(), GURL("http://foo.com"), 111));
218 
219   // Set state to checking to prevent update job from executing fetches.
220   group->update_status_ = AppCacheGroup::CHECKING;
221   group->StartUpdate();
222   AppCacheUpdateJob* update = group->update_job_;
223   EXPECT_TRUE(update != NULL);
224 
225   // Start another update, check that same update job is in use.
226   group->StartUpdateWithHost(NULL);
227   EXPECT_EQ(update, group->update_job_);
228 
229   // Deleting the update should restore the group to APPCACHE_STATUS_IDLE.
230   delete update;
231   EXPECT_TRUE(group->update_job_ == NULL);
232   EXPECT_EQ(AppCacheGroup::IDLE, group->update_status());
233 }
234 
TEST_F(AppCacheGroupTest,CancelUpdate)235 TEST_F(AppCacheGroupTest, CancelUpdate) {
236   MockAppCacheService service;
237   scoped_refptr<AppCacheGroup> group(
238       new AppCacheGroup(service.storage(), GURL("http://foo.com"), 111));
239 
240   // Set state to checking to prevent update job from executing fetches.
241   group->update_status_ = AppCacheGroup::CHECKING;
242   group->StartUpdate();
243   AppCacheUpdateJob* update = group->update_job_;
244   EXPECT_TRUE(update != NULL);
245 
246   // Deleting the group should cancel the update.
247   TestUpdateObserver observer;
248   group->AddUpdateObserver(&observer);
249   group = NULL;  // causes group to be deleted
250   EXPECT_TRUE(observer.update_completed_);
251   EXPECT_FALSE(observer.group_has_cache_);
252 }
253 
TEST_F(AppCacheGroupTest,QueueUpdate)254 TEST_F(AppCacheGroupTest, QueueUpdate) {
255   MockAppCacheService service;
256   scoped_refptr<AppCacheGroup> group(
257       new AppCacheGroup(service.storage(), GURL("http://foo.com"), 111));
258 
259   // Set state to checking to prevent update job from executing fetches.
260   group->update_status_ = AppCacheGroup::CHECKING;
261   group->StartUpdate();
262   EXPECT_TRUE(group->update_job_);
263 
264   // Pretend group's update job is terminating so that next update is queued.
265   group->update_job_->internal_state_ = AppCacheUpdateJob::REFETCH_MANIFEST;
266   EXPECT_TRUE(group->update_job_->IsTerminating());
267 
268   TestAppCacheFrontend frontend;
269   TestAppCacheHost host(1, &frontend, &service);
270   host.new_master_entry_url_ = GURL("http://foo.com/bar.txt");
271   group->StartUpdateWithNewMasterEntry(&host, host.new_master_entry_url_);
272   EXPECT_FALSE(group->queued_updates_.empty());
273 
274   group->AddUpdateObserver(&host);
275   EXPECT_FALSE(group->FindObserver(&host, group->observers_));
276   EXPECT_TRUE(group->FindObserver(&host, group->queued_observers_));
277 
278   // Delete update to cause it to complete. Verify no update complete notice
279   // sent to host.
280   delete group->update_job_;
281   EXPECT_EQ(AppCacheGroup::IDLE, group->update_status_);
282   EXPECT_FALSE(group->restart_update_task_.IsCancelled());
283   EXPECT_FALSE(host.update_completed_);
284 
285   // Start another update. Cancels task and will run queued updates.
286   group->update_status_ = AppCacheGroup::CHECKING;  // prevent actual fetches
287   group->StartUpdate();
288   EXPECT_TRUE(group->update_job_);
289   EXPECT_TRUE(group->restart_update_task_.IsCancelled());
290   EXPECT_TRUE(group->queued_updates_.empty());
291   EXPECT_FALSE(group->update_job_->pending_master_entries_.empty());
292   EXPECT_FALSE(group->FindObserver(&host, group->queued_observers_));
293   EXPECT_TRUE(group->FindObserver(&host, group->observers_));
294 
295   // Delete update to cause it to complete. Verify host is notified.
296   delete group->update_job_;
297   EXPECT_EQ(AppCacheGroup::IDLE, group->update_status_);
298   EXPECT_TRUE(group->restart_update_task_.IsCancelled());
299   EXPECT_TRUE(host.update_completed_);
300 }
301 
302 }  // namespace content
303