Upstream version 7.35.144.0
[platform/framework/web/crosswalk.git] / src / webkit / browser / appcache / appcache_service_unittest.cc
1 // Copyright (c) 2012 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.
4
5 #include <string>
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/pickle.h"
10 #include "base/run_loop.h"
11 #include "net/base/completion_callback.h"
12 #include "net/base/io_buffer.h"
13 #include "net/http/http_response_headers.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "webkit/browser/appcache/appcache_response.h"
16 #include "webkit/browser/appcache/appcache_service.h"
17 #include "webkit/browser/appcache/mock_appcache_storage.h"
18
19
20 namespace appcache {
21 namespace {
22
23 const int64 kMockGroupId = 1;
24 const int64 kMockCacheId = 1;
25 const int64 kMockResponseId = 1;
26 const int64 kMissingCacheId = 5;
27 const int64 kMissingResponseId = 5;
28 const char kMockHeaders[] =
29     "HTTP/1.0 200 OK\0Content-Length: 5\0\0";
30 const char kMockBody[] = "Hello";
31 const int kMockBodySize = 5;
32
33 class MockResponseReader : public AppCacheResponseReader {
34  public:
35   MockResponseReader(int64 response_id,
36                      net::HttpResponseInfo* info, int info_size,
37                      const char* data, int data_size)
38       : AppCacheResponseReader(response_id, 0, NULL),
39         info_(info), info_size_(info_size),
40         data_(data), data_size_(data_size) {
41   }
42   virtual void ReadInfo(HttpResponseInfoIOBuffer* info_buf,
43                         const net::CompletionCallback& callback) OVERRIDE {
44     info_buffer_ = info_buf;
45     callback_ = callback;  // Cleared on completion.
46
47     int rv = info_.get() ? info_size_ : net::ERR_FAILED;
48     info_buffer_->http_info.reset(info_.release());
49     info_buffer_->response_data_size = data_size_;
50     ScheduleUserCallback(rv);
51   }
52   virtual void ReadData(net::IOBuffer* buf, int buf_len,
53                         const net::CompletionCallback& callback) OVERRIDE {
54     buffer_ = buf;
55     buffer_len_ = buf_len;
56     callback_ = callback;  // Cleared on completion.
57
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) {
70     base::MessageLoop::current()->PostTask(FROM_HERE,
71         base::Bind(&MockResponseReader::InvokeUserCompletionCallback,
72                    weak_factory_.GetWeakPtr(), result));
73   }
74
75   scoped_ptr<net::HttpResponseInfo> info_;
76   int info_size_;
77   const char* data_;
78   int data_size_;
79 };
80
81 }  // namespace
82
83
84 class AppCacheServiceTest : public testing::Test {
85  public:
86   AppCacheServiceTest()
87       : kOrigin("http://hello/"),
88         kManifestUrl(kOrigin.Resolve("manifest")),
89         service_(new AppCacheService(NULL)),
90         delete_result_(net::OK), delete_completion_count_(0),
91         deletion_callback_(
92             base::Bind(&AppCacheServiceTest::OnDeleteAppCachesComplete,
93                        base::Unretained(this))) {
94     // 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
107   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(
125         new AppCacheGroup(service_->storage(), kManifestUrl, kMockGroupId));
126     scoped_refptr<AppCache> cache(
127         new AppCache(service_->storage(), kMockCacheId));
128     cache->AddEntry(
129         kManifestUrl,
130         AppCacheEntry(AppCacheEntry::MANIFEST, kMockResponseId,
131                       kMockInfoSize + kMockBodySize));
132     cache->set_complete(true);
133     group->AddCache(cache.get());
134     mock_storage()->AddStoredGroup(group.get());
135     mock_storage()->AddStoredCache(cache.get());
136   }
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
171   const GURL kOrigin;
172   const GURL kManifestUrl;
173
174   scoped_ptr<AppCacheService> service_;
175   int delete_result_;
176   int delete_completion_count_;
177   net::CompletionCallback deletion_callback_;
178
179  private:
180   base::MessageLoop message_loop_;
181 };
182
183 TEST_F(AppCacheServiceTest, DeleteAppCachesForOrigin) {
184   // Without giving mock storage simiulated info, should fail.
185   service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback_);
186   EXPECT_EQ(0, delete_completion_count_);
187   base::RunLoop().RunUntilIdle();
188   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.
193   mock_storage()->SimulateGetAllInfo(new AppCacheInfoCollection);
194   service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback_);
195   EXPECT_EQ(0, delete_completion_count_);
196   base::RunLoop().RunUntilIdle();
197   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;
215   mock_storage()->SimulateGetAllInfo(info.get());
216   service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback_);
217   EXPECT_EQ(0, delete_completion_count_);
218   base::RunLoop().RunUntilIdle();
219   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;
225   mock_storage()->SimulateGetAllInfo(info.get());
226   mock_storage()->SimulateMakeGroupObsoleteFailure();
227   service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback_);
228   EXPECT_EQ(0, delete_completion_count_);
229   base::RunLoop().RunUntilIdle();
230   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.
236   service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback_);
237   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.
245   base::RunLoop().RunUntilIdle();
246   EXPECT_EQ(0, delete_completion_count_);
247 }
248
249 TEST_F(AppCacheServiceTest, CheckAppCacheResponse) {
250   // Check a non-existing manifest.
251   EXPECT_FALSE(IsGroupStored(kManifestUrl));
252   service_->CheckAppCacheResponse(kManifestUrl, 1, 1);
253   base::RunLoop().RunUntilIdle();
254   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);
264   base::RunLoop().RunUntilIdle();
265   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);
274   base::RunLoop().RunUntilIdle();
275   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);
284   base::RunLoop().RunUntilIdle();
285   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);
293   base::RunLoop().RunUntilIdle();
294   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);
302   base::RunLoop().RunUntilIdle();
303   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);
311   base::RunLoop().RunUntilIdle();
312   EXPECT_EQ(0, CountPendingHelpers());
313   EXPECT_FALSE(IsGroupStored(kManifestUrl));
314   ResetStorage();
315
316   service_.reset();  // Clean up.
317   base::RunLoop().RunUntilIdle();
318 }
319
320 // Just tests the backoff scheduling function, not the actual reinit function.
321 TEST_F(AppCacheServiceTest, ScheduleReinitialize) {
322   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?
328   scoped_ptr<AppCacheService> service(new AppCacheService(NULL));
329   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
377 }  // namespace appcache