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