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.
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"
18 class TestAppCacheFrontend
: public content::AppCacheFrontend
{
20 TestAppCacheFrontend()
21 : last_host_id_(-1), last_cache_id_(-1),
22 last_status_(content::APPCACHE_STATUS_OBSOLETE
) {
25 void OnCacheSelected(int host_id
,
26 const content::AppCacheInfo
& info
) override
{
27 last_host_id_
= host_id
;
28 last_cache_id_
= info
.cache_id
;
29 last_status_
= info
.status
;
32 void OnStatusChanged(const std::vector
<int>& host_ids
,
33 content::AppCacheStatus status
) override
{}
35 void OnEventRaised(const std::vector
<int>& host_ids
,
36 content::AppCacheEventID event_id
) override
{}
38 void OnErrorEventRaised(
39 const std::vector
<int>& host_ids
,
40 const content::AppCacheErrorDetails
& details
) override
{}
42 void OnProgressEventRaised(const std::vector
<int>& host_ids
,
45 int num_complete
) override
{}
47 void OnLogMessage(int host_id
,
48 content::AppCacheLogLevel log_level
,
49 const std::string
& message
) override
{}
51 void OnContentBlocked(int host_id
, const GURL
& manifest_url
) override
{}
55 content::AppCacheStatus last_status_
;
62 class TestUpdateObserver
: public AppCacheGroup::UpdateObserver
{
64 TestUpdateObserver() : update_completed_(false), group_has_cache_(false) {
67 void OnUpdateComplete(AppCacheGroup
* group
) override
{
68 update_completed_
= true;
69 group_has_cache_
= group
->HasCache();
72 virtual void OnContentBlocked(AppCacheGroup
* group
) {
75 bool update_completed_
;
76 bool group_has_cache_
;
79 class TestAppCacheHost
: public AppCacheHost
{
81 TestAppCacheHost(int host_id
, AppCacheFrontend
* frontend
,
82 AppCacheServiceImpl
* service
)
83 : AppCacheHost(host_id
, frontend
, service
),
84 update_completed_(false) {
87 void OnUpdateComplete(AppCacheGroup
* group
) override
{
88 update_completed_
= true;
91 bool update_completed_
;
94 class AppCacheGroupTest
: public testing::Test
{
96 base::MessageLoop message_loop_
;
99 TEST_F(AppCacheGroupTest
, AddRemoveCache
) {
100 MockAppCacheService service
;
101 scoped_refptr
<AppCacheGroup
> group(
102 new AppCacheGroup(service
.storage(), GURL("http://foo.com"), 111));
104 base::Time now
= base::Time::Now();
106 scoped_refptr
<AppCache
> cache1(new AppCache(service
.storage(), 111));
107 cache1
->set_complete(true);
108 cache1
->set_update_time(now
);
109 group
->AddCache(cache1
.get());
110 EXPECT_EQ(cache1
.get(), group
->newest_complete_cache());
112 // Adding older cache does not change newest complete cache.
113 scoped_refptr
<AppCache
> cache2(new AppCache(service
.storage(), 222));
114 cache2
->set_complete(true);
115 cache2
->set_update_time(now
- base::TimeDelta::FromDays(1));
116 group
->AddCache(cache2
.get());
117 EXPECT_EQ(cache1
.get(), group
->newest_complete_cache());
119 // Adding newer cache does change newest complete cache.
120 scoped_refptr
<AppCache
> cache3(new AppCache(service
.storage(), 333));
121 cache3
->set_complete(true);
122 cache3
->set_update_time(now
+ base::TimeDelta::FromDays(1));
123 group
->AddCache(cache3
.get());
124 EXPECT_EQ(cache3
.get(), group
->newest_complete_cache());
126 // Adding cache with same update time uses one with larger ID.
127 scoped_refptr
<AppCache
> cache4(new AppCache(service
.storage(), 444));
128 cache4
->set_complete(true);
129 cache4
->set_update_time(now
+ base::TimeDelta::FromDays(1)); // same as 3
130 group
->AddCache(cache4
.get());
131 EXPECT_EQ(cache4
.get(), group
->newest_complete_cache());
134 scoped_refptr
<AppCache
> cache5(new AppCache(service
.storage(), 55));
135 cache5
->set_complete(true);
136 cache5
->set_update_time(now
+ base::TimeDelta::FromDays(1)); // same as 4
137 group
->AddCache(cache5
.get());
138 EXPECT_EQ(cache4
.get(), group
->newest_complete_cache()); // no change
140 // Old caches can always be removed.
141 group
->RemoveCache(cache1
.get());
142 EXPECT_FALSE(cache1
->owning_group());
143 EXPECT_EQ(cache4
.get(), group
->newest_complete_cache()); // newest unchanged
145 // Remove rest of caches.
146 group
->RemoveCache(cache2
.get());
147 EXPECT_FALSE(cache2
->owning_group());
148 EXPECT_EQ(cache4
.get(), group
->newest_complete_cache()); // newest unchanged
149 group
->RemoveCache(cache3
.get());
150 EXPECT_FALSE(cache3
->owning_group());
151 EXPECT_EQ(cache4
.get(), group
->newest_complete_cache()); // newest unchanged
152 group
->RemoveCache(cache5
.get());
153 EXPECT_FALSE(cache5
->owning_group());
154 EXPECT_EQ(cache4
.get(), group
->newest_complete_cache()); // newest unchanged
155 group
->RemoveCache(cache4
.get()); // newest removed
156 EXPECT_FALSE(cache4
->owning_group());
157 EXPECT_FALSE(group
->newest_complete_cache()); // no more newest cache
159 // Can remove newest cache if there are older caches.
160 group
->AddCache(cache1
.get());
161 EXPECT_EQ(cache1
.get(), group
->newest_complete_cache());
162 group
->AddCache(cache4
.get());
163 EXPECT_EQ(cache4
.get(), group
->newest_complete_cache());
164 group
->RemoveCache(cache4
.get()); // remove newest
165 EXPECT_FALSE(cache4
->owning_group());
166 EXPECT_FALSE(group
->newest_complete_cache()); // newest removed
169 TEST_F(AppCacheGroupTest
, CleanupUnusedGroup
) {
170 MockAppCacheService service
;
171 TestAppCacheFrontend frontend
;
172 AppCacheGroup
* group
=
173 new AppCacheGroup(service
.storage(), GURL("http://foo.com"), 111);
175 AppCacheHost
host1(1, &frontend
, &service
);
176 AppCacheHost
host2(2, &frontend
, &service
);
178 base::Time now
= base::Time::Now();
180 AppCache
* cache1
= new AppCache(service
.storage(), 111);
181 cache1
->set_complete(true);
182 cache1
->set_update_time(now
);
183 group
->AddCache(cache1
);
184 EXPECT_EQ(cache1
, group
->newest_complete_cache());
186 host1
.AssociateCompleteCache(cache1
);
187 EXPECT_EQ(frontend
.last_host_id_
, host1
.host_id());
188 EXPECT_EQ(frontend
.last_cache_id_
, cache1
->cache_id());
189 EXPECT_EQ(frontend
.last_status_
, APPCACHE_STATUS_IDLE
);
191 host2
.AssociateCompleteCache(cache1
);
192 EXPECT_EQ(frontend
.last_host_id_
, host2
.host_id());
193 EXPECT_EQ(frontend
.last_cache_id_
, cache1
->cache_id());
194 EXPECT_EQ(frontend
.last_status_
, APPCACHE_STATUS_IDLE
);
196 AppCache
* cache2
= new AppCache(service
.storage(), 222);
197 cache2
->set_complete(true);
198 cache2
->set_update_time(now
+ base::TimeDelta::FromDays(1));
199 group
->AddCache(cache2
);
200 EXPECT_EQ(cache2
, group
->newest_complete_cache());
202 // Unassociate all hosts from older cache.
203 host1
.AssociateNoCache(GURL());
204 host2
.AssociateNoCache(GURL());
205 EXPECT_EQ(frontend
.last_host_id_
, host2
.host_id());
206 EXPECT_EQ(frontend
.last_cache_id_
, kAppCacheNoCacheId
);
207 EXPECT_EQ(frontend
.last_status_
, APPCACHE_STATUS_UNCACHED
);
210 TEST_F(AppCacheGroupTest
, StartUpdate
) {
211 MockAppCacheService service
;
212 scoped_refptr
<AppCacheGroup
> group(
213 new AppCacheGroup(service
.storage(), GURL("http://foo.com"), 111));
215 // Set state to checking to prevent update job from executing fetches.
216 group
->update_status_
= AppCacheGroup::CHECKING
;
217 group
->StartUpdate();
218 AppCacheUpdateJob
* update
= group
->update_job_
;
219 EXPECT_TRUE(update
!= NULL
);
221 // Start another update, check that same update job is in use.
222 group
->StartUpdateWithHost(NULL
);
223 EXPECT_EQ(update
, group
->update_job_
);
225 // Deleting the update should restore the group to APPCACHE_STATUS_IDLE.
227 EXPECT_TRUE(group
->update_job_
== NULL
);
228 EXPECT_EQ(AppCacheGroup::IDLE
, group
->update_status());
231 TEST_F(AppCacheGroupTest
, CancelUpdate
) {
232 MockAppCacheService service
;
233 scoped_refptr
<AppCacheGroup
> group(
234 new AppCacheGroup(service
.storage(), GURL("http://foo.com"), 111));
236 // Set state to checking to prevent update job from executing fetches.
237 group
->update_status_
= AppCacheGroup::CHECKING
;
238 group
->StartUpdate();
239 AppCacheUpdateJob
* update
= group
->update_job_
;
240 EXPECT_TRUE(update
!= NULL
);
242 // Deleting the group should cancel the update.
243 TestUpdateObserver observer
;
244 group
->AddUpdateObserver(&observer
);
245 group
= NULL
; // causes group to be deleted
246 EXPECT_TRUE(observer
.update_completed_
);
247 EXPECT_FALSE(observer
.group_has_cache_
);
250 TEST_F(AppCacheGroupTest
, QueueUpdate
) {
251 MockAppCacheService service
;
252 scoped_refptr
<AppCacheGroup
> group(
253 new AppCacheGroup(service
.storage(), GURL("http://foo.com"), 111));
255 // Set state to checking to prevent update job from executing fetches.
256 group
->update_status_
= AppCacheGroup::CHECKING
;
257 group
->StartUpdate();
258 EXPECT_TRUE(group
->update_job_
);
260 // Pretend group's update job is terminating so that next update is queued.
261 group
->update_job_
->internal_state_
= AppCacheUpdateJob::REFETCH_MANIFEST
;
262 EXPECT_TRUE(group
->update_job_
->IsTerminating());
264 TestAppCacheFrontend frontend
;
265 TestAppCacheHost
host(1, &frontend
, &service
);
266 host
.new_master_entry_url_
= GURL("http://foo.com/bar.txt");
267 group
->StartUpdateWithNewMasterEntry(&host
, host
.new_master_entry_url_
);
268 EXPECT_FALSE(group
->queued_updates_
.empty());
270 group
->AddUpdateObserver(&host
);
271 EXPECT_FALSE(group
->FindObserver(&host
, group
->observers_
));
272 EXPECT_TRUE(group
->FindObserver(&host
, group
->queued_observers_
));
274 // Delete update to cause it to complete. Verify no update complete notice
276 delete group
->update_job_
;
277 EXPECT_EQ(AppCacheGroup::IDLE
, group
->update_status_
);
278 EXPECT_FALSE(group
->restart_update_task_
.IsCancelled());
279 EXPECT_FALSE(host
.update_completed_
);
281 // Start another update. Cancels task and will run queued updates.
282 group
->update_status_
= AppCacheGroup::CHECKING
; // prevent actual fetches
283 group
->StartUpdate();
284 EXPECT_TRUE(group
->update_job_
);
285 EXPECT_TRUE(group
->restart_update_task_
.IsCancelled());
286 EXPECT_TRUE(group
->queued_updates_
.empty());
287 EXPECT_FALSE(group
->update_job_
->pending_master_entries_
.empty());
288 EXPECT_FALSE(group
->FindObserver(&host
, group
->queued_observers_
));
289 EXPECT_TRUE(group
->FindObserver(&host
, group
->observers_
));
291 // Delete update to cause it to complete. Verify host is notified.
292 delete group
->update_job_
;
293 EXPECT_EQ(AppCacheGroup::IDLE
, group
->update_status_
);
294 EXPECT_TRUE(group
->restart_update_task_
.IsCancelled());
295 EXPECT_TRUE(host
.update_completed_
);
298 } // namespace content