blob: 79febf7675ae465389e6b6551de3e5f70b7dd260 [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
avib7348942015-12-25 20:57:105#include <stdint.h>
6
[email protected]20d06f62011-07-22 23:57:357#include <string>
[email protected]e0184cb2011-06-10 23:29:098
[email protected]e29f9332011-10-28 22:44:579#include "base/bind.h"
[email protected]123f2742011-12-02 04:26:5210#include "base/bind_helpers.h"
skyostil95082a62015-06-05 19:53:0711#include "base/location.h"
avib7348942015-12-25 20:57:1012#include "base/macros.h"
[email protected]20d06f62011-07-22 23:57:3513#include "base/pickle.h"
[email protected]f1edfb7e2013-09-13 16:45:1714#include "base/run_loop.h"
skyostil95082a62015-06-05 19:53:0715#include "base/single_thread_task_runner.h"
16#include "base/thread_task_runner_handle.h"
[email protected]98d6d4562014-06-25 20:57:5517#include "content/browser/appcache/appcache_response.h"
18#include "content/browser/appcache/appcache_service_impl.h"
[email protected]71fe3d12014-04-22 00:32:3819#include "content/browser/appcache/mock_appcache_storage.h"
[email protected]e0184cb2011-06-10 23:29:0920#include "net/base/completion_callback.h"
[email protected]20d06f62011-07-22 23:57:3521#include "net/base/io_buffer.h"
22#include "net/http/http_response_headers.h"
[email protected]e0184cb2011-06-10 23:29:0923#include "testing/gtest/include/gtest/gtest.h"
[email protected]20d06f62011-07-22 23:57:3524
[email protected]a507b822014-04-12 05:10:2425namespace content {
[email protected]20d06f62011-07-22 23:57:3526namespace {
27
avib7348942015-12-25 20:57:1028const int64_t kMockGroupId = 1;
29const int64_t kMockCacheId = 1;
30const int64_t kMockResponseId = 1;
31const int64_t kMissingCacheId = 5;
32const int64_t kMissingResponseId = 5;
[email protected]20d06f62011-07-22 23:57:3533const char kMockHeaders[] =
34 "HTTP/1.0 200 OK\0Content-Length: 5\0\0";
35const char kMockBody[] = "Hello";
36const int kMockBodySize = 5;
37
38class MockResponseReader : public AppCacheResponseReader {
39 public:
avib7348942015-12-25 20:57:1040 MockResponseReader(int64_t response_id,
41 net::HttpResponseInfo* info,
42 int info_size,
43 const char* data,
44 int data_size)
[email protected]4252f602011-10-21 19:18:3645 : AppCacheResponseReader(response_id, 0, NULL),
avib7348942015-12-25 20:57:1046 info_(info),
47 info_size_(info_size),
48 data_(data),
49 data_size_(data_size) {}
dchengc2282aa2014-10-21 12:07:5850 void ReadInfo(HttpResponseInfoIOBuffer* info_buf,
51 const net::CompletionCallback& callback) override {
[email protected]20d06f62011-07-22 23:57:3552 info_buffer_ = info_buf;
[email protected]50304162011-12-21 17:51:3053 callback_ = callback; // Cleared on completion.
[email protected]20d06f62011-07-22 23:57:3554
55 int rv = info_.get() ? info_size_ : net::ERR_FAILED;
56 info_buffer_->http_info.reset(info_.release());
57 info_buffer_->response_data_size = data_size_;
58 ScheduleUserCallback(rv);
59 }
dchengc2282aa2014-10-21 12:07:5860 void ReadData(net::IOBuffer* buf,
61 int buf_len,
62 const net::CompletionCallback& callback) override {
[email protected]20d06f62011-07-22 23:57:3563 buffer_ = buf;
64 buffer_len_ = buf_len;
[email protected]50304162011-12-21 17:51:3065 callback_ = callback; // Cleared on completion.
[email protected]20d06f62011-07-22 23:57:3566
67 if (!data_) {
68 ScheduleUserCallback(net::ERR_CACHE_READ_FAILURE);
69 return;
70 }
71 DCHECK(buf_len >= data_size_);
72 memcpy(buf->data(), data_, data_size_);
73 ScheduleUserCallback(data_size_);
74 data_size_ = 0;
75 }
76
77 private:
78 void ScheduleUserCallback(int result) {
skyostil95082a62015-06-05 19:53:0779 base::ThreadTaskRunnerHandle::Get()->PostTask(
80 FROM_HERE, base::Bind(&MockResponseReader::InvokeUserCompletionCallback,
81 weak_factory_.GetWeakPtr(), result));
[email protected]20d06f62011-07-22 23:57:3582 }
83
84 scoped_ptr<net::HttpResponseInfo> info_;
85 int info_size_;
86 const char* data_;
87 int data_size_;
88};
89
90} // namespace
91
[email protected]e0184cb2011-06-10 23:29:0992
[email protected]63ef85512014-06-05 14:21:2693class AppCacheServiceImplTest : public testing::Test {
[email protected]e0184cb2011-06-10 23:29:0994 public:
[email protected]63ef85512014-06-05 14:21:2695 AppCacheServiceImplTest()
[email protected]e0184cb2011-06-10 23:29:0996 : kOrigin("http://hello/"),
[email protected]20d06f62011-07-22 23:57:3597 kManifestUrl(kOrigin.Resolve("manifest")),
[email protected]63ef85512014-06-05 14:21:2698 service_(new AppCacheServiceImpl(NULL)),
[email protected]e0184cb2011-06-10 23:29:0999 delete_result_(net::OK), delete_completion_count_(0),
[email protected]e0b9dda2013-04-30 01:05:43100 deletion_callback_(
[email protected]63ef85512014-06-05 14:21:26101 base::Bind(&AppCacheServiceImplTest::OnDeleteAppCachesComplete,
[email protected]e0b9dda2013-04-30 01:05:43102 base::Unretained(this))) {
[email protected]e0184cb2011-06-10 23:29:09103 // Setup to use mock storage.
104 service_->storage_.reset(new MockAppCacheStorage(service_.get()));
105 }
106
107 void OnDeleteAppCachesComplete(int result) {
108 delete_result_ = result;
109 ++delete_completion_count_;
110 }
111
112 MockAppCacheStorage* mock_storage() {
113 return static_cast<MockAppCacheStorage*>(service_->storage());
114 }
115
[email protected]20d06f62011-07-22 23:57:35116 void ResetStorage() {
117 service_->storage_.reset(new MockAppCacheStorage(service_.get()));
118 }
119
120 bool IsGroupStored(const GURL& manifest_url) {
121 return mock_storage()->IsGroupForManifestStored(manifest_url);
122 }
123
124 int CountPendingHelpers() {
125 return service_->pending_helpers_.size();
126 }
127
128 void SetupMockGroup() {
129 scoped_ptr<net::HttpResponseInfo> info(MakeMockResponseInfo());
130 const int kMockInfoSize = GetResponseInfoSize(info.get());
131
132 // Create a mock group, cache, and entry and stuff them into mock storage.
133 scoped_refptr<AppCacheGroup> group(
[email protected]2aaadde02013-02-15 07:01:46134 new AppCacheGroup(service_->storage(), kManifestUrl, kMockGroupId));
135 scoped_refptr<AppCache> cache(
136 new AppCache(service_->storage(), kMockCacheId));
[email protected]20d06f62011-07-22 23:57:35137 cache->AddEntry(
138 kManifestUrl,
139 AppCacheEntry(AppCacheEntry::MANIFEST, kMockResponseId,
140 kMockInfoSize + kMockBodySize));
141 cache->set_complete(true);
[email protected]ff875be52013-06-02 23:47:38142 group->AddCache(cache.get());
143 mock_storage()->AddStoredGroup(group.get());
144 mock_storage()->AddStoredCache(cache.get());
[email protected]20d06f62011-07-22 23:57:35145 }
146
147 void SetupMockReader(
148 bool valid_info, bool valid_data, bool valid_size) {
149 net::HttpResponseInfo* info = valid_info ? MakeMockResponseInfo() : NULL;
150 int info_size = info ? GetResponseInfoSize(info) : 0;
151 const char* data = valid_data ? kMockBody : NULL;
152 int data_size = valid_size ? kMockBodySize : 3;
153 mock_storage()->SimulateResponseReader(
154 new MockResponseReader(kMockResponseId, info, info_size,
155 data, data_size));
156 }
157
158 net::HttpResponseInfo* MakeMockResponseInfo() {
159 net::HttpResponseInfo* info = new net::HttpResponseInfo;
160 info->request_time = base::Time::Now();
161 info->response_time = base::Time::Now();
162 info->was_cached = false;
163 info->headers = new net::HttpResponseHeaders(
164 std::string(kMockHeaders, arraysize(kMockHeaders)));
165 return info;
166 }
167
168 int GetResponseInfoSize(const net::HttpResponseInfo* info) {
brettwbd4d7112015-06-03 04:29:25169 base::Pickle pickle;
[email protected]20d06f62011-07-22 23:57:35170 return PickleResponseInfo(&pickle, info);
171 }
172
brettwbd4d7112015-06-03 04:29:25173 int PickleResponseInfo(base::Pickle* pickle,
174 const net::HttpResponseInfo* info) {
[email protected]20d06f62011-07-22 23:57:35175 const bool kSkipTransientHeaders = true;
176 const bool kTruncated = false;
177 info->Persist(pickle, kSkipTransientHeaders, kTruncated);
178 return pickle->size();
179 }
180
[email protected]e0184cb2011-06-10 23:29:09181 const GURL kOrigin;
[email protected]20d06f62011-07-22 23:57:35182 const GURL kManifestUrl;
[email protected]e0184cb2011-06-10 23:29:09183
[email protected]63ef85512014-06-05 14:21:26184 scoped_ptr<AppCacheServiceImpl> service_;
[email protected]e0184cb2011-06-10 23:29:09185 int delete_result_;
186 int delete_completion_count_;
[email protected]123f2742011-12-02 04:26:52187 net::CompletionCallback deletion_callback_;
[email protected]81b919c2012-06-08 00:57:16188
189 private:
[email protected]4cc586b2013-05-07 12:43:32190 base::MessageLoop message_loop_;
[email protected]e0184cb2011-06-10 23:29:09191};
192
[email protected]63ef85512014-06-05 14:21:26193TEST_F(AppCacheServiceImplTest, DeleteAppCachesForOrigin) {
[email protected]e0184cb2011-06-10 23:29:09194 // Without giving mock storage simiulated info, should fail.
[email protected]123f2742011-12-02 04:26:52195 service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback_);
[email protected]e0184cb2011-06-10 23:29:09196 EXPECT_EQ(0, delete_completion_count_);
[email protected]f1edfb7e2013-09-13 16:45:17197 base::RunLoop().RunUntilIdle();
[email protected]e0184cb2011-06-10 23:29:09198 EXPECT_EQ(1, delete_completion_count_);
199 EXPECT_EQ(net::ERR_FAILED, delete_result_);
200 delete_completion_count_ = 0;
201
202 // Should succeed given an empty info collection.
[email protected]98d6d4562014-06-25 20:57:55203 mock_storage()->SimulateGetAllInfo(new content::AppCacheInfoCollection);
[email protected]123f2742011-12-02 04:26:52204 service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback_);
[email protected]e0184cb2011-06-10 23:29:09205 EXPECT_EQ(0, delete_completion_count_);
[email protected]f1edfb7e2013-09-13 16:45:17206 base::RunLoop().RunUntilIdle();
[email protected]e0184cb2011-06-10 23:29:09207 EXPECT_EQ(1, delete_completion_count_);
208 EXPECT_EQ(net::OK, delete_result_);
209 delete_completion_count_ = 0;
210
211 scoped_refptr<AppCacheInfoCollection> info(new AppCacheInfoCollection);
212
213 // Should succeed given a non-empty info collection.
214 AppCacheInfo mock_manifest_1;
215 AppCacheInfo mock_manifest_2;
216 AppCacheInfo mock_manifest_3;
217 mock_manifest_1.manifest_url = kOrigin.Resolve("manifest1");
218 mock_manifest_2.manifest_url = kOrigin.Resolve("manifest2");
219 mock_manifest_3.manifest_url = kOrigin.Resolve("manifest3");
220 AppCacheInfoVector info_vector;
221 info_vector.push_back(mock_manifest_1);
222 info_vector.push_back(mock_manifest_2);
223 info_vector.push_back(mock_manifest_3);
224 info->infos_by_origin[kOrigin] = info_vector;
[email protected]ff875be52013-06-02 23:47:38225 mock_storage()->SimulateGetAllInfo(info.get());
[email protected]123f2742011-12-02 04:26:52226 service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback_);
[email protected]e0184cb2011-06-10 23:29:09227 EXPECT_EQ(0, delete_completion_count_);
[email protected]f1edfb7e2013-09-13 16:45:17228 base::RunLoop().RunUntilIdle();
[email protected]e0184cb2011-06-10 23:29:09229 EXPECT_EQ(1, delete_completion_count_);
230 EXPECT_EQ(net::OK, delete_result_);
231 delete_completion_count_ = 0;
232
233 // Should fail if storage fails to delete.
234 info->infos_by_origin[kOrigin] = info_vector;
[email protected]ff875be52013-06-02 23:47:38235 mock_storage()->SimulateGetAllInfo(info.get());
[email protected]e0184cb2011-06-10 23:29:09236 mock_storage()->SimulateMakeGroupObsoleteFailure();
[email protected]123f2742011-12-02 04:26:52237 service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback_);
[email protected]e0184cb2011-06-10 23:29:09238 EXPECT_EQ(0, delete_completion_count_);
[email protected]f1edfb7e2013-09-13 16:45:17239 base::RunLoop().RunUntilIdle();
[email protected]e0184cb2011-06-10 23:29:09240 EXPECT_EQ(1, delete_completion_count_);
241 EXPECT_EQ(net::ERR_FAILED, delete_result_);
242 delete_completion_count_ = 0;
243
244 // Should complete with abort error if the service is deleted
245 // prior to a delete completion.
[email protected]123f2742011-12-02 04:26:52246 service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback_);
[email protected]e0184cb2011-06-10 23:29:09247 EXPECT_EQ(0, delete_completion_count_);
248 service_.reset(); // kill it
249 EXPECT_EQ(1, delete_completion_count_);
250 EXPECT_EQ(net::ERR_ABORTED, delete_result_);
251 delete_completion_count_ = 0;
252
253 // Let any tasks lingering from the sudden deletion run and verify
254 // no other completion calls occur.
[email protected]f1edfb7e2013-09-13 16:45:17255 base::RunLoop().RunUntilIdle();
[email protected]e0184cb2011-06-10 23:29:09256 EXPECT_EQ(0, delete_completion_count_);
257}
258
[email protected]63ef85512014-06-05 14:21:26259TEST_F(AppCacheServiceImplTest, CheckAppCacheResponse) {
[email protected]20d06f62011-07-22 23:57:35260 // Check a non-existing manifest.
261 EXPECT_FALSE(IsGroupStored(kManifestUrl));
262 service_->CheckAppCacheResponse(kManifestUrl, 1, 1);
[email protected]f1edfb7e2013-09-13 16:45:17263 base::RunLoop().RunUntilIdle();
[email protected]20d06f62011-07-22 23:57:35264 EXPECT_EQ(0, CountPendingHelpers());
265 EXPECT_FALSE(IsGroupStored(kManifestUrl));
266 ResetStorage();
267
268 // Check a response that looks good.
269 // Nothing should be deleted.
270 SetupMockGroup();
271 EXPECT_TRUE(IsGroupStored(kManifestUrl));
272 SetupMockReader(true, true, true);
273 service_->CheckAppCacheResponse(kManifestUrl, kMockCacheId, kMockResponseId);
[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_TRUE(IsGroupStored(kManifestUrl));
277 ResetStorage();
278
279 // Check a response for which there is no cache entry.
280 // The group should get deleted.
281 SetupMockGroup();
282 service_->CheckAppCacheResponse(kManifestUrl, kMockCacheId,
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_FALSE(IsGroupStored(kManifestUrl));
287 ResetStorage();
288
289 // Check a response for which there is no manifest entry in a newer version
290 // of the cache. Nothing should get deleted in this case.
291 SetupMockGroup();
292 service_->CheckAppCacheResponse(kManifestUrl, kMissingCacheId,
293 kMissingResponseId);
[email protected]f1edfb7e2013-09-13 16:45:17294 base::RunLoop().RunUntilIdle();
[email protected]20d06f62011-07-22 23:57:35295 EXPECT_EQ(0, CountPendingHelpers());
296 EXPECT_TRUE(IsGroupStored(kManifestUrl));
297 ResetStorage();
298
299 // Check a response with bad headers.
300 SetupMockGroup();
301 service_->CheckAppCacheResponse(kManifestUrl, kMockCacheId, kMockResponseId);
302 SetupMockReader(false, true, true);
[email protected]f1edfb7e2013-09-13 16:45:17303 base::RunLoop().RunUntilIdle();
[email protected]20d06f62011-07-22 23:57:35304 EXPECT_EQ(0, CountPendingHelpers());
305 EXPECT_FALSE(IsGroupStored(kManifestUrl));
306 ResetStorage();
307
308 // Check a response with bad data.
309 SetupMockGroup();
310 service_->CheckAppCacheResponse(kManifestUrl, kMockCacheId, kMockResponseId);
311 SetupMockReader(true, false, true);
[email protected]f1edfb7e2013-09-13 16:45:17312 base::RunLoop().RunUntilIdle();
[email protected]20d06f62011-07-22 23:57:35313 EXPECT_EQ(0, CountPendingHelpers());
314 EXPECT_FALSE(IsGroupStored(kManifestUrl));
315 ResetStorage();
316
317 // Check a response with truncated data.
318 SetupMockGroup();
319 service_->CheckAppCacheResponse(kManifestUrl, kMockCacheId, kMockResponseId);
320 SetupMockReader(true, true, false);
[email protected]f1edfb7e2013-09-13 16:45:17321 base::RunLoop().RunUntilIdle();
[email protected]20d06f62011-07-22 23:57:35322 EXPECT_EQ(0, CountPendingHelpers());
323 EXPECT_FALSE(IsGroupStored(kManifestUrl));
324 ResetStorage();
325
326 service_.reset(); // Clean up.
[email protected]f1edfb7e2013-09-13 16:45:17327 base::RunLoop().RunUntilIdle();
[email protected]20d06f62011-07-22 23:57:35328}
329
[email protected]15b44822014-02-04 00:57:56330// Just tests the backoff scheduling function, not the actual reinit function.
[email protected]63ef85512014-06-05 14:21:26331TEST_F(AppCacheServiceImplTest, ScheduleReinitialize) {
[email protected]15b44822014-02-04 00:57:56332 const base::TimeDelta kNoDelay;
333 const base::TimeDelta kOneSecond(base::TimeDelta::FromSeconds(1));
334 const base::TimeDelta k30Seconds(base::TimeDelta::FromSeconds(30));
335 const base::TimeDelta kOneHour(base::TimeDelta::FromHours(1));
336
337 // Do things get initialized as expected?
[email protected]63ef85512014-06-05 14:21:26338 scoped_ptr<AppCacheServiceImpl> service(new AppCacheServiceImpl(NULL));
[email protected]15b44822014-02-04 00:57:56339 EXPECT_TRUE(service->last_reinit_time_.is_null());
340 EXPECT_FALSE(service->reinit_timer_.IsRunning());
341 EXPECT_EQ(kNoDelay, service->next_reinit_delay_);
342
343 // Do we see artifacts of the timer pending and such?
344 service->ScheduleReinitialize();
345 EXPECT_TRUE(service->reinit_timer_.IsRunning());
346 EXPECT_EQ(kNoDelay, service->reinit_timer_.GetCurrentDelay());
347 EXPECT_EQ(k30Seconds, service->next_reinit_delay_);
348
349 // Nothing should change if already scheduled
350 service->ScheduleReinitialize();
351 EXPECT_TRUE(service->reinit_timer_.IsRunning());
352 EXPECT_EQ(kNoDelay, service->reinit_timer_.GetCurrentDelay());
353 EXPECT_EQ(k30Seconds, service->next_reinit_delay_);
354
355 // Does the delay increase as expected?
356 service->reinit_timer_.Stop();
357 service->last_reinit_time_ = base::Time::Now() - kOneSecond;
358 service->ScheduleReinitialize();
359 EXPECT_TRUE(service->reinit_timer_.IsRunning());
360 EXPECT_EQ(k30Seconds, service->reinit_timer_.GetCurrentDelay());
361 EXPECT_EQ(k30Seconds + k30Seconds, service->next_reinit_delay_);
362
363 // Does the delay reset as expected?
364 service->reinit_timer_.Stop();
365 service->last_reinit_time_ = base::Time::Now() -
366 base::TimeDelta::FromHours(2);
367 service->ScheduleReinitialize();
368 EXPECT_TRUE(service->reinit_timer_.IsRunning());
369 EXPECT_EQ(kNoDelay, service->reinit_timer_.GetCurrentDelay());
370 EXPECT_EQ(k30Seconds, service->next_reinit_delay_);
371
372 // Does the delay max out as expected?
373 service->reinit_timer_.Stop();
374 service->last_reinit_time_ = base::Time::Now() - kOneSecond;
375 service->next_reinit_delay_ = kOneHour;
376 service->ScheduleReinitialize();
377 EXPECT_TRUE(service->reinit_timer_.IsRunning());
378 EXPECT_EQ(kOneHour, service->reinit_timer_.GetCurrentDelay());
379 EXPECT_EQ(kOneHour, service->next_reinit_delay_);
380
381 // Fine to delete while pending.
382 service.reset(NULL);
383}
384
385
386
[email protected]a507b822014-04-12 05:10:24387} // namespace content