Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / content / browser / appcache / appcache_service_unittest.cc
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.
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 "content/browser/appcache/mock_appcache_storage.h"
12 #include "net/base/completion_callback.h"
13 #include "net/base/io_buffer.h"
14 #include "net/http/http_response_headers.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "webkit/browser/appcache/appcache_response.h"
17 #include "webkit/browser/appcache/appcache_service.h"
18
19 using appcache::AppCache;
20 using appcache::AppCacheEntry;
21 using appcache::AppCacheGroup;
22 using appcache::AppCacheInfo;
23 using appcache::AppCacheInfoCollection;
24 using appcache::AppCacheInfoVector;
25 using appcache::AppCacheResponseReader;
26 using appcache::AppCacheService;
27 using appcache::HttpResponseInfoIOBuffer;
28
29 namespace content {
30 namespace {
31
32 const int64 kMockGroupId = 1;
33 const int64 kMockCacheId = 1;
34 const int64 kMockResponseId = 1;
35 const int64 kMissingCacheId = 5;
36 const int64 kMissingResponseId = 5;
37 const char kMockHeaders[] =
38     "HTTP/1.0 200 OK\0Content-Length: 5\0\0";
39 const char kMockBody[] = "Hello";
40 const int kMockBodySize = 5;
41
42 class MockResponseReader : public AppCacheResponseReader {
43  public:
44   MockResponseReader(int64 response_id,
45                      net::HttpResponseInfo* info, int info_size,
46                      const char* data, int data_size)
47       : AppCacheResponseReader(response_id, 0, NULL),
48         info_(info), info_size_(info_size),
49         data_(data), data_size_(data_size) {
50   }
51   virtual void ReadInfo(HttpResponseInfoIOBuffer* info_buf,
52                         const net::CompletionCallback& callback) OVERRIDE {
53     info_buffer_ = info_buf;
54     callback_ = callback;  // Cleared on completion.
55
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   }
61   virtual void ReadData(net::IOBuffer* buf, int buf_len,
62                         const net::CompletionCallback& callback) OVERRIDE {
63     buffer_ = buf;
64     buffer_len_ = buf_len;
65     callback_ = callback;  // Cleared on completion.
66
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) {
79     base::MessageLoop::current()->PostTask(FROM_HERE,
80         base::Bind(&MockResponseReader::InvokeUserCompletionCallback,
81                    weak_factory_.GetWeakPtr(), result));
82   }
83
84   scoped_ptr<net::HttpResponseInfo> info_;
85   int info_size_;
86   const char* data_;
87   int data_size_;
88 };
89
90 }  // namespace
91
92
93 class AppCacheServiceTest : public testing::Test {
94  public:
95   AppCacheServiceTest()
96       : kOrigin("http://hello/"),
97         kManifestUrl(kOrigin.Resolve("manifest")),
98         service_(new AppCacheService(NULL)),
99         delete_result_(net::OK), delete_completion_count_(0),
100         deletion_callback_(
101             base::Bind(&AppCacheServiceTest::OnDeleteAppCachesComplete,
102                        base::Unretained(this))) {
103     // 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
116   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(
134         new AppCacheGroup(service_->storage(), kManifestUrl, kMockGroupId));
135     scoped_refptr<AppCache> cache(
136         new AppCache(service_->storage(), kMockCacheId));
137     cache->AddEntry(
138         kManifestUrl,
139         AppCacheEntry(AppCacheEntry::MANIFEST, kMockResponseId,
140                       kMockInfoSize + kMockBodySize));
141     cache->set_complete(true);
142     group->AddCache(cache.get());
143     mock_storage()->AddStoredGroup(group.get());
144     mock_storage()->AddStoredCache(cache.get());
145   }
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) {
169     Pickle pickle;
170     return PickleResponseInfo(&pickle, info);
171   }
172
173   int PickleResponseInfo(Pickle* pickle, const net::HttpResponseInfo* info) {
174     const bool kSkipTransientHeaders = true;
175     const bool kTruncated = false;
176     info->Persist(pickle, kSkipTransientHeaders, kTruncated);
177     return pickle->size();
178   }
179
180   const GURL kOrigin;
181   const GURL kManifestUrl;
182
183   scoped_ptr<AppCacheService> service_;
184   int delete_result_;
185   int delete_completion_count_;
186   net::CompletionCallback deletion_callback_;
187
188  private:
189   base::MessageLoop message_loop_;
190 };
191
192 TEST_F(AppCacheServiceTest, DeleteAppCachesForOrigin) {
193   // Without giving mock storage simiulated info, should fail.
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::ERR_FAILED, delete_result_);
199   delete_completion_count_ = 0;
200
201   // Should succeed given an empty info collection.
202   mock_storage()->SimulateGetAllInfo(new AppCacheInfoCollection);
203   service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback_);
204   EXPECT_EQ(0, delete_completion_count_);
205   base::RunLoop().RunUntilIdle();
206   EXPECT_EQ(1, delete_completion_count_);
207   EXPECT_EQ(net::OK, delete_result_);
208   delete_completion_count_ = 0;
209
210   scoped_refptr<AppCacheInfoCollection> info(new AppCacheInfoCollection);
211
212   // Should succeed given a non-empty info collection.
213   AppCacheInfo mock_manifest_1;
214   AppCacheInfo mock_manifest_2;
215   AppCacheInfo mock_manifest_3;
216   mock_manifest_1.manifest_url = kOrigin.Resolve("manifest1");
217   mock_manifest_2.manifest_url = kOrigin.Resolve("manifest2");
218   mock_manifest_3.manifest_url = kOrigin.Resolve("manifest3");
219   AppCacheInfoVector info_vector;
220   info_vector.push_back(mock_manifest_1);
221   info_vector.push_back(mock_manifest_2);
222   info_vector.push_back(mock_manifest_3);
223   info->infos_by_origin[kOrigin] = info_vector;
224   mock_storage()->SimulateGetAllInfo(info.get());
225   service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback_);
226   EXPECT_EQ(0, delete_completion_count_);
227   base::RunLoop().RunUntilIdle();
228   EXPECT_EQ(1, delete_completion_count_);
229   EXPECT_EQ(net::OK, delete_result_);
230   delete_completion_count_ = 0;
231
232   // Should fail if storage fails to delete.
233   info->infos_by_origin[kOrigin] = info_vector;
234   mock_storage()->SimulateGetAllInfo(info.get());
235   mock_storage()->SimulateMakeGroupObsoleteFailure();
236   service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback_);
237   EXPECT_EQ(0, delete_completion_count_);
238   base::RunLoop().RunUntilIdle();
239   EXPECT_EQ(1, delete_completion_count_);
240   EXPECT_EQ(net::ERR_FAILED, delete_result_);
241   delete_completion_count_ = 0;
242
243   // Should complete with abort error if the service is deleted
244   // prior to a delete completion.
245   service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback_);
246   EXPECT_EQ(0, delete_completion_count_);
247   service_.reset();  // kill it
248   EXPECT_EQ(1, delete_completion_count_);
249   EXPECT_EQ(net::ERR_ABORTED, delete_result_);
250   delete_completion_count_ = 0;
251
252   // Let any tasks lingering from the sudden deletion run and verify
253   // no other completion calls occur.
254   base::RunLoop().RunUntilIdle();
255   EXPECT_EQ(0, delete_completion_count_);
256 }
257
258 TEST_F(AppCacheServiceTest, CheckAppCacheResponse) {
259   // Check a non-existing manifest.
260   EXPECT_FALSE(IsGroupStored(kManifestUrl));
261   service_->CheckAppCacheResponse(kManifestUrl, 1, 1);
262   base::RunLoop().RunUntilIdle();
263   EXPECT_EQ(0, CountPendingHelpers());
264   EXPECT_FALSE(IsGroupStored(kManifestUrl));
265   ResetStorage();
266
267   // Check a response that looks good.
268   // Nothing should be deleted.
269   SetupMockGroup();
270   EXPECT_TRUE(IsGroupStored(kManifestUrl));
271   SetupMockReader(true, true, true);
272   service_->CheckAppCacheResponse(kManifestUrl, kMockCacheId, kMockResponseId);
273   base::RunLoop().RunUntilIdle();
274   EXPECT_EQ(0, CountPendingHelpers());
275   EXPECT_TRUE(IsGroupStored(kManifestUrl));
276   ResetStorage();
277
278   // Check a response for which there is no cache entry.
279   // The group should get deleted.
280   SetupMockGroup();
281   service_->CheckAppCacheResponse(kManifestUrl, kMockCacheId,
282                                   kMissingResponseId);
283   base::RunLoop().RunUntilIdle();
284   EXPECT_EQ(0, CountPendingHelpers());
285   EXPECT_FALSE(IsGroupStored(kManifestUrl));
286   ResetStorage();
287
288   // Check a response for which there is no manifest entry in a newer version
289   // of the cache. Nothing should get deleted in this case.
290   SetupMockGroup();
291   service_->CheckAppCacheResponse(kManifestUrl, kMissingCacheId,
292                                   kMissingResponseId);
293   base::RunLoop().RunUntilIdle();
294   EXPECT_EQ(0, CountPendingHelpers());
295   EXPECT_TRUE(IsGroupStored(kManifestUrl));
296   ResetStorage();
297
298   // Check a response with bad headers.
299   SetupMockGroup();
300   service_->CheckAppCacheResponse(kManifestUrl, kMockCacheId, kMockResponseId);
301   SetupMockReader(false, true, true);
302   base::RunLoop().RunUntilIdle();
303   EXPECT_EQ(0, CountPendingHelpers());
304   EXPECT_FALSE(IsGroupStored(kManifestUrl));
305   ResetStorage();
306
307   // Check a response with bad data.
308   SetupMockGroup();
309   service_->CheckAppCacheResponse(kManifestUrl, kMockCacheId, kMockResponseId);
310   SetupMockReader(true, false, true);
311   base::RunLoop().RunUntilIdle();
312   EXPECT_EQ(0, CountPendingHelpers());
313   EXPECT_FALSE(IsGroupStored(kManifestUrl));
314   ResetStorage();
315
316   // Check a response with truncated data.
317   SetupMockGroup();
318   service_->CheckAppCacheResponse(kManifestUrl, kMockCacheId, kMockResponseId);
319   SetupMockReader(true, true, false);
320   base::RunLoop().RunUntilIdle();
321   EXPECT_EQ(0, CountPendingHelpers());
322   EXPECT_FALSE(IsGroupStored(kManifestUrl));
323   ResetStorage();
324
325   service_.reset();  // Clean up.
326   base::RunLoop().RunUntilIdle();
327 }
328
329 // Just tests the backoff scheduling function, not the actual reinit function.
330 TEST_F(AppCacheServiceTest, ScheduleReinitialize) {
331   const base::TimeDelta kNoDelay;
332   const base::TimeDelta kOneSecond(base::TimeDelta::FromSeconds(1));
333   const base::TimeDelta k30Seconds(base::TimeDelta::FromSeconds(30));
334   const base::TimeDelta kOneHour(base::TimeDelta::FromHours(1));
335
336   // Do things get initialized as expected?
337   scoped_ptr<AppCacheService> service(new AppCacheService(NULL));
338   EXPECT_TRUE(service->last_reinit_time_.is_null());
339   EXPECT_FALSE(service->reinit_timer_.IsRunning());
340   EXPECT_EQ(kNoDelay, service->next_reinit_delay_);
341
342   // Do we see artifacts of the timer pending and such?
343   service->ScheduleReinitialize();
344   EXPECT_TRUE(service->reinit_timer_.IsRunning());
345   EXPECT_EQ(kNoDelay, service->reinit_timer_.GetCurrentDelay());
346   EXPECT_EQ(k30Seconds, service->next_reinit_delay_);
347
348   // Nothing should change if already scheduled
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   // Does the delay increase as expected?
355   service->reinit_timer_.Stop();
356   service->last_reinit_time_ = base::Time::Now() - kOneSecond;
357   service->ScheduleReinitialize();
358   EXPECT_TRUE(service->reinit_timer_.IsRunning());
359   EXPECT_EQ(k30Seconds, service->reinit_timer_.GetCurrentDelay());
360   EXPECT_EQ(k30Seconds + k30Seconds, service->next_reinit_delay_);
361
362   // Does the delay reset as expected?
363   service->reinit_timer_.Stop();
364   service->last_reinit_time_ = base::Time::Now() -
365                                base::TimeDelta::FromHours(2);
366   service->ScheduleReinitialize();
367   EXPECT_TRUE(service->reinit_timer_.IsRunning());
368   EXPECT_EQ(kNoDelay, service->reinit_timer_.GetCurrentDelay());
369   EXPECT_EQ(k30Seconds, service->next_reinit_delay_);
370
371   // Does the delay max out as expected?
372   service->reinit_timer_.Stop();
373   service->last_reinit_time_ = base::Time::Now() - kOneSecond;
374   service->next_reinit_delay_ = kOneHour;
375   service->ScheduleReinitialize();
376   EXPECT_TRUE(service->reinit_timer_.IsRunning());
377   EXPECT_EQ(kOneHour, service->reinit_timer_.GetCurrentDelay());
378   EXPECT_EQ(kOneHour, service->next_reinit_delay_);
379
380   // Fine to delete while pending.
381   service.reset(NULL);
382 }
383
384
385
386 }  // namespace content