OLD | NEW |
| (Empty) |
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 "content/browser/service_worker/service_worker_cache.h" | |
6 | |
7 #include "base/files/file_path.h" | |
8 #include "base/files/scoped_temp_dir.h" | |
9 #include "base/message_loop/message_loop_proxy.h" | |
10 #include "base/run_loop.h" | |
11 #include "content/browser/fileapi/chrome_blob_storage_context.h" | |
12 #include "content/browser/fileapi/mock_url_request_delegate.h" | |
13 #include "content/browser/quota/mock_quota_manager_proxy.h" | |
14 #include "content/common/service_worker/service_worker_types.h" | |
15 #include "content/public/browser/browser_thread.h" | |
16 #include "content/public/common/referrer.h" | |
17 #include "content/public/test/test_browser_context.h" | |
18 #include "content/public/test/test_browser_thread_bundle.h" | |
19 #include "net/url_request/url_request_context.h" | |
20 #include "net/url_request/url_request_context_getter.h" | |
21 #include "net/url_request/url_request_job_factory_impl.h" | |
22 #include "storage/browser/blob/blob_data_builder.h" | |
23 #include "storage/browser/blob/blob_data_handle.h" | |
24 #include "storage/browser/blob/blob_data_snapshot.h" | |
25 #include "storage/browser/blob/blob_storage_context.h" | |
26 #include "storage/browser/blob/blob_url_request_job_factory.h" | |
27 #include "storage/browser/quota/quota_manager_proxy.h" | |
28 #include "testing/gtest/include/gtest/gtest.h" | |
29 | |
30 namespace content { | |
31 | |
32 namespace { | |
33 const char kTestData[] = "Hello World"; | |
34 | |
35 // Returns a BlobProtocolHandler that uses |blob_storage_context|. Caller owns | |
36 // the memory. | |
37 storage::BlobProtocolHandler* CreateMockBlobProtocolHandler( | |
38 storage::BlobStorageContext* blob_storage_context) { | |
39 // The FileSystemContext and MessageLoopProxy are not actually used but a | |
40 // MessageLoopProxy is needed to avoid a DCHECK in BlobURLRequestJob ctor. | |
41 return new storage::BlobProtocolHandler( | |
42 blob_storage_context, NULL, base::MessageLoopProxy::current().get()); | |
43 } | |
44 | |
45 // A disk_cache::Backend wrapper that can delay operations. | |
46 class DelayableBackend : public disk_cache::Backend { | |
47 public: | |
48 DelayableBackend(scoped_ptr<disk_cache::Backend> backend) | |
49 : backend_(backend.Pass()), delay_open_(false) {} | |
50 | |
51 // disk_cache::Backend overrides | |
52 net::CacheType GetCacheType() const override { | |
53 return backend_->GetCacheType(); | |
54 } | |
55 int32 GetEntryCount() const override { return backend_->GetEntryCount(); } | |
56 int OpenEntry(const std::string& key, | |
57 disk_cache::Entry** entry, | |
58 const CompletionCallback& callback) override { | |
59 if (delay_open_) { | |
60 open_entry_callback_ = | |
61 base::Bind(&DelayableBackend::OpenEntryDelayedImpl, | |
62 base::Unretained(this), key, entry, callback); | |
63 return net::ERR_IO_PENDING; | |
64 } | |
65 | |
66 return backend_->OpenEntry(key, entry, callback); | |
67 } | |
68 int CreateEntry(const std::string& key, | |
69 disk_cache::Entry** entry, | |
70 const CompletionCallback& callback) override { | |
71 return backend_->CreateEntry(key, entry, callback); | |
72 } | |
73 int DoomEntry(const std::string& key, | |
74 const CompletionCallback& callback) override { | |
75 return backend_->DoomEntry(key, callback); | |
76 } | |
77 int DoomAllEntries(const CompletionCallback& callback) override { | |
78 return backend_->DoomAllEntries(callback); | |
79 } | |
80 int DoomEntriesBetween(base::Time initial_time, | |
81 base::Time end_time, | |
82 const CompletionCallback& callback) override { | |
83 return backend_->DoomEntriesBetween(initial_time, end_time, callback); | |
84 } | |
85 int DoomEntriesSince(base::Time initial_time, | |
86 const CompletionCallback& callback) override { | |
87 return backend_->DoomEntriesSince(initial_time, callback); | |
88 } | |
89 scoped_ptr<Iterator> CreateIterator() override { | |
90 return backend_->CreateIterator(); | |
91 } | |
92 void GetStats( | |
93 std::vector<std::pair<std::string, std::string>>* stats) override { | |
94 return backend_->GetStats(stats); | |
95 } | |
96 void OnExternalCacheHit(const std::string& key) override { | |
97 return backend_->OnExternalCacheHit(key); | |
98 } | |
99 | |
100 // Call to continue a delayed open. | |
101 void OpenEntryContinue() { | |
102 EXPECT_FALSE(open_entry_callback_.is_null()); | |
103 open_entry_callback_.Run(); | |
104 } | |
105 | |
106 void set_delay_open(bool value) { delay_open_ = value; } | |
107 | |
108 private: | |
109 void OpenEntryDelayedImpl(const std::string& key, | |
110 disk_cache::Entry** entry, | |
111 const CompletionCallback& callback) { | |
112 int rv = backend_->OpenEntry(key, entry, callback); | |
113 if (rv != net::ERR_IO_PENDING) | |
114 callback.Run(rv); | |
115 } | |
116 | |
117 scoped_ptr<disk_cache::Backend> backend_; | |
118 bool delay_open_; | |
119 base::Closure open_entry_callback_; | |
120 }; | |
121 | |
122 } // namespace | |
123 | |
124 // A ServiceWorkerCache that can optionally delay during backend creation. | |
125 class TestServiceWorkerCache : public ServiceWorkerCache { | |
126 public: | |
127 TestServiceWorkerCache( | |
128 const GURL& origin, | |
129 const base::FilePath& path, | |
130 net::URLRequestContext* request_context, | |
131 const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy, | |
132 base::WeakPtr<storage::BlobStorageContext> blob_context) | |
133 : ServiceWorkerCache(origin, | |
134 path, | |
135 request_context, | |
136 quota_manager_proxy, | |
137 blob_context), | |
138 delay_backend_creation_(false) {} | |
139 | |
140 void CreateBackend(const ErrorCallback& callback) override { | |
141 backend_creation_callback_ = callback; | |
142 if (delay_backend_creation_) | |
143 return; | |
144 ContinueCreateBackend(); | |
145 } | |
146 | |
147 void ContinueCreateBackend() { | |
148 ServiceWorkerCache::CreateBackend(backend_creation_callback_); | |
149 } | |
150 | |
151 void set_delay_backend_creation(bool delay) { | |
152 delay_backend_creation_ = delay; | |
153 } | |
154 | |
155 // Swap the existing backend with a delayable one. The backend must have been | |
156 // created before calling this. | |
157 DelayableBackend* UseDelayableBackend() { | |
158 EXPECT_TRUE(backend_); | |
159 DelayableBackend* delayable_backend = new DelayableBackend(backend_.Pass()); | |
160 backend_.reset(delayable_backend); | |
161 return delayable_backend; | |
162 } | |
163 | |
164 private: | |
165 ~TestServiceWorkerCache() override {} | |
166 | |
167 bool delay_backend_creation_; | |
168 ErrorCallback backend_creation_callback_; | |
169 | |
170 DISALLOW_COPY_AND_ASSIGN(TestServiceWorkerCache); | |
171 }; | |
172 | |
173 class ServiceWorkerCacheTest : public testing::Test { | |
174 public: | |
175 ServiceWorkerCacheTest() | |
176 : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP), | |
177 callback_error_(ServiceWorkerCache::ERROR_TYPE_OK), | |
178 callback_closed_(false) {} | |
179 | |
180 void SetUp() override { | |
181 ChromeBlobStorageContext* blob_storage_context = | |
182 ChromeBlobStorageContext::GetFor(&browser_context_); | |
183 // Wait for chrome_blob_storage_context to finish initializing. | |
184 base::RunLoop().RunUntilIdle(); | |
185 blob_storage_context_ = blob_storage_context->context(); | |
186 | |
187 quota_manager_proxy_ = new MockQuotaManagerProxy( | |
188 nullptr, base::MessageLoopProxy::current().get()); | |
189 | |
190 url_request_job_factory_.reset(new net::URLRequestJobFactoryImpl); | |
191 url_request_job_factory_->SetProtocolHandler( | |
192 "blob", CreateMockBlobProtocolHandler(blob_storage_context->context())); | |
193 | |
194 net::URLRequestContext* url_request_context = | |
195 browser_context_.GetRequestContext()->GetURLRequestContext(); | |
196 | |
197 url_request_context->set_job_factory(url_request_job_factory_.get()); | |
198 | |
199 CreateRequests(blob_storage_context); | |
200 | |
201 if (!MemoryOnly()) | |
202 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | |
203 base::FilePath path = MemoryOnly() ? base::FilePath() : temp_dir_.path(); | |
204 | |
205 cache_ = make_scoped_refptr(new TestServiceWorkerCache( | |
206 GURL("http://example.com"), path, url_request_context, | |
207 quota_manager_proxy_, blob_storage_context->context()->AsWeakPtr())); | |
208 } | |
209 | |
210 void TearDown() override { | |
211 quota_manager_proxy_->SimulateQuotaManagerDestroyed(); | |
212 base::RunLoop().RunUntilIdle(); | |
213 } | |
214 | |
215 void CreateRequests(ChromeBlobStorageContext* blob_storage_context) { | |
216 ServiceWorkerHeaderMap headers; | |
217 headers.insert(std::make_pair("a", "a")); | |
218 headers.insert(std::make_pair("b", "b")); | |
219 body_request_ = | |
220 ServiceWorkerFetchRequest(GURL("http://example.com/body.html"), "GET", | |
221 headers, Referrer(), false); | |
222 no_body_request_ = | |
223 ServiceWorkerFetchRequest(GURL("http://example.com/no_body.html"), | |
224 "GET", | |
225 headers, | |
226 Referrer(), | |
227 false); | |
228 | |
229 std::string expected_response; | |
230 for (int i = 0; i < 100; ++i) | |
231 expected_blob_data_ += kTestData; | |
232 | |
233 scoped_ptr<storage::BlobDataBuilder> blob_data( | |
234 new storage::BlobDataBuilder("blob-id:myblob")); | |
235 blob_data->AppendData(expected_blob_data_); | |
236 | |
237 blob_handle_ = | |
238 blob_storage_context->context()->AddFinishedBlob(blob_data.get()); | |
239 | |
240 body_response_ = | |
241 ServiceWorkerResponse(GURL("http://example.com/body.html"), | |
242 200, | |
243 "OK", | |
244 blink::WebServiceWorkerResponseTypeDefault, | |
245 headers, | |
246 blob_handle_->uuid(), | |
247 expected_blob_data_.size(), | |
248 GURL()); | |
249 | |
250 no_body_response_ = | |
251 ServiceWorkerResponse(GURL("http://example.com/no_body.html"), | |
252 200, | |
253 "OK", | |
254 blink::WebServiceWorkerResponseTypeDefault, | |
255 headers, | |
256 "", | |
257 0, | |
258 GURL()); | |
259 } | |
260 | |
261 scoped_ptr<ServiceWorkerFetchRequest> CopyFetchRequest( | |
262 const ServiceWorkerFetchRequest& request) { | |
263 return make_scoped_ptr(new ServiceWorkerFetchRequest(request.url, | |
264 request.method, | |
265 request.headers, | |
266 request.referrer, | |
267 request.is_reload)); | |
268 } | |
269 | |
270 scoped_ptr<ServiceWorkerResponse> CopyFetchResponse( | |
271 const ServiceWorkerResponse& response) { | |
272 scoped_ptr<ServiceWorkerResponse> sw_response( | |
273 new ServiceWorkerResponse(response.url, | |
274 response.status_code, | |
275 response.status_text, | |
276 response.response_type, | |
277 response.headers, | |
278 response.blob_uuid, | |
279 response.blob_size, | |
280 response.stream_url)); | |
281 return sw_response.Pass(); | |
282 } | |
283 | |
284 bool Put(const ServiceWorkerFetchRequest& request, | |
285 const ServiceWorkerResponse& response) { | |
286 scoped_ptr<base::RunLoop> loop(new base::RunLoop()); | |
287 | |
288 cache_->Put(CopyFetchRequest(request), | |
289 CopyFetchResponse(response), | |
290 base::Bind(&ServiceWorkerCacheTest::ResponseAndErrorCallback, | |
291 base::Unretained(this), | |
292 base::Unretained(loop.get()))); | |
293 // TODO(jkarlin): These functions should use base::RunLoop().RunUntilIdle() | |
294 // once the cache uses a passed in MessageLoopProxy instead of the CACHE | |
295 // thread. | |
296 loop->Run(); | |
297 | |
298 return callback_error_ == ServiceWorkerCache::ERROR_TYPE_OK; | |
299 } | |
300 | |
301 bool Match(const ServiceWorkerFetchRequest& request) { | |
302 scoped_ptr<base::RunLoop> loop(new base::RunLoop()); | |
303 | |
304 cache_->Match(CopyFetchRequest(request), | |
305 base::Bind(&ServiceWorkerCacheTest::ResponseAndErrorCallback, | |
306 base::Unretained(this), | |
307 base::Unretained(loop.get()))); | |
308 loop->Run(); | |
309 | |
310 return callback_error_ == ServiceWorkerCache::ERROR_TYPE_OK; | |
311 } | |
312 | |
313 bool Delete(const ServiceWorkerFetchRequest& request) { | |
314 scoped_ptr<base::RunLoop> loop(new base::RunLoop()); | |
315 | |
316 cache_->Delete(CopyFetchRequest(request), | |
317 base::Bind(&ServiceWorkerCacheTest::ErrorTypeCallback, | |
318 base::Unretained(this), | |
319 base::Unretained(loop.get()))); | |
320 loop->Run(); | |
321 | |
322 return callback_error_ == ServiceWorkerCache::ERROR_TYPE_OK; | |
323 } | |
324 | |
325 bool Keys() { | |
326 scoped_ptr<base::RunLoop> loop(new base::RunLoop()); | |
327 | |
328 cache_->Keys(base::Bind(&ServiceWorkerCacheTest::RequestsCallback, | |
329 base::Unretained(this), | |
330 base::Unretained(loop.get()))); | |
331 loop->Run(); | |
332 | |
333 return callback_error_ == ServiceWorkerCache::ERROR_TYPE_OK; | |
334 } | |
335 | |
336 bool Close() { | |
337 scoped_ptr<base::RunLoop> loop(new base::RunLoop()); | |
338 | |
339 cache_->Close(base::Bind(&ServiceWorkerCacheTest::CloseCallback, | |
340 base::Unretained(this), | |
341 base::Unretained(loop.get()))); | |
342 loop->Run(); | |
343 return callback_closed_; | |
344 } | |
345 | |
346 void RequestsCallback(base::RunLoop* run_loop, | |
347 ServiceWorkerCache::ErrorType error, | |
348 scoped_ptr<ServiceWorkerCache::Requests> requests) { | |
349 callback_error_ = error; | |
350 callback_strings_.clear(); | |
351 if (requests) { | |
352 for (size_t i = 0u; i < requests->size(); ++i) | |
353 callback_strings_.push_back(requests->at(i).url.spec()); | |
354 } | |
355 if (run_loop) | |
356 run_loop->Quit(); | |
357 } | |
358 | |
359 void ErrorTypeCallback(base::RunLoop* run_loop, | |
360 ServiceWorkerCache::ErrorType error) { | |
361 callback_error_ = error; | |
362 if (run_loop) | |
363 run_loop->Quit(); | |
364 } | |
365 | |
366 void ResponseAndErrorCallback( | |
367 base::RunLoop* run_loop, | |
368 ServiceWorkerCache::ErrorType error, | |
369 scoped_ptr<ServiceWorkerResponse> response, | |
370 scoped_ptr<storage::BlobDataHandle> body_handle) { | |
371 callback_error_ = error; | |
372 callback_response_ = response.Pass(); | |
373 callback_response_data_.reset(); | |
374 if (error == ServiceWorkerCache::ERROR_TYPE_OK && | |
375 !callback_response_->blob_uuid.empty()) { | |
376 callback_response_data_ = body_handle.Pass(); | |
377 } | |
378 | |
379 if (run_loop) | |
380 run_loop->Quit(); | |
381 } | |
382 | |
383 void CloseCallback(base::RunLoop* run_loop) { | |
384 EXPECT_FALSE(callback_closed_); | |
385 callback_closed_ = true; | |
386 if (run_loop) | |
387 run_loop->Quit(); | |
388 } | |
389 | |
390 void CopyBody(storage::BlobDataHandle* blob_handle, std::string* output) { | |
391 scoped_ptr<storage::BlobDataSnapshot> data = blob_handle->CreateSnapshot(); | |
392 const auto& items = data->items(); | |
393 for (const auto& item : items) { | |
394 output->append(item->bytes(), item->length()); | |
395 } | |
396 } | |
397 | |
398 bool VerifyKeys(const std::vector<std::string>& expected_keys) { | |
399 if (expected_keys.size() != callback_strings_.size()) | |
400 return false; | |
401 | |
402 std::set<std::string> found_set; | |
403 for (int i = 0, max = callback_strings_.size(); i < max; ++i) | |
404 found_set.insert(callback_strings_[i]); | |
405 | |
406 for (int i = 0, max = expected_keys.size(); i < max; ++i) { | |
407 if (found_set.find(expected_keys[i]) == found_set.end()) | |
408 return false; | |
409 } | |
410 return true; | |
411 } | |
412 | |
413 bool TestResponseType(blink::WebServiceWorkerResponseType response_type) { | |
414 body_response_.response_type = response_type; | |
415 EXPECT_TRUE(Put(body_request_, body_response_)); | |
416 EXPECT_TRUE(Match(body_request_)); | |
417 EXPECT_TRUE(Delete(body_request_)); | |
418 return response_type == callback_response_->response_type; | |
419 } | |
420 | |
421 void VerifyAllOpsFail() { | |
422 EXPECT_FALSE(Put(no_body_request_, no_body_response_)); | |
423 EXPECT_FALSE(Match(no_body_request_)); | |
424 EXPECT_FALSE(Delete(body_request_)); | |
425 EXPECT_FALSE(Keys()); | |
426 } | |
427 | |
428 virtual bool MemoryOnly() { return false; } | |
429 | |
430 protected: | |
431 TestBrowserContext browser_context_; | |
432 TestBrowserThreadBundle browser_thread_bundle_; | |
433 scoped_ptr<net::URLRequestJobFactoryImpl> url_request_job_factory_; | |
434 scoped_refptr<MockQuotaManagerProxy> quota_manager_proxy_; | |
435 storage::BlobStorageContext* blob_storage_context_; | |
436 | |
437 base::ScopedTempDir temp_dir_; | |
438 scoped_refptr<TestServiceWorkerCache> cache_; | |
439 | |
440 ServiceWorkerFetchRequest body_request_; | |
441 ServiceWorkerResponse body_response_; | |
442 ServiceWorkerFetchRequest no_body_request_; | |
443 ServiceWorkerResponse no_body_response_; | |
444 scoped_ptr<storage::BlobDataHandle> blob_handle_; | |
445 std::string expected_blob_data_; | |
446 | |
447 ServiceWorkerCache::ErrorType callback_error_; | |
448 scoped_ptr<ServiceWorkerResponse> callback_response_; | |
449 scoped_ptr<storage::BlobDataHandle> callback_response_data_; | |
450 std::vector<std::string> callback_strings_; | |
451 bool callback_closed_; | |
452 }; | |
453 | |
454 class ServiceWorkerCacheTestP : public ServiceWorkerCacheTest, | |
455 public testing::WithParamInterface<bool> { | |
456 bool MemoryOnly() override { return !GetParam(); } | |
457 }; | |
458 | |
459 class ServiceWorkerCacheMemoryOnlyTest | |
460 : public ServiceWorkerCacheTest, | |
461 public testing::WithParamInterface<bool> { | |
462 bool MemoryOnly() override { return true; } | |
463 }; | |
464 | |
465 TEST_P(ServiceWorkerCacheTestP, PutNoBody) { | |
466 EXPECT_TRUE(Put(no_body_request_, no_body_response_)); | |
467 EXPECT_TRUE(callback_response_); | |
468 EXPECT_STREQ(no_body_response_.url.spec().c_str(), | |
469 callback_response_->url.spec().c_str()); | |
470 EXPECT_FALSE(callback_response_data_); | |
471 EXPECT_STREQ("", callback_response_->blob_uuid.c_str()); | |
472 EXPECT_EQ(0u, callback_response_->blob_size); | |
473 } | |
474 | |
475 TEST_P(ServiceWorkerCacheTestP, PutBody) { | |
476 EXPECT_TRUE(Put(body_request_, body_response_)); | |
477 EXPECT_TRUE(callback_response_); | |
478 EXPECT_STREQ(body_response_.url.spec().c_str(), | |
479 callback_response_->url.spec().c_str()); | |
480 EXPECT_TRUE(callback_response_data_); | |
481 EXPECT_STRNE("", callback_response_->blob_uuid.c_str()); | |
482 EXPECT_EQ(expected_blob_data_.size(), callback_response_->blob_size); | |
483 | |
484 std::string response_body; | |
485 CopyBody(callback_response_data_.get(), &response_body); | |
486 EXPECT_STREQ(expected_blob_data_.c_str(), response_body.c_str()); | |
487 } | |
488 | |
489 TEST_P(ServiceWorkerCacheTestP, ResponseURLDiffersFromRequestURL) { | |
490 no_body_response_.url = GURL("http://example.com/foobar"); | |
491 EXPECT_STRNE("http://example.com/foobar", | |
492 no_body_request_.url.spec().c_str()); | |
493 EXPECT_TRUE(Put(no_body_request_, no_body_response_)); | |
494 EXPECT_TRUE(Match(no_body_request_)); | |
495 EXPECT_STREQ("http://example.com/foobar", | |
496 callback_response_->url.spec().c_str()); | |
497 } | |
498 | |
499 TEST_P(ServiceWorkerCacheTestP, ResponseURLEmpty) { | |
500 no_body_response_.url = GURL(); | |
501 EXPECT_STRNE("", no_body_request_.url.spec().c_str()); | |
502 EXPECT_TRUE(Put(no_body_request_, no_body_response_)); | |
503 EXPECT_TRUE(Match(no_body_request_)); | |
504 EXPECT_STREQ("", callback_response_->url.spec().c_str()); | |
505 } | |
506 | |
507 TEST_F(ServiceWorkerCacheTest, PutBodyDropBlobRef) { | |
508 scoped_ptr<base::RunLoop> loop(new base::RunLoop()); | |
509 cache_->Put(CopyFetchRequest(body_request_), | |
510 CopyFetchResponse(body_response_), | |
511 base::Bind(&ServiceWorkerCacheTestP::ResponseAndErrorCallback, | |
512 base::Unretained(this), | |
513 base::Unretained(loop.get()))); | |
514 // The handle should be held by the cache now so the deref here should be | |
515 // okay. | |
516 blob_handle_.reset(); | |
517 loop->Run(); | |
518 | |
519 EXPECT_EQ(ServiceWorkerCache::ERROR_TYPE_OK, callback_error_); | |
520 } | |
521 | |
522 TEST_P(ServiceWorkerCacheTestP, PutReplace) { | |
523 EXPECT_TRUE(Put(body_request_, no_body_response_)); | |
524 EXPECT_TRUE(Match(body_request_)); | |
525 EXPECT_FALSE(callback_response_data_); | |
526 | |
527 EXPECT_TRUE(Put(body_request_, body_response_)); | |
528 EXPECT_TRUE(Match(body_request_)); | |
529 EXPECT_TRUE(callback_response_data_); | |
530 | |
531 EXPECT_TRUE(Put(body_request_, no_body_response_)); | |
532 EXPECT_TRUE(Match(body_request_)); | |
533 EXPECT_FALSE(callback_response_data_); | |
534 } | |
535 | |
536 TEST_P(ServiceWorkerCacheTestP, MatchNoBody) { | |
537 EXPECT_TRUE(Put(no_body_request_, no_body_response_)); | |
538 EXPECT_TRUE(Match(no_body_request_)); | |
539 EXPECT_EQ(200, callback_response_->status_code); | |
540 EXPECT_STREQ("OK", callback_response_->status_text.c_str()); | |
541 EXPECT_STREQ("http://example.com/no_body.html", | |
542 callback_response_->url.spec().c_str()); | |
543 EXPECT_STREQ("", callback_response_->blob_uuid.c_str()); | |
544 EXPECT_EQ(0u, callback_response_->blob_size); | |
545 } | |
546 | |
547 TEST_P(ServiceWorkerCacheTestP, MatchBody) { | |
548 EXPECT_TRUE(Put(body_request_, body_response_)); | |
549 EXPECT_TRUE(Match(body_request_)); | |
550 EXPECT_EQ(200, callback_response_->status_code); | |
551 EXPECT_STREQ("OK", callback_response_->status_text.c_str()); | |
552 EXPECT_STREQ("http://example.com/body.html", | |
553 callback_response_->url.spec().c_str()); | |
554 EXPECT_STRNE("", callback_response_->blob_uuid.c_str()); | |
555 EXPECT_EQ(expected_blob_data_.size(), callback_response_->blob_size); | |
556 | |
557 std::string response_body; | |
558 CopyBody(callback_response_data_.get(), &response_body); | |
559 EXPECT_STREQ(expected_blob_data_.c_str(), response_body.c_str()); | |
560 } | |
561 | |
562 TEST_P(ServiceWorkerCacheTestP, Vary) { | |
563 body_request_.headers["vary_foo"] = "foo"; | |
564 body_response_.headers["vary"] = "vary_foo"; | |
565 EXPECT_TRUE(Put(body_request_, body_response_)); | |
566 EXPECT_TRUE(Match(body_request_)); | |
567 | |
568 body_request_.headers["vary_foo"] = "bar"; | |
569 EXPECT_FALSE(Match(body_request_)); | |
570 | |
571 body_request_.headers.erase("vary_foo"); | |
572 EXPECT_FALSE(Match(body_request_)); | |
573 } | |
574 | |
575 TEST_P(ServiceWorkerCacheTestP, EmptyVary) { | |
576 body_response_.headers["vary"] = ""; | |
577 EXPECT_TRUE(Put(body_request_, body_response_)); | |
578 EXPECT_TRUE(Match(body_request_)); | |
579 | |
580 body_request_.headers["zoo"] = "zoo"; | |
581 EXPECT_TRUE(Match(body_request_)); | |
582 } | |
583 | |
584 TEST_P(ServiceWorkerCacheTestP, NoVaryButDiffHeaders) { | |
585 EXPECT_TRUE(Put(body_request_, body_response_)); | |
586 EXPECT_TRUE(Match(body_request_)); | |
587 | |
588 body_request_.headers["zoo"] = "zoo"; | |
589 EXPECT_TRUE(Match(body_request_)); | |
590 } | |
591 | |
592 TEST_P(ServiceWorkerCacheTestP, VaryMultiple) { | |
593 body_request_.headers["vary_foo"] = "foo"; | |
594 body_request_.headers["vary_bar"] = "bar"; | |
595 body_response_.headers["vary"] = " vary_foo , vary_bar"; | |
596 EXPECT_TRUE(Put(body_request_, body_response_)); | |
597 EXPECT_TRUE(Match(body_request_)); | |
598 | |
599 body_request_.headers["vary_bar"] = "foo"; | |
600 EXPECT_FALSE(Match(body_request_)); | |
601 | |
602 body_request_.headers.erase("vary_bar"); | |
603 EXPECT_FALSE(Match(body_request_)); | |
604 } | |
605 | |
606 TEST_P(ServiceWorkerCacheTestP, VaryNewHeader) { | |
607 body_request_.headers["vary_foo"] = "foo"; | |
608 body_response_.headers["vary"] = " vary_foo, vary_bar"; | |
609 EXPECT_TRUE(Put(body_request_, body_response_)); | |
610 EXPECT_TRUE(Match(body_request_)); | |
611 | |
612 body_request_.headers["vary_bar"] = "bar"; | |
613 EXPECT_FALSE(Match(body_request_)); | |
614 } | |
615 | |
616 TEST_P(ServiceWorkerCacheTestP, VaryStar) { | |
617 body_response_.headers["vary"] = "*"; | |
618 EXPECT_TRUE(Put(body_request_, body_response_)); | |
619 EXPECT_FALSE(Match(body_request_)); | |
620 } | |
621 | |
622 TEST_P(ServiceWorkerCacheTestP, EmptyKeys) { | |
623 EXPECT_TRUE(Keys()); | |
624 EXPECT_EQ(0u, callback_strings_.size()); | |
625 } | |
626 | |
627 TEST_P(ServiceWorkerCacheTestP, TwoKeys) { | |
628 EXPECT_TRUE(Put(no_body_request_, no_body_response_)); | |
629 EXPECT_TRUE(Put(body_request_, body_response_)); | |
630 EXPECT_TRUE(Keys()); | |
631 EXPECT_EQ(2u, callback_strings_.size()); | |
632 std::vector<std::string> expected_keys; | |
633 expected_keys.push_back(no_body_request_.url.spec()); | |
634 expected_keys.push_back(body_request_.url.spec()); | |
635 EXPECT_TRUE(VerifyKeys(expected_keys)); | |
636 } | |
637 | |
638 TEST_P(ServiceWorkerCacheTestP, TwoKeysThenOne) { | |
639 EXPECT_TRUE(Put(no_body_request_, no_body_response_)); | |
640 EXPECT_TRUE(Put(body_request_, body_response_)); | |
641 EXPECT_TRUE(Keys()); | |
642 EXPECT_EQ(2u, callback_strings_.size()); | |
643 std::vector<std::string> expected_keys; | |
644 expected_keys.push_back(no_body_request_.url.spec()); | |
645 expected_keys.push_back(body_request_.url.spec()); | |
646 EXPECT_TRUE(VerifyKeys(expected_keys)); | |
647 | |
648 EXPECT_TRUE(Delete(body_request_)); | |
649 EXPECT_TRUE(Keys()); | |
650 EXPECT_EQ(1u, callback_strings_.size()); | |
651 std::vector<std::string> expected_key; | |
652 expected_key.push_back(no_body_request_.url.spec()); | |
653 EXPECT_TRUE(VerifyKeys(expected_key)); | |
654 } | |
655 | |
656 TEST_P(ServiceWorkerCacheTestP, DeleteNoBody) { | |
657 EXPECT_TRUE(Put(no_body_request_, no_body_response_)); | |
658 EXPECT_TRUE(Match(no_body_request_)); | |
659 EXPECT_TRUE(Delete(no_body_request_)); | |
660 EXPECT_FALSE(Match(no_body_request_)); | |
661 EXPECT_FALSE(Delete(no_body_request_)); | |
662 EXPECT_TRUE(Put(no_body_request_, no_body_response_)); | |
663 EXPECT_TRUE(Match(no_body_request_)); | |
664 EXPECT_TRUE(Delete(no_body_request_)); | |
665 } | |
666 | |
667 TEST_P(ServiceWorkerCacheTestP, DeleteBody) { | |
668 EXPECT_TRUE(Put(body_request_, body_response_)); | |
669 EXPECT_TRUE(Match(body_request_)); | |
670 EXPECT_TRUE(Delete(body_request_)); | |
671 EXPECT_FALSE(Match(body_request_)); | |
672 EXPECT_FALSE(Delete(body_request_)); | |
673 EXPECT_TRUE(Put(body_request_, body_response_)); | |
674 EXPECT_TRUE(Match(body_request_)); | |
675 EXPECT_TRUE(Delete(body_request_)); | |
676 } | |
677 | |
678 TEST_P(ServiceWorkerCacheTestP, QuickStressNoBody) { | |
679 for (int i = 0; i < 100; ++i) { | |
680 EXPECT_FALSE(Match(no_body_request_)); | |
681 EXPECT_TRUE(Put(no_body_request_, no_body_response_)); | |
682 EXPECT_TRUE(Match(no_body_request_)); | |
683 EXPECT_TRUE(Delete(no_body_request_)); | |
684 } | |
685 } | |
686 | |
687 TEST_P(ServiceWorkerCacheTestP, QuickStressBody) { | |
688 for (int i = 0; i < 100; ++i) { | |
689 ASSERT_FALSE(Match(body_request_)); | |
690 ASSERT_TRUE(Put(body_request_, body_response_)); | |
691 ASSERT_TRUE(Match(body_request_)); | |
692 ASSERT_TRUE(Delete(body_request_)); | |
693 } | |
694 } | |
695 | |
696 TEST_P(ServiceWorkerCacheTestP, PutResponseType) { | |
697 EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeBasic)); | |
698 EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeCORS)); | |
699 EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeDefault)); | |
700 EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeError)); | |
701 EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeOpaque)); | |
702 } | |
703 | |
704 TEST_F(ServiceWorkerCacheTest, CaselessServiceWorkerResponseHeaders) { | |
705 // ServiceWorkerCache depends on ServiceWorkerResponse having caseless | |
706 // headers so that it can quickly lookup vary headers. | |
707 ServiceWorkerResponse response(GURL("http://www.example.com"), | |
708 200, | |
709 "OK", | |
710 blink::WebServiceWorkerResponseTypeDefault, | |
711 ServiceWorkerHeaderMap(), | |
712 "", | |
713 0, | |
714 GURL()); | |
715 response.headers["content-type"] = "foo"; | |
716 response.headers["Content-Type"] = "bar"; | |
717 EXPECT_EQ("bar", response.headers["content-type"]); | |
718 } | |
719 | |
720 TEST_F(ServiceWorkerCacheTest, CaselessServiceWorkerFetchRequestHeaders) { | |
721 // ServiceWorkerCache depends on ServiceWorkerFetchRequest having caseless | |
722 // headers so that it can quickly lookup vary headers. | |
723 ServiceWorkerFetchRequest request(GURL("http://www.example.com"), | |
724 "GET", | |
725 ServiceWorkerHeaderMap(), | |
726 Referrer(), | |
727 false); | |
728 request.headers["content-type"] = "foo"; | |
729 request.headers["Content-Type"] = "bar"; | |
730 EXPECT_EQ("bar", request.headers["content-type"]); | |
731 } | |
732 | |
733 TEST_P(ServiceWorkerCacheTestP, QuotaManagerModified) { | |
734 EXPECT_EQ(0, quota_manager_proxy_->notify_storage_modified_count()); | |
735 | |
736 EXPECT_TRUE(Put(no_body_request_, no_body_response_)); | |
737 EXPECT_EQ(1, quota_manager_proxy_->notify_storage_modified_count()); | |
738 EXPECT_LT(0, quota_manager_proxy_->last_notified_delta()); | |
739 int64 sum_delta = quota_manager_proxy_->last_notified_delta(); | |
740 | |
741 EXPECT_TRUE(Put(body_request_, body_response_)); | |
742 EXPECT_EQ(2, quota_manager_proxy_->notify_storage_modified_count()); | |
743 EXPECT_LT(sum_delta, quota_manager_proxy_->last_notified_delta()); | |
744 sum_delta += quota_manager_proxy_->last_notified_delta(); | |
745 | |
746 EXPECT_TRUE(Delete(body_request_)); | |
747 EXPECT_EQ(3, quota_manager_proxy_->notify_storage_modified_count()); | |
748 sum_delta += quota_manager_proxy_->last_notified_delta(); | |
749 | |
750 EXPECT_TRUE(Delete(no_body_request_)); | |
751 EXPECT_EQ(4, quota_manager_proxy_->notify_storage_modified_count()); | |
752 sum_delta += quota_manager_proxy_->last_notified_delta(); | |
753 | |
754 EXPECT_EQ(0, sum_delta); | |
755 } | |
756 | |
757 TEST_F(ServiceWorkerCacheMemoryOnlyTest, MemoryBackedSize) { | |
758 EXPECT_EQ(0, cache_->MemoryBackedSize()); | |
759 EXPECT_TRUE(Put(no_body_request_, no_body_response_)); | |
760 EXPECT_LT(0, cache_->MemoryBackedSize()); | |
761 int64 no_body_size = cache_->MemoryBackedSize(); | |
762 | |
763 EXPECT_TRUE(Delete(no_body_request_)); | |
764 EXPECT_EQ(0, cache_->MemoryBackedSize()); | |
765 | |
766 EXPECT_TRUE(Put(body_request_, body_response_)); | |
767 EXPECT_LT(no_body_size, cache_->MemoryBackedSize()); | |
768 | |
769 EXPECT_TRUE(Delete(body_request_)); | |
770 EXPECT_EQ(0, cache_->MemoryBackedSize()); | |
771 } | |
772 | |
773 TEST_F(ServiceWorkerCacheTest, MemoryBackedSizePersistent) { | |
774 EXPECT_EQ(0, cache_->MemoryBackedSize()); | |
775 EXPECT_TRUE(Put(no_body_request_, no_body_response_)); | |
776 EXPECT_EQ(0, cache_->MemoryBackedSize()); | |
777 } | |
778 | |
779 TEST_P(ServiceWorkerCacheTestP, OpsFailOnClosedBackendNeverCreated) { | |
780 cache_->set_delay_backend_creation( | |
781 true); // Will hang the test if a backend is created. | |
782 EXPECT_TRUE(Close()); | |
783 VerifyAllOpsFail(); | |
784 } | |
785 | |
786 TEST_P(ServiceWorkerCacheTestP, OpsFailOnClosedBackend) { | |
787 // Create the backend and put something in it. | |
788 EXPECT_TRUE(Put(body_request_, body_response_)); | |
789 EXPECT_TRUE(Close()); | |
790 VerifyAllOpsFail(); | |
791 } | |
792 | |
793 TEST_P(ServiceWorkerCacheTestP, VerifySerialScheduling) { | |
794 // Start two operations, the first one is delayed but the second isn't. The | |
795 // second should wait for the first. | |
796 EXPECT_TRUE(Keys()); // Opens the backend. | |
797 DelayableBackend* delayable_backend = cache_->UseDelayableBackend(); | |
798 delayable_backend->set_delay_open(true); | |
799 | |
800 scoped_ptr<ServiceWorkerResponse> response1 = | |
801 CopyFetchResponse(body_response_); | |
802 response1->status_code = 1; | |
803 | |
804 scoped_ptr<base::RunLoop> close_loop1(new base::RunLoop()); | |
805 cache_->Put(CopyFetchRequest(body_request_), response1.Pass(), | |
806 base::Bind(&ServiceWorkerCacheTest::ResponseAndErrorCallback, | |
807 base::Unretained(this), close_loop1.get())); | |
808 | |
809 // Blocks on opening the cache entry. | |
810 base::RunLoop().RunUntilIdle(); | |
811 | |
812 delayable_backend->set_delay_open(false); | |
813 scoped_ptr<ServiceWorkerResponse> response2 = | |
814 CopyFetchResponse(body_response_); | |
815 response2->status_code = 2; | |
816 scoped_ptr<base::RunLoop> close_loop2(new base::RunLoop()); | |
817 cache_->Put(CopyFetchRequest(body_request_), response2.Pass(), | |
818 base::Bind(&ServiceWorkerCacheTest::ResponseAndErrorCallback, | |
819 base::Unretained(this), close_loop2.get())); | |
820 | |
821 // The second put operation should wait for the first to complete. | |
822 base::RunLoop().RunUntilIdle(); | |
823 EXPECT_FALSE(callback_response_); | |
824 | |
825 delayable_backend->OpenEntryContinue(); | |
826 close_loop1->Run(); | |
827 EXPECT_EQ(1, callback_response_->status_code); | |
828 close_loop2->Run(); | |
829 EXPECT_EQ(2, callback_response_->status_code); | |
830 } | |
831 | |
832 INSTANTIATE_TEST_CASE_P(ServiceWorkerCacheTest, | |
833 ServiceWorkerCacheTestP, | |
834 ::testing::Values(false, true)); | |
835 | |
836 } // namespace content | |
OLD | NEW |