blob: b3532f5a25a07472c0e0879bb3f791641a0e9fe0 [file] [log] [blame]
[email protected]a507b822014-04-12 05:10:241// Copyright 2014 The Chromium Authors. All rights reserved.
[email protected]e0184cb2011-06-10 23:29:092// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]20d06f62011-07-22 23:57:355#include <string>
[email protected]e0184cb2011-06-10 23:29:096
[email protected]e29f9332011-10-28 22:44:577#include "base/bind.h"
[email protected]123f2742011-12-02 04:26:528#include "base/bind_helpers.h"
[email protected]20d06f62011-07-22 23:57:359#include "base/pickle.h"
[email protected]f1edfb7e2013-09-13 16:45:1710#include "base/run_loop.h"
[email protected]98d6d4562014-06-25 20:57:5511#include "content/browser/appcache/appcache_response.h"
12#include "content/browser/appcache/appcache_service_impl.h"
[email protected]71fe3d12014-04-22 00:32:3813#include "content/browser/appcache/mock_appcache_storage.h"
[email protected]e0184cb2011-06-10 23:29:0914#include "net/base/completion_callback.h"
[email protected]20d06f62011-07-22 23:57:3515#include "net/base/io_buffer.h"
16#include "net/http/http_response_headers.h"
[email protected]e0184cb2011-06-10 23:29:0917#include "testing/gtest/include/gtest/gtest.h"
[email protected]20d06f62011-07-22 23:57:3518
[email protected]a507b822014-04-12 05:10:2419namespace content {
[email protected]20d06f62011-07-22 23:57:3520namespace {
21
22const int64 kMockGroupId = 1;
23const int64 kMockCacheId = 1;
24const int64 kMockResponseId = 1;
25const int64 kMissingCacheId = 5;
26const int64 kMissingResponseId = 5;
27const char kMockHeaders[] =
28 "HTTP/1.0 200 OK\0Content-Length: 5\0\0";
29const char kMockBody[] = "Hello";
30const int kMockBodySize = 5;
31
32class MockResponseReader : public AppCacheResponseReader {
33 public:
34 MockResponseReader(int64 response_id,
35 net::HttpResponseInfo* info, int info_size,
36 const char* data, int data_size)
[email protected]4252f602011-10-21 19:18:3637 : AppCacheResponseReader(response_id, 0, NULL),
[email protected]20d06f62011-07-22 23:57:3538 info_(info), info_size_(info_size),
39 data_(data), data_size_(data_size) {
40 }
dchengc2282aa2014-10-21 12:07:5841 void ReadInfo(HttpResponseInfoIOBuffer* info_buf,
42 const net::CompletionCallback& callback) override {
[email protected]20d06f62011-07-22 23:57:3543 info_buffer_ = info_buf;
[email protected]50304162011-12-21 17:51:3044 callback_ = callback; // Cleared on completion.
[email protected]20d06f62011-07-22 23:57:3545
46 int rv = info_.get() ? info_size_ : net::ERR_FAILED;
47 info_buffer_->http_info.reset(info_.release());
48 info_buffer_->response_data_size = data_size_;
49 ScheduleUserCallback(rv);
50 }
dchengc2282aa2014-10-21 12:07:5851 void ReadData(net::IOBuffer* buf,
52 int buf_len,
53 const net::CompletionCallback& callback) override {
[email protected]20d06f62011-07-22 23:57:3554 buffer_ = buf;
55 buffer_len_ = buf_len;
[email protected]50304162011-12-21 17:51:3056 callback_ = callback; // Cleared on completion.
[email protected]20d06f62011-07-22 23:57:3557
58 if (!data_) {
59 ScheduleUserCallback(net::ERR_CACHE_READ_FAILURE);
60 return;
61 }
62 DCHECK(buf_len >= data_size_);
63 memcpy(buf->data(), data_, data_size_);
64 ScheduleUserCallback(data_size_);
65 data_size_ = 0;
66 }
67
68 private:
69 void ScheduleUserCallback(int result) {
[email protected]4cc586b2013-05-07 12:43:3270 base::MessageLoop::current()->PostTask(FROM_HERE,
[email protected]72a3ce52011-12-22 05:10:2471 base::Bind(&MockResponseReader::InvokeUserCompletionCallback,
[email protected]e29f9332011-10-28 22:44:5772 weak_factory_.GetWeakPtr(), result));
[email protected]20d06f62011-07-22 23:57:3573 }
74
75 scoped_ptr<net::HttpResponseInfo> info_;
76 int info_size_;
77 const char* data_;
78 int data_size_;
79};
80
81} // namespace
82
[email protected]e0184cb2011-06-10 23:29:0983
[email protected]63ef85512014-06-05 14:21:2684class AppCacheServiceImplTest : public testing::Test {
[email protected]e0184cb2011-06-10 23:29:0985 public:
[email protected]63ef85512014-06-05 14:21:2686 AppCacheServiceImplTest()
[email protected]e0184cb2011-06-10 23:29:0987 : kOrigin("http://hello/"),
[email protected]20d06f62011-07-22 23:57:3588 kManifestUrl(kOrigin.Resolve("manifest")),
[email protected]63ef85512014-06-05 14:21:2689 service_(new AppCacheServiceImpl(NULL)),
[email protected]e0184cb2011-06-10 23:29:0990 delete_result_(net::OK), delete_completion_count_(0),
[email protected]e0b9dda2013-04-30 01:05:4391 deletion_callback_(
[email protected]63ef85512014-06-05 14:21:2692 base::Bind(&AppCacheServiceImplTest::OnDeleteAppCachesComplete,
[email protected]e0b9dda2013-04-30 01:05:4393 base::Unretained(this))) {
[email protected]e0184cb2011-06-10 23:29:0994 // Setup to use mock storage.
95 service_->storage_.reset(new MockAppCacheStorage(service_.get()));
96 }
97
98 void OnDeleteAppCachesComplete(int result) {
99 delete_result_ = result;
100 ++delete_completion_count_;
101 }
102
103 MockAppCacheStorage* mock_storage() {
104 return static_cast<MockAppCacheStorage*>(service_->storage());
105 }
106
[email protected]20d06f62011-07-22 23:57:35107 void ResetStorage() {
108 service_->storage_.reset(new MockAppCacheStorage(service_.get()));
109 }
110
111 bool IsGroupStored(const GURL& manifest_url) {
112 return mock_storage()->IsGroupForManifestStored(manifest_url);
113 }
114
115 int CountPendingHelpers() {
116 return service_->pending_helpers_.size();
117 }
118
119 void SetupMockGroup() {
120 scoped_ptr<net::HttpResponseInfo> info(MakeMockResponseInfo());
121 const int kMockInfoSize = GetResponseInfoSize(info.get());
122
123 // Create a mock group, cache, and entry and stuff them into mock storage.
124 scoped_refptr<AppCacheGroup> group(
[email protected]2aaadde02013-02-15 07:01:46125 new AppCacheGroup(service_->storage(), kManifestUrl, kMockGroupId));
126 scoped_refptr<AppCache> cache(
127 new AppCache(service_->storage(), kMockCacheId));
[email protected]20d06f62011-07-22 23:57:35128 cache->AddEntry(
129 kManifestUrl,
130 AppCacheEntry(AppCacheEntry::MANIFEST, kMockResponseId,
131 kMockInfoSize + kMockBodySize));
132 cache->set_complete(true);
[email protected]ff875be52013-06-02 23:47:38133 group->AddCache(cache.get());
134 mock_storage()->AddStoredGroup(group.get());
135 mock_storage()->AddStoredCache(cache.get());
[email protected]20d06f62011-07-22 23:57:35136 }
137
138 void SetupMockReader(
139 bool valid_info, bool valid_data, bool valid_size) {
140 net::HttpResponseInfo* info = valid_info ? MakeMockResponseInfo() : NULL;
141 int info_size = info ? GetResponseInfoSize(info) : 0;
142 const char* data = valid_data ? kMockBody : NULL;
143 int data_size = valid_size ? kMockBodySize : 3;
144 mock_storage()->SimulateResponseReader(
145 new MockResponseReader(kMockResponseId, info, info_size,
146 data, data_size));
147 }
148
149 net::HttpResponseInfo* MakeMockResponseInfo() {
150 net::HttpResponseInfo* info = new net::HttpResponseInfo;
151 info->request_time = base::Time::Now();
152 info->response_time = base::Time::Now();
153 info->was_cached = false;
154 info->headers = new net::HttpResponseHeaders(
155 std::string(kMockHeaders, arraysize(kMockHeaders)));
156 return info;
157 }
158
159 int GetResponseInfoSize(const net::HttpResponseInfo* info) {
160 Pickle pickle;
161 return PickleResponseInfo(&pickle, info);
162 }
163
164 int PickleResponseInfo(Pickle* pickle, const net::HttpResponseInfo* info) {
165 const bool kSkipTransientHeaders = true;
166 const bool kTruncated = false;
167 info->Persist(pickle, kSkipTransientHeaders, kTruncated);
168 return pickle->size();
169 }
170
[email protected]e0184cb2011-06-10 23:29:09171 const GURL kOrigin;
[email protected]20d06f62011-07-22 23:57:35172 const GURL kManifestUrl;
[email protected]e0184cb2011-06-10 23:29:09173
[email protected]63ef85512014-06-05 14:21:26174 scoped_ptr<AppCacheServiceImpl> service_;
[email protected]e0184cb2011-06-10 23:29:09175 int delete_result_;
176 int delete_completion_count_;
[email protected]123f2742011-12-02 04:26:52177 net::CompletionCallback deletion_callback_;
[email protected]81b919c2012-06-08 00:57:16178
179 private:
[email protected]4cc586b2013-05-07 12:43:32180 base::MessageLoop message_loop_;
[email protected]e0184cb2011-06-10 23:29:09181};
182
[email protected]63ef85512014-06-05 14:21:26183TEST_F(AppCacheServiceImplTest, DeleteAppCachesForOrigin) {
[email protected]e0184cb2011-06-10 23:29:09184 // Without giving mock storage simiulated info, should fail.
[email protected]123f2742011-12-02 04:26:52185 service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback_);
[email protected]e0184cb2011-06-10 23:29:09186 EXPECT_EQ(0, delete_completion_count_);
[email protected]f1edfb7e2013-09-13 16:45:17187 base::RunLoop().RunUntilIdle();
[email protected]e0184cb2011-06-10 23:29:09188 EXPECT_EQ(1, delete_completion_count_);
189 EXPECT_EQ(net::ERR_FAILED, delete_result_);
190 delete_completion_count_ = 0;
191
192 // Should succeed given an empty info collection.
[email protected]98d6d4562014-06-25 20:57:55193 mock_storage()->SimulateGetAllInfo(new content::AppCacheInfoCollection);
[email protected]123f2742011-12-02 04:26:52194 service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback_);
[email protected]e0184cb2011-06-10 23:29:09195 EXPECT_EQ(0, delete_completion_count_);
[email protected]f1edfb7e2013-09-13 16:45:17196 base::RunLoop().RunUntilIdle();
[email protected]e0184cb2011-06-10 23:29:09197 EXPECT_EQ(1, delete_completion_count_);
198 EXPECT_EQ(net::OK, delete_result_);
199 delete_completion_count_ = 0;
200
201 scoped_refptr<AppCacheInfoCollection> info(new AppCacheInfoCollection);
202
203 // Should succeed given a non-empty info collection.
204 AppCacheInfo mock_manifest_1;
205 AppCacheInfo mock_manifest_2;
206 AppCacheInfo mock_manifest_3;
207 mock_manifest_1.manifest_url = kOrigin.Resolve("manifest1");
208 mock_manifest_2.manifest_url = kOrigin.Resolve("manifest2");
209 mock_manifest_3.manifest_url = kOrigin.Resolve("manifest3");
210 AppCacheInfoVector info_vector;
211 info_vector.push_back(mock_manifest_1);
212 info_vector.push_back(mock_manifest_2);
213 info_vector.push_back(mock_manifest_3);
214 info->infos_by_origin[kOrigin] = info_vector;
[email protected]ff875be52013-06-02 23:47:38215 mock_storage()->SimulateGetAllInfo(info.get());
[email protected]123f2742011-12-02 04:26:52216 service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback_);
[email protected]e0184cb2011-06-10 23:29:09217 EXPECT_EQ(0, delete_completion_count_);
[email protected]f1edfb7e2013-09-13 16:45:17218 base::RunLoop().RunUntilIdle();
[email protected]e0184cb2011-06-10 23:29:09219 EXPECT_EQ(1, delete_completion_count_);
220 EXPECT_EQ(net::OK, delete_result_);
221 delete_completion_count_ = 0;
222
223 // Should fail if storage fails to delete.
224 info->infos_by_origin[kOrigin] = info_vector;
[email protected]ff875be52013-06-02 23:47:38225 mock_storage()->SimulateGetAllInfo(info.get());
[email protected]e0184cb2011-06-10 23:29:09226 mock_storage()->SimulateMakeGroupObsoleteFailure();
[email protected]123f2742011-12-02 04:26:52227 service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback_);
[email protected]e0184cb2011-06-10 23:29:09228 EXPECT_EQ(0, delete_completion_count_);
[email protected]f1edfb7e2013-09-13 16:45:17229 base::RunLoop().RunUntilIdle();
[email protected]e0184cb2011-06-10 23:29:09230 EXPECT_EQ(1, delete_completion_count_);
231 EXPECT_EQ(net::ERR_FAILED, delete_result_);
232 delete_completion_count_ = 0;
233
234 // Should complete with abort error if the service is deleted
235 // prior to a delete completion.
[email protected]123f2742011-12-02 04:26:52236 service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback_);
[email protected]e0184cb2011-06-10 23:29:09237 EXPECT_EQ(0, delete_completion_count_);
238 service_.reset(); // kill it
239 EXPECT_EQ(1, delete_completion_count_);
240 EXPECT_EQ(net::ERR_ABORTED, delete_result_);
241 delete_completion_count_ = 0;
242
243 // Let any tasks lingering from the sudden deletion run and verify
244 // no other completion calls occur.
[email protected]f1edfb7e2013-09-13 16:45:17245 base::RunLoop().RunUntilIdle();
[email protected]e0184cb2011-06-10 23:29:09246 EXPECT_EQ(0, delete_completion_count_);
247}
248
[email protected]63ef85512014-06-05 14:21:26249TEST_F(AppCacheServiceImplTest, CheckAppCacheResponse) {
[email protected]20d06f62011-07-22 23:57:35250 // Check a non-existing manifest.
251 EXPECT_FALSE(IsGroupStored(kManifestUrl));
252 service_->CheckAppCacheResponse(kManifestUrl, 1, 1);
[email protected]f1edfb7e2013-09-13 16:45:17253 base::RunLoop().RunUntilIdle();
[email protected]20d06f62011-07-22 23:57:35254 EXPECT_EQ(0, CountPendingHelpers());
255 EXPECT_FALSE(IsGroupStored(kManifestUrl));
256 ResetStorage();
257
258 // Check a response that looks good.
259 // Nothing should be deleted.
260 SetupMockGroup();
261 EXPECT_TRUE(IsGroupStored(kManifestUrl));
262 SetupMockReader(true, true, true);
263 service_->CheckAppCacheResponse(kManifestUrl, kMockCacheId, kMockResponseId);
[email protected]f1edfb7e2013-09-13 16:45:17264 base::RunLoop().RunUntilIdle();
[email protected]20d06f62011-07-22 23:57:35265 EXPECT_EQ(0, CountPendingHelpers());
266 EXPECT_TRUE(IsGroupStored(kManifestUrl));
267 ResetStorage();
268
269 // Check a response for which there is no cache entry.
270 // The group should get deleted.
271 SetupMockGroup();
272 service_->CheckAppCacheResponse(kManifestUrl, kMockCacheId,
273 kMissingResponseId);
[email protected]f1edfb7e2013-09-13 16:45:17274 base::RunLoop().RunUntilIdle();
[email protected]20d06f62011-07-22 23:57:35275 EXPECT_EQ(0, CountPendingHelpers());
276 EXPECT_FALSE(IsGroupStored(kManifestUrl));
277 ResetStorage();
278
279 // Check a response for which there is no manifest entry in a newer version
280 // of the cache. Nothing should get deleted in this case.
281 SetupMockGroup();
282 service_->CheckAppCacheResponse(kManifestUrl, kMissingCacheId,
283 kMissingResponseId);
[email protected]f1edfb7e2013-09-13 16:45:17284 base::RunLoop().RunUntilIdle();
[email protected]20d06f62011-07-22 23:57:35285 EXPECT_EQ(0, CountPendingHelpers());
286 EXPECT_TRUE(IsGroupStored(kManifestUrl));
287 ResetStorage();
288
289 // Check a response with bad headers.
290 SetupMockGroup();
291 service_->CheckAppCacheResponse(kManifestUrl, kMockCacheId, kMockResponseId);
292 SetupMockReader(false, true, true);
[email protected]f1edfb7e2013-09-13 16:45:17293 base::RunLoop().RunUntilIdle();
[email protected]20d06f62011-07-22 23:57:35294 EXPECT_EQ(0, CountPendingHelpers());
295 EXPECT_FALSE(IsGroupStored(kManifestUrl));
296 ResetStorage();
297
298 // Check a response with bad data.
299 SetupMockGroup();
300 service_->CheckAppCacheResponse(kManifestUrl, kMockCacheId, kMockResponseId);
301 SetupMockReader(true, false, true);
[email protected]f1edfb7e2013-09-13 16:45:17302 base::RunLoop().RunUntilIdle();
[email protected]20d06f62011-07-22 23:57:35303 EXPECT_EQ(0, CountPendingHelpers());
304 EXPECT_FALSE(IsGroupStored(kManifestUrl));
305 ResetStorage();
306
307 // Check a response with truncated data.
308 SetupMockGroup();
309 service_->CheckAppCacheResponse(kManifestUrl, kMockCacheId, kMockResponseId);
310 SetupMockReader(true, true, false);
[email protected]f1edfb7e2013-09-13 16:45:17311 base::RunLoop().RunUntilIdle();
[email protected]20d06f62011-07-22 23:57:35312 EXPECT_EQ(0, CountPendingHelpers());
313 EXPECT_FALSE(IsGroupStored(kManifestUrl));
314 ResetStorage();
315
316 service_.reset(); // Clean up.
[email protected]f1edfb7e2013-09-13 16:45:17317 base::RunLoop().RunUntilIdle();
[email protected]20d06f62011-07-22 23:57:35318}
319
[email protected]15b44822014-02-04 00:57:56320// Just tests the backoff scheduling function, not the actual reinit function.
[email protected]63ef85512014-06-05 14:21:26321TEST_F(AppCacheServiceImplTest, ScheduleReinitialize) {
[email protected]15b44822014-02-04 00:57:56322 const base::TimeDelta kNoDelay;
323 const base::TimeDelta kOneSecond(base::TimeDelta::FromSeconds(1));
324 const base::TimeDelta k30Seconds(base::TimeDelta::FromSeconds(30));
325 const base::TimeDelta kOneHour(base::TimeDelta::FromHours(1));
326
327 // Do things get initialized as expected?
[email protected]63ef85512014-06-05 14:21:26328 scoped_ptr<AppCacheServiceImpl> service(new AppCacheServiceImpl(NULL));
[email protected]15b44822014-02-04 00:57:56329 EXPECT_TRUE(service->last_reinit_time_.is_null());
330 EXPECT_FALSE(service->reinit_timer_.IsRunning());
331 EXPECT_EQ(kNoDelay, service->next_reinit_delay_);
332
333 // Do we see artifacts of the timer pending and such?
334 service->ScheduleReinitialize();
335 EXPECT_TRUE(service->reinit_timer_.IsRunning());
336 EXPECT_EQ(kNoDelay, service->reinit_timer_.GetCurrentDelay());
337 EXPECT_EQ(k30Seconds, service->next_reinit_delay_);
338
339 // Nothing should change if already scheduled
340 service->ScheduleReinitialize();
341 EXPECT_TRUE(service->reinit_timer_.IsRunning());
342 EXPECT_EQ(kNoDelay, service->reinit_timer_.GetCurrentDelay());
343 EXPECT_EQ(k30Seconds, service->next_reinit_delay_);
344
345 // Does the delay increase as expected?
346 service->reinit_timer_.Stop();
347 service->last_reinit_time_ = base::Time::Now() - kOneSecond;
348 service->ScheduleReinitialize();
349 EXPECT_TRUE(service->reinit_timer_.IsRunning());
350 EXPECT_EQ(k30Seconds, service->reinit_timer_.GetCurrentDelay());
351 EXPECT_EQ(k30Seconds + k30Seconds, service->next_reinit_delay_);
352
353 // Does the delay reset as expected?
354 service->reinit_timer_.Stop();
355 service->last_reinit_time_ = base::Time::Now() -
356 base::TimeDelta::FromHours(2);
357 service->ScheduleReinitialize();
358 EXPECT_TRUE(service->reinit_timer_.IsRunning());
359 EXPECT_EQ(kNoDelay, service->reinit_timer_.GetCurrentDelay());
360 EXPECT_EQ(k30Seconds, service->next_reinit_delay_);
361
362 // Does the delay max out as expected?
363 service->reinit_timer_.Stop();
364 service->last_reinit_time_ = base::Time::Now() - kOneSecond;
365 service->next_reinit_delay_ = kOneHour;
366 service->ScheduleReinitialize();
367 EXPECT_TRUE(service->reinit_timer_.IsRunning());
368 EXPECT_EQ(kOneHour, service->reinit_timer_.GetCurrentDelay());
369 EXPECT_EQ(kOneHour, service->next_reinit_delay_);
370
371 // Fine to delete while pending.
372 service.reset(NULL);
373}
374
375
376
[email protected]a507b822014-04-12 05:10:24377} // namespace content