blob: a50ce5ca7fcd33c1b131494884441f763e89de54 [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"
fdoray86573e42017-04-06 17:26:3616#include "base/test/scoped_task_environment.h"
gab30f26df2016-05-11 19:37:5517#include "base/threading/thread_task_runner_handle.h"
[email protected]98d6d4562014-06-25 20:57:5518#include "content/browser/appcache/appcache_response.h"
19#include "content/browser/appcache/appcache_service_impl.h"
[email protected]71fe3d12014-04-22 00:32:3820#include "content/browser/appcache/mock_appcache_storage.h"
Bence Béky8f278af2018-08-10 15:14:2721#include "net/base/completion_once_callback.h"
[email protected]20d06f62011-07-22 23:57:3522#include "net/base/io_buffer.h"
23#include "net/http/http_response_headers.h"
[email protected]e0184cb2011-06-10 23:29:0924#include "testing/gtest/include/gtest/gtest.h"
[email protected]20d06f62011-07-22 23:57:3525
[email protected]a507b822014-04-12 05:10:2426namespace content {
[email protected]20d06f62011-07-22 23:57:3527namespace {
28
avib7348942015-12-25 20:57:1029const int64_t kMockGroupId = 1;
30const int64_t kMockCacheId = 1;
31const int64_t kMockResponseId = 1;
32const int64_t kMissingCacheId = 5;
33const int64_t kMissingResponseId = 5;
[email protected]20d06f62011-07-22 23:57:3534const char kMockHeaders[] =
35 "HTTP/1.0 200 OK\0Content-Length: 5\0\0";
36const char kMockBody[] = "Hello";
37const int kMockBodySize = 5;
38
39class MockResponseReader : public AppCacheResponseReader {
40 public:
avib7348942015-12-25 20:57:1041 MockResponseReader(int64_t response_id,
42 net::HttpResponseInfo* info,
43 int info_size,
44 const char* data,
45 int data_size)
Victor Costan7e182c512018-10-04 17:42:4846 : AppCacheResponseReader(response_id, /*disk_cache=*/nullptr),
avib7348942015-12-25 20:57:1047 info_(info),
48 info_size_(info_size),
49 data_(data),
50 data_size_(data_size) {}
dchengc2282aa2014-10-21 12:07:5851 void ReadInfo(HttpResponseInfoIOBuffer* info_buf,
Mark Pilgrim3561fad2017-09-21 13:25:1952 OnceCompletionCallback callback) override {
[email protected]20d06f62011-07-22 23:57:3553 info_buffer_ = info_buf;
Mark Pilgrim3561fad2017-09-21 13:25:1954 callback_ = std::move(callback); // Cleared on completion.
[email protected]20d06f62011-07-22 23:57:3555
56 int rv = info_.get() ? info_size_ : net::ERR_FAILED;
57 info_buffer_->http_info.reset(info_.release());
58 info_buffer_->response_data_size = data_size_;
59 ScheduleUserCallback(rv);
60 }
dchengc2282aa2014-10-21 12:07:5861 void ReadData(net::IOBuffer* buf,
62 int buf_len,
Mark Pilgrim3561fad2017-09-21 13:25:1963 OnceCompletionCallback callback) override {
[email protected]20d06f62011-07-22 23:57:3564 buffer_ = buf;
65 buffer_len_ = buf_len;
Mark Pilgrim3561fad2017-09-21 13:25:1966 callback_ = std::move(callback); // Cleared on completion.
[email protected]20d06f62011-07-22 23:57:3567
68 if (!data_) {
69 ScheduleUserCallback(net::ERR_CACHE_READ_FAILURE);
70 return;
71 }
72 DCHECK(buf_len >= data_size_);
73 memcpy(buf->data(), data_, data_size_);
74 ScheduleUserCallback(data_size_);
75 data_size_ = 0;
76 }
77
78 private:
79 void ScheduleUserCallback(int result) {
skyostil95082a62015-06-05 19:53:0780 base::ThreadTaskRunnerHandle::Get()->PostTask(
tzikfbcbc332017-08-17 00:37:5481 FROM_HERE,
82 base::BindOnce(&MockResponseReader::InvokeUserCompletionCallback,
83 weak_factory_.GetWeakPtr(), result));
[email protected]20d06f62011-07-22 23:57:3584 }
85
dcheng59716272016-04-09 05:19:0886 std::unique_ptr<net::HttpResponseInfo> info_;
[email protected]20d06f62011-07-22 23:57:3587 int info_size_;
88 const char* data_;
89 int data_size_;
90};
91
92} // namespace
93
[email protected]e0184cb2011-06-10 23:29:0994
[email protected]63ef85512014-06-05 14:21:2695class AppCacheServiceImplTest : public testing::Test {
[email protected]e0184cb2011-06-10 23:29:0996 public:
[email protected]63ef85512014-06-05 14:21:2697 AppCacheServiceImplTest()
Xunran Dinge8baedad2018-03-26 21:06:4298 : kOriginURL("http://hello/"),
99 kOrigin(url::Origin::Create(kOriginURL)),
100 kManifestUrl(kOriginURL.Resolve("manifest")),
Ivan Kotenkov2c0d2bb32017-11-01 15:41:28101 service_(new AppCacheServiceImpl(nullptr)),
102 delete_result_(net::OK),
Bence Béky8f278af2018-08-10 15:14:27103 delete_completion_count_(0) {
[email protected]e0184cb2011-06-10 23:29:09104 // Setup to use mock storage.
105 service_->storage_.reset(new MockAppCacheStorage(service_.get()));
106 }
107
108 void OnDeleteAppCachesComplete(int result) {
109 delete_result_ = result;
110 ++delete_completion_count_;
111 }
112
113 MockAppCacheStorage* mock_storage() {
114 return static_cast<MockAppCacheStorage*>(service_->storage());
115 }
116
[email protected]20d06f62011-07-22 23:57:35117 void ResetStorage() {
118 service_->storage_.reset(new MockAppCacheStorage(service_.get()));
119 }
120
121 bool IsGroupStored(const GURL& manifest_url) {
122 return mock_storage()->IsGroupForManifestStored(manifest_url);
123 }
124
125 int CountPendingHelpers() {
126 return service_->pending_helpers_.size();
127 }
128
129 void SetupMockGroup() {
dcheng59716272016-04-09 05:19:08130 std::unique_ptr<net::HttpResponseInfo> info(MakeMockResponseInfo());
[email protected]20d06f62011-07-22 23:57:35131 const int kMockInfoSize = GetResponseInfoSize(info.get());
132
133 // Create a mock group, cache, and entry and stuff them into mock storage.
134 scoped_refptr<AppCacheGroup> group(
[email protected]2aaadde02013-02-15 07:01:46135 new AppCacheGroup(service_->storage(), kManifestUrl, kMockGroupId));
136 scoped_refptr<AppCache> cache(
137 new AppCache(service_->storage(), kMockCacheId));
[email protected]20d06f62011-07-22 23:57:35138 cache->AddEntry(
139 kManifestUrl,
140 AppCacheEntry(AppCacheEntry::MANIFEST, kMockResponseId,
141 kMockInfoSize + kMockBodySize));
142 cache->set_complete(true);
[email protected]ff875be52013-06-02 23:47:38143 group->AddCache(cache.get());
144 mock_storage()->AddStoredGroup(group.get());
145 mock_storage()->AddStoredCache(cache.get());
[email protected]20d06f62011-07-22 23:57:35146 }
147
148 void SetupMockReader(
149 bool valid_info, bool valid_data, bool valid_size) {
Ivan Kotenkov2c0d2bb32017-11-01 15:41:28150 net::HttpResponseInfo* info = valid_info ? MakeMockResponseInfo() : nullptr;
[email protected]20d06f62011-07-22 23:57:35151 int info_size = info ? GetResponseInfoSize(info) : 0;
Ivan Kotenkov2c0d2bb32017-11-01 15:41:28152 const char* data = valid_data ? kMockBody : nullptr;
[email protected]20d06f62011-07-22 23:57:35153 int data_size = valid_size ? kMockBodySize : 3;
154 mock_storage()->SimulateResponseReader(
155 new MockResponseReader(kMockResponseId, info, info_size,
156 data, data_size));
157 }
158
159 net::HttpResponseInfo* MakeMockResponseInfo() {
160 net::HttpResponseInfo* info = new net::HttpResponseInfo;
161 info->request_time = base::Time::Now();
162 info->response_time = base::Time::Now();
163 info->was_cached = false;
164 info->headers = new net::HttpResponseHeaders(
165 std::string(kMockHeaders, arraysize(kMockHeaders)));
166 return info;
167 }
168
169 int GetResponseInfoSize(const net::HttpResponseInfo* info) {
brettwbd4d7112015-06-03 04:29:25170 base::Pickle pickle;
[email protected]20d06f62011-07-22 23:57:35171 return PickleResponseInfo(&pickle, info);
172 }
173
brettwbd4d7112015-06-03 04:29:25174 int PickleResponseInfo(base::Pickle* pickle,
175 const net::HttpResponseInfo* info) {
[email protected]20d06f62011-07-22 23:57:35176 const bool kSkipTransientHeaders = true;
177 const bool kTruncated = false;
178 info->Persist(pickle, kSkipTransientHeaders, kTruncated);
179 return pickle->size();
180 }
181
Bence Béky8f278af2018-08-10 15:14:27182 net::CompletionOnceCallback deletion_callback() {
183 return base::BindOnce(&AppCacheServiceImplTest::OnDeleteAppCachesComplete,
184 base::Unretained(this));
185 }
186
Xunran Dinge8baedad2018-03-26 21:06:42187 const GURL kOriginURL;
188 const url::Origin kOrigin;
[email protected]20d06f62011-07-22 23:57:35189 const GURL kManifestUrl;
[email protected]e0184cb2011-06-10 23:29:09190
michaelnbe6b2412017-07-11 02:11:26191 base::test::ScopedTaskEnvironment scoped_task_environment_;
dcheng59716272016-04-09 05:19:08192 std::unique_ptr<AppCacheServiceImpl> service_;
[email protected]e0184cb2011-06-10 23:29:09193 int delete_result_;
194 int delete_completion_count_;
[email protected]e0184cb2011-06-10 23:29:09195};
196
[email protected]63ef85512014-06-05 14:21:26197TEST_F(AppCacheServiceImplTest, DeleteAppCachesForOrigin) {
[email protected]e0184cb2011-06-10 23:29:09198 // Without giving mock storage simiulated info, should fail.
Bence Béky8f278af2018-08-10 15:14:27199 service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback());
[email protected]e0184cb2011-06-10 23:29:09200 EXPECT_EQ(0, delete_completion_count_);
[email protected]f1edfb7e2013-09-13 16:45:17201 base::RunLoop().RunUntilIdle();
[email protected]e0184cb2011-06-10 23:29:09202 EXPECT_EQ(1, delete_completion_count_);
203 EXPECT_EQ(net::ERR_FAILED, delete_result_);
204 delete_completion_count_ = 0;
205
206 // Should succeed given an empty info collection.
[email protected]98d6d4562014-06-25 20:57:55207 mock_storage()->SimulateGetAllInfo(new content::AppCacheInfoCollection);
Bence Béky8f278af2018-08-10 15:14:27208 service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback());
[email protected]e0184cb2011-06-10 23:29:09209 EXPECT_EQ(0, delete_completion_count_);
[email protected]f1edfb7e2013-09-13 16:45:17210 base::RunLoop().RunUntilIdle();
[email protected]e0184cb2011-06-10 23:29:09211 EXPECT_EQ(1, delete_completion_count_);
212 EXPECT_EQ(net::OK, delete_result_);
213 delete_completion_count_ = 0;
214
215 scoped_refptr<AppCacheInfoCollection> info(new AppCacheInfoCollection);
216
217 // Should succeed given a non-empty info collection.
218 AppCacheInfo mock_manifest_1;
219 AppCacheInfo mock_manifest_2;
220 AppCacheInfo mock_manifest_3;
Xunran Dinge8baedad2018-03-26 21:06:42221 mock_manifest_1.manifest_url = kOriginURL.Resolve("manifest1");
222 mock_manifest_2.manifest_url = kOriginURL.Resolve("manifest2");
223 mock_manifest_3.manifest_url = kOriginURL.Resolve("manifest3");
[email protected]e0184cb2011-06-10 23:29:09224 AppCacheInfoVector info_vector;
225 info_vector.push_back(mock_manifest_1);
226 info_vector.push_back(mock_manifest_2);
227 info_vector.push_back(mock_manifest_3);
Xunran Dinge4c04692018-03-29 05:50:55228 info->infos_by_origin[kOrigin] = info_vector;
[email protected]ff875be52013-06-02 23:47:38229 mock_storage()->SimulateGetAllInfo(info.get());
Bence Béky8f278af2018-08-10 15:14:27230 service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback());
[email protected]e0184cb2011-06-10 23:29:09231 EXPECT_EQ(0, delete_completion_count_);
[email protected]f1edfb7e2013-09-13 16:45:17232 base::RunLoop().RunUntilIdle();
[email protected]e0184cb2011-06-10 23:29:09233 EXPECT_EQ(1, delete_completion_count_);
234 EXPECT_EQ(net::OK, delete_result_);
235 delete_completion_count_ = 0;
236
237 // Should fail if storage fails to delete.
Xunran Dinge4c04692018-03-29 05:50:55238 info->infos_by_origin[kOrigin] = info_vector;
[email protected]ff875be52013-06-02 23:47:38239 mock_storage()->SimulateGetAllInfo(info.get());
[email protected]e0184cb2011-06-10 23:29:09240 mock_storage()->SimulateMakeGroupObsoleteFailure();
Bence Béky8f278af2018-08-10 15:14:27241 service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback());
[email protected]e0184cb2011-06-10 23:29:09242 EXPECT_EQ(0, delete_completion_count_);
[email protected]f1edfb7e2013-09-13 16:45:17243 base::RunLoop().RunUntilIdle();
[email protected]e0184cb2011-06-10 23:29:09244 EXPECT_EQ(1, delete_completion_count_);
245 EXPECT_EQ(net::ERR_FAILED, delete_result_);
246 delete_completion_count_ = 0;
247
248 // Should complete with abort error if the service is deleted
249 // prior to a delete completion.
Bence Béky8f278af2018-08-10 15:14:27250 service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback());
[email protected]e0184cb2011-06-10 23:29:09251 EXPECT_EQ(0, delete_completion_count_);
252 service_.reset(); // kill it
253 EXPECT_EQ(1, delete_completion_count_);
254 EXPECT_EQ(net::ERR_ABORTED, delete_result_);
255 delete_completion_count_ = 0;
256
257 // Let any tasks lingering from the sudden deletion run and verify
258 // no other completion calls occur.
[email protected]f1edfb7e2013-09-13 16:45:17259 base::RunLoop().RunUntilIdle();
[email protected]e0184cb2011-06-10 23:29:09260 EXPECT_EQ(0, delete_completion_count_);
261}
262
[email protected]63ef85512014-06-05 14:21:26263TEST_F(AppCacheServiceImplTest, CheckAppCacheResponse) {
[email protected]20d06f62011-07-22 23:57:35264 // Check a non-existing manifest.
265 EXPECT_FALSE(IsGroupStored(kManifestUrl));
266 service_->CheckAppCacheResponse(kManifestUrl, 1, 1);
[email protected]f1edfb7e2013-09-13 16:45:17267 base::RunLoop().RunUntilIdle();
[email protected]20d06f62011-07-22 23:57:35268 EXPECT_EQ(0, CountPendingHelpers());
269 EXPECT_FALSE(IsGroupStored(kManifestUrl));
270 ResetStorage();
271
272 // Check a response that looks good.
273 // Nothing should be deleted.
274 SetupMockGroup();
275 EXPECT_TRUE(IsGroupStored(kManifestUrl));
276 SetupMockReader(true, true, true);
277 service_->CheckAppCacheResponse(kManifestUrl, kMockCacheId, kMockResponseId);
[email protected]f1edfb7e2013-09-13 16:45:17278 base::RunLoop().RunUntilIdle();
[email protected]20d06f62011-07-22 23:57:35279 EXPECT_EQ(0, CountPendingHelpers());
280 EXPECT_TRUE(IsGroupStored(kManifestUrl));
281 ResetStorage();
282
283 // Check a response for which there is no cache entry.
284 // The group should get deleted.
285 SetupMockGroup();
286 service_->CheckAppCacheResponse(kManifestUrl, kMockCacheId,
287 kMissingResponseId);
[email protected]f1edfb7e2013-09-13 16:45:17288 base::RunLoop().RunUntilIdle();
[email protected]20d06f62011-07-22 23:57:35289 EXPECT_EQ(0, CountPendingHelpers());
290 EXPECT_FALSE(IsGroupStored(kManifestUrl));
291 ResetStorage();
292
293 // Check a response for which there is no manifest entry in a newer version
294 // of the cache. Nothing should get deleted in this case.
295 SetupMockGroup();
296 service_->CheckAppCacheResponse(kManifestUrl, kMissingCacheId,
297 kMissingResponseId);
[email protected]f1edfb7e2013-09-13 16:45:17298 base::RunLoop().RunUntilIdle();
[email protected]20d06f62011-07-22 23:57:35299 EXPECT_EQ(0, CountPendingHelpers());
300 EXPECT_TRUE(IsGroupStored(kManifestUrl));
301 ResetStorage();
302
303 // Check a response with bad headers.
304 SetupMockGroup();
305 service_->CheckAppCacheResponse(kManifestUrl, kMockCacheId, kMockResponseId);
306 SetupMockReader(false, true, true);
[email protected]f1edfb7e2013-09-13 16:45:17307 base::RunLoop().RunUntilIdle();
[email protected]20d06f62011-07-22 23:57:35308 EXPECT_EQ(0, CountPendingHelpers());
309 EXPECT_FALSE(IsGroupStored(kManifestUrl));
310 ResetStorage();
311
312 // Check a response with bad data.
313 SetupMockGroup();
314 service_->CheckAppCacheResponse(kManifestUrl, kMockCacheId, kMockResponseId);
315 SetupMockReader(true, false, true);
[email protected]f1edfb7e2013-09-13 16:45:17316 base::RunLoop().RunUntilIdle();
[email protected]20d06f62011-07-22 23:57:35317 EXPECT_EQ(0, CountPendingHelpers());
318 EXPECT_FALSE(IsGroupStored(kManifestUrl));
319 ResetStorage();
320
321 // Check a response with truncated data.
322 SetupMockGroup();
323 service_->CheckAppCacheResponse(kManifestUrl, kMockCacheId, kMockResponseId);
324 SetupMockReader(true, true, false);
[email protected]f1edfb7e2013-09-13 16:45:17325 base::RunLoop().RunUntilIdle();
[email protected]20d06f62011-07-22 23:57:35326 EXPECT_EQ(0, CountPendingHelpers());
327 EXPECT_FALSE(IsGroupStored(kManifestUrl));
328 ResetStorage();
329
330 service_.reset(); // Clean up.
[email protected]f1edfb7e2013-09-13 16:45:17331 base::RunLoop().RunUntilIdle();
[email protected]20d06f62011-07-22 23:57:35332}
333
[email protected]15b44822014-02-04 00:57:56334// Just tests the backoff scheduling function, not the actual reinit function.
[email protected]63ef85512014-06-05 14:21:26335TEST_F(AppCacheServiceImplTest, ScheduleReinitialize) {
[email protected]15b44822014-02-04 00:57:56336 const base::TimeDelta kNoDelay;
337 const base::TimeDelta kOneSecond(base::TimeDelta::FromSeconds(1));
338 const base::TimeDelta k30Seconds(base::TimeDelta::FromSeconds(30));
339 const base::TimeDelta kOneHour(base::TimeDelta::FromHours(1));
340
341 // Do things get initialized as expected?
Ivan Kotenkov2c0d2bb32017-11-01 15:41:28342 std::unique_ptr<AppCacheServiceImpl> service(
343 new AppCacheServiceImpl(nullptr));
[email protected]15b44822014-02-04 00:57:56344 EXPECT_TRUE(service->last_reinit_time_.is_null());
345 EXPECT_FALSE(service->reinit_timer_.IsRunning());
346 EXPECT_EQ(kNoDelay, service->next_reinit_delay_);
347
348 // Do we see artifacts of the timer pending and such?
349 service->ScheduleReinitialize();
350 EXPECT_TRUE(service->reinit_timer_.IsRunning());
351 EXPECT_EQ(kNoDelay, service->reinit_timer_.GetCurrentDelay());
352 EXPECT_EQ(k30Seconds, service->next_reinit_delay_);
353
354 // Nothing should change if already scheduled
355 service->ScheduleReinitialize();
356 EXPECT_TRUE(service->reinit_timer_.IsRunning());
357 EXPECT_EQ(kNoDelay, service->reinit_timer_.GetCurrentDelay());
358 EXPECT_EQ(k30Seconds, service->next_reinit_delay_);
359
360 // Does the delay increase as expected?
361 service->reinit_timer_.Stop();
362 service->last_reinit_time_ = base::Time::Now() - kOneSecond;
363 service->ScheduleReinitialize();
364 EXPECT_TRUE(service->reinit_timer_.IsRunning());
365 EXPECT_EQ(k30Seconds, service->reinit_timer_.GetCurrentDelay());
366 EXPECT_EQ(k30Seconds + k30Seconds, service->next_reinit_delay_);
367
368 // Does the delay reset as expected?
369 service->reinit_timer_.Stop();
370 service->last_reinit_time_ = base::Time::Now() -
371 base::TimeDelta::FromHours(2);
372 service->ScheduleReinitialize();
373 EXPECT_TRUE(service->reinit_timer_.IsRunning());
374 EXPECT_EQ(kNoDelay, service->reinit_timer_.GetCurrentDelay());
375 EXPECT_EQ(k30Seconds, service->next_reinit_delay_);
376
377 // Does the delay max out as expected?
378 service->reinit_timer_.Stop();
379 service->last_reinit_time_ = base::Time::Now() - kOneSecond;
380 service->next_reinit_delay_ = kOneHour;
381 service->ScheduleReinitialize();
382 EXPECT_TRUE(service->reinit_timer_.IsRunning());
383 EXPECT_EQ(kOneHour, service->reinit_timer_.GetCurrentDelay());
384 EXPECT_EQ(kOneHour, service->next_reinit_delay_);
385
386 // Fine to delete while pending.
Ivan Kotenkov2c0d2bb32017-11-01 15:41:28387 service.reset(nullptr);
[email protected]15b44822014-02-04 00:57:56388}
389
390
391
[email protected]a507b822014-04-12 05:10:24392} // namespace content