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 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
;
32 virtual void OnStatusChanged(const std::vector
<int>& host_ids
,
33 content::AppCacheStatus status
) OVERRIDE
{
36 virtual void OnEventRaised(const std::vector
<int>& host_ids
,
37 content::AppCacheEventID event_id
) OVERRIDE
{
40 virtual void OnErrorEventRaised(const std::vector
<int>& host_ids
,
41 const content::AppCacheErrorDetails
& details
)
44 virtual void OnProgressEventRaised(const std::vector
<int>& host_ids
,
46 int num_total
, int num_complete
) OVERRIDE
{
49 virtual void OnLogMessage(int host_id
, content::AppCacheLogLevel log_level
,
50 const std::string
& message
) OVERRIDE
{
53 virtual void OnContentBlocked(int host_id
,
54 const GURL
& manifest_url
) OVERRIDE
{
59 content::AppCacheStatus last_status_
;
66 class TestUpdateObserver
: public AppCacheGroup::UpdateObserver
{
68 TestUpdateObserver() : update_completed_(false), group_has_cache_(false) {
71 virtual void OnUpdateComplete(AppCacheGroup
* group
) OVERRIDE
{
72 update_completed_
= true;
73 group_has_cache_
= group
->HasCache();
76 virtual void OnContentBlocked(AppCacheGroup
* group
) {
79 bool update_completed_
;
80 bool group_has_cache_
;
83 class TestAppCacheHost
: public AppCacheHost
{
85 TestAppCacheHost(int host_id
, AppCacheFrontend
* frontend
,
86 AppCacheServiceImpl
* service
)
87 : AppCacheHost(host_id
, frontend
, service
),
88 update_completed_(false) {
91 virtual void OnUpdateComplete(AppCacheGroup
* group
) OVERRIDE
{
92 update_completed_
= true;
95 bool update_completed_
;
98 class AppCacheGroupTest
: public testing::Test
{
100 base::MessageLoop message_loop_
;
103 TEST_F(AppCacheGroupTest
, AddRemoveCache
) {
104 MockAppCacheService service
;
105 scoped_refptr
<AppCacheGroup
> group(
106 new AppCacheGroup(service
.storage(), GURL("http://foo.com"), 111));
108 base::Time now
= base::Time::Now();
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());
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());
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());
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());
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
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
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
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
173 TEST_F(AppCacheGroupTest
, CleanupUnusedGroup
) {
174 MockAppCacheService service
;
175 TestAppCacheFrontend frontend
;
176 AppCacheGroup
* group
=
177 new AppCacheGroup(service
.storage(), GURL("http://foo.com"), 111);
179 AppCacheHost
host1(1, &frontend
, &service
);
180 AppCacheHost
host2(2, &frontend
, &service
);
182 base::Time now
= base::Time::Now();
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());
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
);
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
);
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());
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
);
214 TEST_F(AppCacheGroupTest
, StartUpdate
) {
215 MockAppCacheService service
;
216 scoped_refptr
<AppCacheGroup
> group(
217 new AppCacheGroup(service
.storage(), GURL("http://foo.com"), 111));
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
);
225 // Start another update, check that same update job is in use.
226 group
->StartUpdateWithHost(NULL
);
227 EXPECT_EQ(update
, group
->update_job_
);
229 // Deleting the update should restore the group to APPCACHE_STATUS_IDLE.
231 EXPECT_TRUE(group
->update_job_
== NULL
);
232 EXPECT_EQ(AppCacheGroup::IDLE
, group
->update_status());
235 TEST_F(AppCacheGroupTest
, CancelUpdate
) {
236 MockAppCacheService service
;
237 scoped_refptr
<AppCacheGroup
> group(
238 new AppCacheGroup(service
.storage(), GURL("http://foo.com"), 111));
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
);
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_
);
254 TEST_F(AppCacheGroupTest
, QueueUpdate
) {
255 MockAppCacheService service
;
256 scoped_refptr
<AppCacheGroup
> group(
257 new AppCacheGroup(service
.storage(), GURL("http://foo.com"), 111));
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_
);
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());
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());
274 group
->AddUpdateObserver(&host
);
275 EXPECT_FALSE(group
->FindObserver(&host
, group
->observers_
));
276 EXPECT_TRUE(group
->FindObserver(&host
, group
->queued_observers_
));
278 // Delete update to cause it to complete. Verify no update complete notice
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_
);
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_
));
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_
);
302 } // namespace content