Update V8 to version 4.6.55.
[chromium-blink-merge.git] / content / browser / appcache / appcache_service_unittest.cc
blob62e6a4dbe0b216f93d48f7f94e592788fd841a6e
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.
5 #include <string>
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/location.h"
10 #include "base/pickle.h"
11 #include "base/run_loop.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "content/browser/appcache/appcache_response.h"
15 #include "content/browser/appcache/appcache_service_impl.h"
16 #include "content/browser/appcache/mock_appcache_storage.h"
17 #include "net/base/completion_callback.h"
18 #include "net/base/io_buffer.h"
19 #include "net/http/http_response_headers.h"
20 #include "testing/gtest/include/gtest/gtest.h"
22 namespace content {
23 namespace {
25 const int64 kMockGroupId = 1;
26 const int64 kMockCacheId = 1;
27 const int64 kMockResponseId = 1;
28 const int64 kMissingCacheId = 5;
29 const int64 kMissingResponseId = 5;
30 const char kMockHeaders[] =
31 "HTTP/1.0 200 OK\0Content-Length: 5\0\0";
32 const char kMockBody[] = "Hello";
33 const int kMockBodySize = 5;
35 class MockResponseReader : public AppCacheResponseReader {
36 public:
37 MockResponseReader(int64 response_id,
38 net::HttpResponseInfo* info, int info_size,
39 const char* data, int data_size)
40 : AppCacheResponseReader(response_id, 0, NULL),
41 info_(info), info_size_(info_size),
42 data_(data), data_size_(data_size) {
44 void ReadInfo(HttpResponseInfoIOBuffer* info_buf,
45 const net::CompletionCallback& callback) override {
46 info_buffer_ = info_buf;
47 callback_ = callback; // Cleared on completion.
49 int rv = info_.get() ? info_size_ : net::ERR_FAILED;
50 info_buffer_->http_info.reset(info_.release());
51 info_buffer_->response_data_size = data_size_;
52 ScheduleUserCallback(rv);
54 void ReadData(net::IOBuffer* buf,
55 int buf_len,
56 const net::CompletionCallback& callback) override {
57 buffer_ = buf;
58 buffer_len_ = buf_len;
59 callback_ = callback; // Cleared on completion.
61 if (!data_) {
62 ScheduleUserCallback(net::ERR_CACHE_READ_FAILURE);
63 return;
65 DCHECK(buf_len >= data_size_);
66 memcpy(buf->data(), data_, data_size_);
67 ScheduleUserCallback(data_size_);
68 data_size_ = 0;
71 private:
72 void ScheduleUserCallback(int result) {
73 base::ThreadTaskRunnerHandle::Get()->PostTask(
74 FROM_HERE, base::Bind(&MockResponseReader::InvokeUserCompletionCallback,
75 weak_factory_.GetWeakPtr(), result));
78 scoped_ptr<net::HttpResponseInfo> info_;
79 int info_size_;
80 const char* data_;
81 int data_size_;
84 } // namespace
87 class AppCacheServiceImplTest : public testing::Test {
88 public:
89 AppCacheServiceImplTest()
90 : kOrigin("http://hello/"),
91 kManifestUrl(kOrigin.Resolve("manifest")),
92 service_(new AppCacheServiceImpl(NULL)),
93 delete_result_(net::OK), delete_completion_count_(0),
94 deletion_callback_(
95 base::Bind(&AppCacheServiceImplTest::OnDeleteAppCachesComplete,
96 base::Unretained(this))) {
97 // Setup to use mock storage.
98 service_->storage_.reset(new MockAppCacheStorage(service_.get()));
101 void OnDeleteAppCachesComplete(int result) {
102 delete_result_ = result;
103 ++delete_completion_count_;
106 MockAppCacheStorage* mock_storage() {
107 return static_cast<MockAppCacheStorage*>(service_->storage());
110 void ResetStorage() {
111 service_->storage_.reset(new MockAppCacheStorage(service_.get()));
114 bool IsGroupStored(const GURL& manifest_url) {
115 return mock_storage()->IsGroupForManifestStored(manifest_url);
118 int CountPendingHelpers() {
119 return service_->pending_helpers_.size();
122 void SetupMockGroup() {
123 scoped_ptr<net::HttpResponseInfo> info(MakeMockResponseInfo());
124 const int kMockInfoSize = GetResponseInfoSize(info.get());
126 // Create a mock group, cache, and entry and stuff them into mock storage.
127 scoped_refptr<AppCacheGroup> group(
128 new AppCacheGroup(service_->storage(), kManifestUrl, kMockGroupId));
129 scoped_refptr<AppCache> cache(
130 new AppCache(service_->storage(), kMockCacheId));
131 cache->AddEntry(
132 kManifestUrl,
133 AppCacheEntry(AppCacheEntry::MANIFEST, kMockResponseId,
134 kMockInfoSize + kMockBodySize));
135 cache->set_complete(true);
136 group->AddCache(cache.get());
137 mock_storage()->AddStoredGroup(group.get());
138 mock_storage()->AddStoredCache(cache.get());
141 void SetupMockReader(
142 bool valid_info, bool valid_data, bool valid_size) {
143 net::HttpResponseInfo* info = valid_info ? MakeMockResponseInfo() : NULL;
144 int info_size = info ? GetResponseInfoSize(info) : 0;
145 const char* data = valid_data ? kMockBody : NULL;
146 int data_size = valid_size ? kMockBodySize : 3;
147 mock_storage()->SimulateResponseReader(
148 new MockResponseReader(kMockResponseId, info, info_size,
149 data, data_size));
152 net::HttpResponseInfo* MakeMockResponseInfo() {
153 net::HttpResponseInfo* info = new net::HttpResponseInfo;
154 info->request_time = base::Time::Now();
155 info->response_time = base::Time::Now();
156 info->was_cached = false;
157 info->headers = new net::HttpResponseHeaders(
158 std::string(kMockHeaders, arraysize(kMockHeaders)));
159 return info;
162 int GetResponseInfoSize(const net::HttpResponseInfo* info) {
163 base::Pickle pickle;
164 return PickleResponseInfo(&pickle, info);
167 int PickleResponseInfo(base::Pickle* pickle,
168 const net::HttpResponseInfo* info) {
169 const bool kSkipTransientHeaders = true;
170 const bool kTruncated = false;
171 info->Persist(pickle, kSkipTransientHeaders, kTruncated);
172 return pickle->size();
175 const GURL kOrigin;
176 const GURL kManifestUrl;
178 scoped_ptr<AppCacheServiceImpl> service_;
179 int delete_result_;
180 int delete_completion_count_;
181 net::CompletionCallback deletion_callback_;
183 private:
184 base::MessageLoop message_loop_;
187 TEST_F(AppCacheServiceImplTest, DeleteAppCachesForOrigin) {
188 // Without giving mock storage simiulated info, should fail.
189 service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback_);
190 EXPECT_EQ(0, delete_completion_count_);
191 base::RunLoop().RunUntilIdle();
192 EXPECT_EQ(1, delete_completion_count_);
193 EXPECT_EQ(net::ERR_FAILED, delete_result_);
194 delete_completion_count_ = 0;
196 // Should succeed given an empty info collection.
197 mock_storage()->SimulateGetAllInfo(new content::AppCacheInfoCollection);
198 service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback_);
199 EXPECT_EQ(0, delete_completion_count_);
200 base::RunLoop().RunUntilIdle();
201 EXPECT_EQ(1, delete_completion_count_);
202 EXPECT_EQ(net::OK, delete_result_);
203 delete_completion_count_ = 0;
205 scoped_refptr<AppCacheInfoCollection> info(new AppCacheInfoCollection);
207 // Should succeed given a non-empty info collection.
208 AppCacheInfo mock_manifest_1;
209 AppCacheInfo mock_manifest_2;
210 AppCacheInfo mock_manifest_3;
211 mock_manifest_1.manifest_url = kOrigin.Resolve("manifest1");
212 mock_manifest_2.manifest_url = kOrigin.Resolve("manifest2");
213 mock_manifest_3.manifest_url = kOrigin.Resolve("manifest3");
214 AppCacheInfoVector info_vector;
215 info_vector.push_back(mock_manifest_1);
216 info_vector.push_back(mock_manifest_2);
217 info_vector.push_back(mock_manifest_3);
218 info->infos_by_origin[kOrigin] = info_vector;
219 mock_storage()->SimulateGetAllInfo(info.get());
220 service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback_);
221 EXPECT_EQ(0, delete_completion_count_);
222 base::RunLoop().RunUntilIdle();
223 EXPECT_EQ(1, delete_completion_count_);
224 EXPECT_EQ(net::OK, delete_result_);
225 delete_completion_count_ = 0;
227 // Should fail if storage fails to delete.
228 info->infos_by_origin[kOrigin] = info_vector;
229 mock_storage()->SimulateGetAllInfo(info.get());
230 mock_storage()->SimulateMakeGroupObsoleteFailure();
231 service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback_);
232 EXPECT_EQ(0, delete_completion_count_);
233 base::RunLoop().RunUntilIdle();
234 EXPECT_EQ(1, delete_completion_count_);
235 EXPECT_EQ(net::ERR_FAILED, delete_result_);
236 delete_completion_count_ = 0;
238 // Should complete with abort error if the service is deleted
239 // prior to a delete completion.
240 service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback_);
241 EXPECT_EQ(0, delete_completion_count_);
242 service_.reset(); // kill it
243 EXPECT_EQ(1, delete_completion_count_);
244 EXPECT_EQ(net::ERR_ABORTED, delete_result_);
245 delete_completion_count_ = 0;
247 // Let any tasks lingering from the sudden deletion run and verify
248 // no other completion calls occur.
249 base::RunLoop().RunUntilIdle();
250 EXPECT_EQ(0, delete_completion_count_);
253 TEST_F(AppCacheServiceImplTest, CheckAppCacheResponse) {
254 // Check a non-existing manifest.
255 EXPECT_FALSE(IsGroupStored(kManifestUrl));
256 service_->CheckAppCacheResponse(kManifestUrl, 1, 1);
257 base::RunLoop().RunUntilIdle();
258 EXPECT_EQ(0, CountPendingHelpers());
259 EXPECT_FALSE(IsGroupStored(kManifestUrl));
260 ResetStorage();
262 // Check a response that looks good.
263 // Nothing should be deleted.
264 SetupMockGroup();
265 EXPECT_TRUE(IsGroupStored(kManifestUrl));
266 SetupMockReader(true, true, true);
267 service_->CheckAppCacheResponse(kManifestUrl, kMockCacheId, kMockResponseId);
268 base::RunLoop().RunUntilIdle();
269 EXPECT_EQ(0, CountPendingHelpers());
270 EXPECT_TRUE(IsGroupStored(kManifestUrl));
271 ResetStorage();
273 // Check a response for which there is no cache entry.
274 // The group should get deleted.
275 SetupMockGroup();
276 service_->CheckAppCacheResponse(kManifestUrl, kMockCacheId,
277 kMissingResponseId);
278 base::RunLoop().RunUntilIdle();
279 EXPECT_EQ(0, CountPendingHelpers());
280 EXPECT_FALSE(IsGroupStored(kManifestUrl));
281 ResetStorage();
283 // Check a response for which there is no manifest entry in a newer version
284 // of the cache. Nothing should get deleted in this case.
285 SetupMockGroup();
286 service_->CheckAppCacheResponse(kManifestUrl, kMissingCacheId,
287 kMissingResponseId);
288 base::RunLoop().RunUntilIdle();
289 EXPECT_EQ(0, CountPendingHelpers());
290 EXPECT_TRUE(IsGroupStored(kManifestUrl));
291 ResetStorage();
293 // Check a response with bad headers.
294 SetupMockGroup();
295 service_->CheckAppCacheResponse(kManifestUrl, kMockCacheId, kMockResponseId);
296 SetupMockReader(false, true, true);
297 base::RunLoop().RunUntilIdle();
298 EXPECT_EQ(0, CountPendingHelpers());
299 EXPECT_FALSE(IsGroupStored(kManifestUrl));
300 ResetStorage();
302 // Check a response with bad data.
303 SetupMockGroup();
304 service_->CheckAppCacheResponse(kManifestUrl, kMockCacheId, kMockResponseId);
305 SetupMockReader(true, false, true);
306 base::RunLoop().RunUntilIdle();
307 EXPECT_EQ(0, CountPendingHelpers());
308 EXPECT_FALSE(IsGroupStored(kManifestUrl));
309 ResetStorage();
311 // Check a response with truncated data.
312 SetupMockGroup();
313 service_->CheckAppCacheResponse(kManifestUrl, kMockCacheId, kMockResponseId);
314 SetupMockReader(true, true, false);
315 base::RunLoop().RunUntilIdle();
316 EXPECT_EQ(0, CountPendingHelpers());
317 EXPECT_FALSE(IsGroupStored(kManifestUrl));
318 ResetStorage();
320 service_.reset(); // Clean up.
321 base::RunLoop().RunUntilIdle();
324 // Just tests the backoff scheduling function, not the actual reinit function.
325 TEST_F(AppCacheServiceImplTest, ScheduleReinitialize) {
326 const base::TimeDelta kNoDelay;
327 const base::TimeDelta kOneSecond(base::TimeDelta::FromSeconds(1));
328 const base::TimeDelta k30Seconds(base::TimeDelta::FromSeconds(30));
329 const base::TimeDelta kOneHour(base::TimeDelta::FromHours(1));
331 // Do things get initialized as expected?
332 scoped_ptr<AppCacheServiceImpl> service(new AppCacheServiceImpl(NULL));
333 EXPECT_TRUE(service->last_reinit_time_.is_null());
334 EXPECT_FALSE(service->reinit_timer_.IsRunning());
335 EXPECT_EQ(kNoDelay, service->next_reinit_delay_);
337 // Do we see artifacts of the timer pending and such?
338 service->ScheduleReinitialize();
339 EXPECT_TRUE(service->reinit_timer_.IsRunning());
340 EXPECT_EQ(kNoDelay, service->reinit_timer_.GetCurrentDelay());
341 EXPECT_EQ(k30Seconds, service->next_reinit_delay_);
343 // Nothing should change if already scheduled
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_);
349 // Does the delay increase as expected?
350 service->reinit_timer_.Stop();
351 service->last_reinit_time_ = base::Time::Now() - kOneSecond;
352 service->ScheduleReinitialize();
353 EXPECT_TRUE(service->reinit_timer_.IsRunning());
354 EXPECT_EQ(k30Seconds, service->reinit_timer_.GetCurrentDelay());
355 EXPECT_EQ(k30Seconds + k30Seconds, service->next_reinit_delay_);
357 // Does the delay reset as expected?
358 service->reinit_timer_.Stop();
359 service->last_reinit_time_ = base::Time::Now() -
360 base::TimeDelta::FromHours(2);
361 service->ScheduleReinitialize();
362 EXPECT_TRUE(service->reinit_timer_.IsRunning());
363 EXPECT_EQ(kNoDelay, service->reinit_timer_.GetCurrentDelay());
364 EXPECT_EQ(k30Seconds, service->next_reinit_delay_);
366 // Does the delay max out as expected?
367 service->reinit_timer_.Stop();
368 service->last_reinit_time_ = base::Time::Now() - kOneSecond;
369 service->next_reinit_delay_ = kOneHour;
370 service->ScheduleReinitialize();
371 EXPECT_TRUE(service->reinit_timer_.IsRunning());
372 EXPECT_EQ(kOneHour, service->reinit_timer_.GetCurrentDelay());
373 EXPECT_EQ(kOneHour, service->next_reinit_delay_);
375 // Fine to delete while pending.
376 service.reset(NULL);
381 } // namespace content