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 <stddef.h>
6 #include <stdint.h>
7
8 #include <limits>
9 #include <memory>
10 #include <set>
11 #include <utility>
12
13 #include "base/bind.h"
14 #include "base/callback_helpers.h"
15 #include "base/files/file_path.h"
16 #include "base/files/scoped_temp_dir.h"
17 #include "base/macros.h"
18 #include "base/memory/ptr_util.h"
19 #include "base/memory/ref_counted.h"
20 #include "base/notreached.h"
21 #include "base/run_loop.h"
22 #include "base/strings/strcat.h"
23 #include "base/strings/string_number_conversions.h"
24 #include "base/strings/string_split.h"
25 #include "base/test/bind.h"
26 #include "base/test/metrics/histogram_tester.h"
27 #include "base/threading/thread_task_runner_handle.h"
28 #include "build/build_config.h"
29 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
30 #include "content/browser/cache_storage/cache_storage_cache.h"
31 #include "content/browser/cache_storage/cache_storage_cache_handle.h"
32 #include "content/browser/cache_storage/cache_storage_histogram_utils.h"
33 #include "content/browser/cache_storage/cache_storage_manager.h"
34 #include "content/browser/cache_storage/legacy/legacy_cache_storage.h"
35 #include "content/browser/cache_storage/legacy/legacy_cache_storage_cache.h"
36 #include "content/common/background_fetch/background_fetch_types.h"
37 #include "content/public/browser/browser_thread.h"
38 #include "content/public/test/browser_task_environment.h"
39 #include "content/public/test/test_browser_context.h"
40 #include "content/public/test/test_utils.h"
41 #include "crypto/symmetric_key.h"
42 #include "mojo/public/cpp/bindings/remote.h"
43 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
44 #include "mojo/public/cpp/system/data_pipe.h"
45 #include "mojo/public/cpp/system/data_pipe_drainer.h"
46 #include "net/base/test_completion_callback.h"
47 #include "net/base/url_util.h"
48 #include "net/disk_cache/disk_cache.h"
49 #include "storage/browser/blob/blob_storage_context.h"
50 #include "storage/browser/quota/quota_manager_proxy.h"
51 #include "storage/browser/test/blob_test_utils.h"
52 #include "storage/browser/test/fake_blob.h"
53 #include "storage/browser/test/mock_quota_manager_proxy.h"
54 #include "storage/browser/test/mock_special_storage_policy.h"
55 #include "testing/gtest/include/gtest/gtest.h"
56 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom.h"
57 #include "url/origin.h"
58
59 using blink::FetchAPIRequestHeadersMap;
60 using blink::mojom::CacheStorageError;
61 using blink::mojom::CacheStorageVerboseErrorPtr;
62
63 namespace content {
64 namespace cache_storage_cache_unittest {
65
66 const char kTestData[] = "Hello World";
67 const char kCacheName[] = "test_cache";
68 const FetchAPIRequestHeadersMap kHeaders({{"a", "a"}, {"b", "b"}});
69
SizeCallback(base::RunLoop * run_loop,bool * callback_called,int64_t * out_size,int64_t size)70 void SizeCallback(base::RunLoop* run_loop,
71 bool* callback_called,
72 int64_t* out_size,
73 int64_t size) {
74 *callback_called = true;
75 *out_size = size;
76 if (run_loop)
77 run_loop->Quit();
78 }
79
80 // A blob that never finishes writing to its pipe.
81 class SlowBlob : public storage::FakeBlob {
82 public:
SlowBlob(base::OnceClosure quit_closure)83 explicit SlowBlob(base::OnceClosure quit_closure)
84 : FakeBlob("foo"), quit_closure_(std::move(quit_closure)) {}
85
ReadAll(mojo::ScopedDataPipeProducerHandle producer_handle,mojo::PendingRemote<blink::mojom::BlobReaderClient> client)86 void ReadAll(
87 mojo::ScopedDataPipeProducerHandle producer_handle,
88 mojo::PendingRemote<blink::mojom::BlobReaderClient> client) override {
89 // Don't respond, forcing the consumer to wait forever.
90 std::move(quit_closure_).Run();
91 }
92
93 private:
94 base::OnceClosure quit_closure_;
95 };
96
97 // A disk_cache::Backend wrapper that can delay operations.
98 class DelayableBackend : public disk_cache::Backend {
99 public:
DelayableBackend(std::unique_ptr<disk_cache::Backend> backend)100 explicit DelayableBackend(std::unique_ptr<disk_cache::Backend> backend)
101 : Backend(backend->GetCacheType()),
102 backend_(std::move(backend)),
103 delay_open_entry_(false) {}
104
105 // disk_cache::Backend overrides
GetEntryCount() const106 int32_t GetEntryCount() const override { return backend_->GetEntryCount(); }
OpenEntry(const std::string & key,net::RequestPriority request_priority,EntryResultCallback callback)107 EntryResult OpenEntry(const std::string& key,
108 net::RequestPriority request_priority,
109 EntryResultCallback callback) override {
110 if (delay_open_entry_ && open_entry_callback_.is_null()) {
111 open_entry_callback_ =
112 base::BindOnce(&DelayableBackend::OpenEntryDelayedImpl,
113 base::Unretained(this), key, std::move(callback));
114 if (open_entry_started_callback_)
115 std::move(open_entry_started_callback_).Run();
116 return EntryResult::MakeError(net::ERR_IO_PENDING);
117 }
118 return backend_->OpenEntry(key, request_priority, std::move(callback));
119 }
120
CreateEntry(const std::string & key,net::RequestPriority request_priority,EntryResultCallback callback)121 EntryResult CreateEntry(const std::string& key,
122 net::RequestPriority request_priority,
123 EntryResultCallback callback) override {
124 return backend_->CreateEntry(key, request_priority, std::move(callback));
125 }
OpenOrCreateEntry(const std::string & key,net::RequestPriority request_priority,EntryResultCallback callback)126 EntryResult OpenOrCreateEntry(const std::string& key,
127 net::RequestPriority request_priority,
128 EntryResultCallback callback) override {
129 return backend_->OpenOrCreateEntry(key, request_priority,
130 std::move(callback));
131 }
DoomEntry(const std::string & key,net::RequestPriority request_priority,CompletionOnceCallback callback)132 net::Error DoomEntry(const std::string& key,
133 net::RequestPriority request_priority,
134 CompletionOnceCallback callback) override {
135 return backend_->DoomEntry(key, request_priority, std::move(callback));
136 }
DoomAllEntries(CompletionOnceCallback callback)137 net::Error DoomAllEntries(CompletionOnceCallback callback) override {
138 return backend_->DoomAllEntries(std::move(callback));
139 }
DoomEntriesBetween(base::Time initial_time,base::Time end_time,CompletionOnceCallback callback)140 net::Error DoomEntriesBetween(base::Time initial_time,
141 base::Time end_time,
142 CompletionOnceCallback callback) override {
143 return backend_->DoomEntriesBetween(initial_time, end_time,
144 std::move(callback));
145 }
DoomEntriesSince(base::Time initial_time,CompletionOnceCallback callback)146 net::Error DoomEntriesSince(base::Time initial_time,
147 CompletionOnceCallback callback) override {
148 return backend_->DoomEntriesSince(initial_time, std::move(callback));
149 }
CalculateSizeOfAllEntries(Int64CompletionOnceCallback callback)150 int64_t CalculateSizeOfAllEntries(
151 Int64CompletionOnceCallback callback) override {
152 return backend_->CalculateSizeOfAllEntries(std::move(callback));
153 }
CreateIterator()154 std::unique_ptr<Iterator> CreateIterator() override {
155 return backend_->CreateIterator();
156 }
GetStats(base::StringPairs * stats)157 void GetStats(base::StringPairs* stats) override {
158 return backend_->GetStats(stats);
159 }
OnExternalCacheHit(const std::string & key)160 void OnExternalCacheHit(const std::string& key) override {
161 return backend_->OnExternalCacheHit(key);
162 }
163
DumpMemoryStats(base::trace_event::ProcessMemoryDump * pmd,const std::string & parent_absolute_name) const164 size_t DumpMemoryStats(
165 base::trace_event::ProcessMemoryDump* pmd,
166 const std::string& parent_absolute_name) const override {
167 NOTREACHED();
168 return 0u;
169 }
170
MaxFileSize() const171 int64_t MaxFileSize() const override { return backend_->MaxFileSize(); }
172
173 // Call to continue a delayed call to OpenEntry.
OpenEntryContinue()174 bool OpenEntryContinue() {
175 if (open_entry_callback_.is_null())
176 return false;
177 std::move(open_entry_callback_).Run();
178 return true;
179 }
180
set_delay_open_entry(bool value)181 void set_delay_open_entry(bool value) { delay_open_entry_ = value; }
182
set_open_entry_started_callback(base::OnceClosure open_entry_started_callback)183 void set_open_entry_started_callback(
184 base::OnceClosure open_entry_started_callback) {
185 open_entry_started_callback_ = std::move(open_entry_started_callback);
186 }
187
188 private:
OpenEntryDelayedImpl(const std::string & key,EntryResultCallback callback)189 void OpenEntryDelayedImpl(const std::string& key,
190 EntryResultCallback callback) {
191 auto copyable_callback =
192 base::AdaptCallbackForRepeating(std::move(callback));
193 EntryResult result =
194 backend_->OpenEntry(key, net::HIGHEST, copyable_callback);
195 if (result.net_error() != net::ERR_IO_PENDING)
196 copyable_callback.Run(std::move(result));
197 }
198
199 std::unique_ptr<disk_cache::Backend> backend_;
200 bool delay_open_entry_;
201 base::OnceClosure open_entry_callback_;
202 base::OnceClosure open_entry_started_callback_;
203 };
204
205 class FailableCacheEntry : public disk_cache::Entry {
206 public:
FailableCacheEntry(disk_cache::Entry * entry)207 explicit FailableCacheEntry(disk_cache::Entry* entry) : entry_(entry) {}
208
Doom()209 void Doom() override { entry_->Doom(); }
Close()210 void Close() override { entry_->Close(); }
GetKey() const211 std::string GetKey() const override { return entry_->GetKey(); }
GetLastUsed() const212 base::Time GetLastUsed() const override { return entry_->GetLastUsed(); }
GetLastModified() const213 base::Time GetLastModified() const override {
214 return entry_->GetLastModified();
215 }
GetDataSize(int index) const216 int32_t GetDataSize(int index) const override {
217 return entry_->GetDataSize(index);
218 }
ReadData(int index,int offset,IOBuffer * buf,int buf_len,CompletionOnceCallback callback)219 int ReadData(int index,
220 int offset,
221 IOBuffer* buf,
222 int buf_len,
223 CompletionOnceCallback callback) override {
224 return entry_->ReadData(index, offset, buf, buf_len, std::move(callback));
225 }
WriteData(int index,int offset,IOBuffer * buf,int buf_len,CompletionOnceCallback callback,bool truncate)226 int WriteData(int index,
227 int offset,
228 IOBuffer* buf,
229 int buf_len,
230 CompletionOnceCallback callback,
231 bool truncate) override {
232 std::move(callback).Run(net::ERR_FAILED);
233 return net::ERR_IO_PENDING;
234 }
ReadSparseData(int64_t offset,IOBuffer * buf,int buf_len,CompletionOnceCallback callback)235 int ReadSparseData(int64_t offset,
236 IOBuffer* buf,
237 int buf_len,
238 CompletionOnceCallback callback) override {
239 return entry_->ReadSparseData(offset, buf, buf_len, std::move(callback));
240 }
WriteSparseData(int64_t offset,IOBuffer * buf,int buf_len,CompletionOnceCallback callback)241 int WriteSparseData(int64_t offset,
242 IOBuffer* buf,
243 int buf_len,
244 CompletionOnceCallback callback) override {
245 return entry_->WriteSparseData(offset, buf, buf_len, std::move(callback));
246 }
GetAvailableRange(int64_t offset,int len,int64_t * start,CompletionOnceCallback callback)247 int GetAvailableRange(int64_t offset,
248 int len,
249 int64_t* start,
250 CompletionOnceCallback callback) override {
251 return entry_->GetAvailableRange(offset, len, start, std::move(callback));
252 }
CouldBeSparse() const253 bool CouldBeSparse() const override { return entry_->CouldBeSparse(); }
CancelSparseIO()254 void CancelSparseIO() override { entry_->CancelSparseIO(); }
ReadyForSparseIO(CompletionOnceCallback callback)255 net::Error ReadyForSparseIO(CompletionOnceCallback callback) override {
256 return entry_->ReadyForSparseIO(std::move(callback));
257 }
SetLastUsedTimeForTest(base::Time time)258 void SetLastUsedTimeForTest(base::Time time) override {
259 entry_->SetLastUsedTimeForTest(time);
260 }
261
262 private:
263 disk_cache::Entry* const entry_;
264 };
265
266 class FailableBackend : public disk_cache::Backend {
267 public:
268 enum class FailureStage { CREATE_ENTRY = 0, WRITE_HEADERS = 1 };
FailableBackend(std::unique_ptr<disk_cache::Backend> backend,FailureStage stage)269 explicit FailableBackend(std::unique_ptr<disk_cache::Backend> backend,
270 FailureStage stage)
271 : Backend(backend->GetCacheType()),
272 backend_(std::move(backend)),
273 stage_(stage) {}
274
275 // disk_cache::Backend overrides
GetEntryCount() const276 int32_t GetEntryCount() const override { return backend_->GetEntryCount(); }
277
OpenOrCreateEntry(const std::string & key,net::RequestPriority request_priority,EntryResultCallback callback)278 EntryResult OpenOrCreateEntry(const std::string& key,
279 net::RequestPriority request_priority,
280 EntryResultCallback callback) override {
281 if (stage_ == FailureStage::CREATE_ENTRY) {
282 return EntryResult::MakeError(net::ERR_FILE_NO_SPACE);
283 } else if (stage_ == FailureStage::WRITE_HEADERS) {
284 return backend_->OpenOrCreateEntry(
285 key, request_priority,
286 base::BindOnce(
287 [](EntryResultCallback callback, disk_cache::EntryResult result) {
288 FailableCacheEntry failable_entry(result.ReleaseEntry());
289 EntryResult failable_result =
290 EntryResult::MakeCreated(&failable_entry);
291 std::move(callback).Run(std::move(failable_result));
292 },
293 std::move(callback)));
294 } else {
295 return backend_->OpenOrCreateEntry(key, request_priority,
296 std::move(callback));
297 }
298 }
299
OpenEntry(const std::string & key,net::RequestPriority request_priority,EntryResultCallback callback)300 EntryResult OpenEntry(const std::string& key,
301 net::RequestPriority request_priority,
302 EntryResultCallback callback) override {
303 return backend_->OpenEntry(key, request_priority, std::move(callback));
304 }
305
CreateEntry(const std::string & key,net::RequestPriority request_priority,EntryResultCallback callback)306 EntryResult CreateEntry(const std::string& key,
307 net::RequestPriority request_priority,
308 EntryResultCallback callback) override {
309 return backend_->CreateEntry(key, request_priority, std::move(callback));
310 }
311
DoomEntry(const std::string & key,net::RequestPriority request_priority,CompletionOnceCallback callback)312 net::Error DoomEntry(const std::string& key,
313 net::RequestPriority request_priority,
314 CompletionOnceCallback callback) override {
315 return backend_->DoomEntry(key, request_priority, std::move(callback));
316 }
317
DoomAllEntries(CompletionOnceCallback callback)318 net::Error DoomAllEntries(CompletionOnceCallback callback) override {
319 return backend_->DoomAllEntries(std::move(callback));
320 }
321
DoomEntriesBetween(base::Time initial_time,base::Time end_time,CompletionOnceCallback callback)322 net::Error DoomEntriesBetween(base::Time initial_time,
323 base::Time end_time,
324 CompletionOnceCallback callback) override {
325 return backend_->DoomEntriesBetween(initial_time, end_time,
326 std::move(callback));
327 }
DoomEntriesSince(base::Time initial_time,CompletionOnceCallback callback)328 net::Error DoomEntriesSince(base::Time initial_time,
329 CompletionOnceCallback callback) override {
330 return backend_->DoomEntriesSince(initial_time, std::move(callback));
331 }
CalculateSizeOfAllEntries(Int64CompletionOnceCallback callback)332 int64_t CalculateSizeOfAllEntries(
333 Int64CompletionOnceCallback callback) override {
334 return backend_->CalculateSizeOfAllEntries(std::move(callback));
335 }
CreateIterator()336 std::unique_ptr<Iterator> CreateIterator() override {
337 return backend_->CreateIterator();
338 }
GetStats(base::StringPairs * stats)339 void GetStats(base::StringPairs* stats) override {
340 return backend_->GetStats(stats);
341 }
OnExternalCacheHit(const std::string & key)342 void OnExternalCacheHit(const std::string& key) override {
343 return backend_->OnExternalCacheHit(key);
344 }
DumpMemoryStats(base::trace_event::ProcessMemoryDump * pmd,const std::string & parent_absolute_name) const345 size_t DumpMemoryStats(
346 base::trace_event::ProcessMemoryDump* pmd,
347 const std::string& parent_absolute_name) const override {
348 NOTREACHED();
349 return 0u;
350 }
MaxFileSize() const351 int64_t MaxFileSize() const override { return backend_->MaxFileSize(); }
352
353 private:
354 std::unique_ptr<disk_cache::Backend> backend_;
355 FailureStage stage_;
356 };
357
CopySideData(blink::mojom::Blob * actual_blob)358 std::string CopySideData(blink::mojom::Blob* actual_blob) {
359 std::string output;
360 base::RunLoop loop;
361 actual_blob->ReadSideData(base::BindLambdaForTesting(
362 [&](const base::Optional<mojo_base::BigBuffer> data) {
363 if (data)
364 output.append(data->data(), data->data() + data->size());
365 loop.Quit();
366 }));
367 loop.Run();
368 return output;
369 }
370
ResponseMetadataEqual(const blink::mojom::FetchAPIResponse & expected,const blink::mojom::FetchAPIResponse & actual)371 bool ResponseMetadataEqual(const blink::mojom::FetchAPIResponse& expected,
372 const blink::mojom::FetchAPIResponse& actual) {
373 EXPECT_EQ(expected.status_code, actual.status_code);
374 if (expected.status_code != actual.status_code)
375 return false;
376 EXPECT_EQ(expected.status_text, actual.status_text);
377 if (expected.status_text != actual.status_text)
378 return false;
379 EXPECT_EQ(expected.url_list.size(), actual.url_list.size());
380 if (expected.url_list.size() != actual.url_list.size())
381 return false;
382 for (size_t i = 0; i < expected.url_list.size(); ++i) {
383 EXPECT_EQ(expected.url_list[i], actual.url_list[i]);
384 if (expected.url_list[i] != actual.url_list[i])
385 return false;
386 }
387 EXPECT_EQ(!expected.blob, !actual.blob);
388 if (!expected.blob != !actual.blob)
389 return false;
390
391 if (expected.blob) {
392 if (expected.blob->size == 0) {
393 EXPECT_STREQ("", actual.blob->uuid.c_str());
394 if (!actual.blob->uuid.empty())
395 return false;
396 } else {
397 EXPECT_STRNE("", actual.blob->uuid.c_str());
398 if (actual.blob->uuid.empty())
399 return false;
400 }
401 }
402
403 EXPECT_EQ(expected.response_time, actual.response_time);
404 if (expected.response_time != actual.response_time)
405 return false;
406
407 EXPECT_EQ(expected.cache_storage_cache_name, actual.cache_storage_cache_name);
408 if (expected.cache_storage_cache_name != actual.cache_storage_cache_name)
409 return false;
410
411 EXPECT_EQ(expected.cors_exposed_header_names,
412 actual.cors_exposed_header_names);
413 if (expected.cors_exposed_header_names != actual.cors_exposed_header_names)
414 return false;
415
416 return true;
417 }
418
SetCacheName(blink::mojom::FetchAPIResponsePtr response)419 blink::mojom::FetchAPIResponsePtr SetCacheName(
420 blink::mojom::FetchAPIResponsePtr response) {
421 response->response_source =
422 network::mojom::FetchResponseSource::kCacheStorage;
423 response->cache_storage_cache_name = kCacheName;
424 return response;
425 }
426
CreateTestPaddingKey()427 std::unique_ptr<crypto::SymmetricKey> CreateTestPaddingKey() {
428 return crypto::SymmetricKey::Import(crypto::SymmetricKey::HMAC_SHA1,
429 "abc123");
430 }
431
OnBadMessage(std::string * result)432 void OnBadMessage(std::string* result) {
433 *result = "CSDH_UNEXPECTED_OPERATION";
434 }
435
436 // A CacheStorageCache that can optionally delay during backend creation.
437 class TestCacheStorageCache : public LegacyCacheStorageCache {
438 public:
TestCacheStorageCache(const url::Origin & origin,const std::string & cache_name,const base::FilePath & path,LegacyCacheStorage * cache_storage,const scoped_refptr<storage::QuotaManagerProxy> & quota_manager_proxy,scoped_refptr<BlobStorageContextWrapper> blob_storage_context)439 TestCacheStorageCache(
440 const url::Origin& origin,
441 const std::string& cache_name,
442 const base::FilePath& path,
443 LegacyCacheStorage* cache_storage,
444 const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
445 scoped_refptr<BlobStorageContextWrapper> blob_storage_context)
446 : LegacyCacheStorageCache(origin,
447 CacheStorageOwner::kCacheAPI,
448 cache_name,
449 path,
450 cache_storage,
451 base::ThreadTaskRunnerHandle::Get(),
452 quota_manager_proxy,
453 std::move(blob_storage_context),
454 0 /* cache_size */,
455 0 /* cache_padding */,
456 CreateTestPaddingKey()),
457 delay_backend_creation_(false) {}
458
~TestCacheStorageCache()459 ~TestCacheStorageCache() override { base::RunLoop().RunUntilIdle(); }
460
CreateBackend(ErrorCallback callback)461 void CreateBackend(ErrorCallback callback) override {
462 backend_creation_callback_ = std::move(callback);
463 if (delay_backend_creation_)
464 return;
465 ContinueCreateBackend();
466 }
467
ContinueCreateBackend()468 void ContinueCreateBackend() {
469 LegacyCacheStorageCache::CreateBackend(
470 std::move(backend_creation_callback_));
471 }
472
set_delay_backend_creation(bool delay)473 void set_delay_backend_creation(bool delay) {
474 delay_backend_creation_ = delay;
475 }
476
477 // Swap the existing backend with a delayable one. The backend must have been
478 // created before calling this.
UseDelayableBackend()479 DelayableBackend* UseDelayableBackend() {
480 EXPECT_TRUE(backend_);
481 DelayableBackend* delayable_backend =
482 new DelayableBackend(std::move(backend_));
483 backend_.reset(delayable_backend);
484 return delayable_backend;
485 }
486
UseFailableBackend(FailableBackend::FailureStage stage)487 void UseFailableBackend(FailableBackend::FailureStage stage) {
488 EXPECT_TRUE(backend_);
489 auto failable_backend =
490 std::make_unique<FailableBackend>(std::move(backend_), stage);
491 backend_ = std::move(failable_backend);
492 }
493
Init()494 void Init() { InitBackend(); }
495
GetRequiredSafeSpaceForRequest(const blink::mojom::FetchAPIRequestPtr & request)496 base::CheckedNumeric<uint64_t> GetRequiredSafeSpaceForRequest(
497 const blink::mojom::FetchAPIRequestPtr& request) {
498 return CalculateRequiredSafeSpaceForRequest(request);
499 }
500
GetRequiredSafeSpaceForResponse(const blink::mojom::FetchAPIResponsePtr & response)501 base::CheckedNumeric<uint64_t> GetRequiredSafeSpaceForResponse(
502 const blink::mojom::FetchAPIResponsePtr& response) {
503 return CalculateRequiredSafeSpaceForResponse(response);
504 }
505
506 private:
507 bool delay_backend_creation_;
508 ErrorCallback backend_creation_callback_;
509
510 DISALLOW_COPY_AND_ASSIGN(TestCacheStorageCache);
511 };
512
513 class MockLegacyCacheStorage : public LegacyCacheStorage {
514 public:
MockLegacyCacheStorage(const base::FilePath & origin_path,bool memory_only,base::SequencedTaskRunner * cache_task_runner,scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner,scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,scoped_refptr<BlobStorageContextWrapper> blob_storage_context,LegacyCacheStorageManager * cache_storage_manager,const url::Origin & origin,CacheStorageOwner owner)515 MockLegacyCacheStorage(
516 const base::FilePath& origin_path,
517 bool memory_only,
518 base::SequencedTaskRunner* cache_task_runner,
519 scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner,
520 scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
521 scoped_refptr<BlobStorageContextWrapper> blob_storage_context,
522 LegacyCacheStorageManager* cache_storage_manager,
523 const url::Origin& origin,
524 CacheStorageOwner owner)
525 : LegacyCacheStorage(origin_path,
526 memory_only,
527 cache_task_runner,
528 std::move(scheduler_task_runner),
529 std::move(quota_manager_proxy),
530 std::move(blob_storage_context),
531 cache_storage_manager,
532 std::move(origin),
533 owner) {}
534
CacheUnreferenced(LegacyCacheStorageCache * cache)535 void CacheUnreferenced(LegacyCacheStorageCache* cache) override {
536 // Normally the LegacyCacheStorage will attempt to delete the cache
537 // from its map when the cache has become unreferenced. Since we are
538 // using detached cache objects we instead override to do nothing here.
539 }
540 };
541
542 class CacheStorageCacheTest : public testing::Test {
543 public:
CacheStorageCacheTest()544 CacheStorageCacheTest()
545 : task_environment_(BrowserTaskEnvironment::IO_MAINLOOP) {}
546
SetUp()547 void SetUp() override {
548 ChromeBlobStorageContext* blob_storage_context =
549 ChromeBlobStorageContext::GetFor(&browser_context_);
550 // Wait for chrome_blob_storage_context to finish initializing.
551 base::RunLoop().RunUntilIdle();
552
553 mojo::PendingRemote<storage::mojom::BlobStorageContext> remote;
554 blob_storage_context->BindMojoContext(
555 remote.InitWithNewPipeAndPassReceiver());
556 blob_storage_context_ =
557 base::MakeRefCounted<BlobStorageContextWrapper>(std::move(remote));
558
559 const bool is_incognito = MemoryOnly();
560 if (!is_incognito) {
561 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
562 temp_dir_path_ = temp_dir_.GetPath();
563 }
564
565 quota_policy_ = base::MakeRefCounted<storage::MockSpecialStoragePolicy>();
566 mock_quota_manager_ = base::MakeRefCounted<storage::MockQuotaManager>(
567 is_incognito, temp_dir_path_, base::ThreadTaskRunnerHandle::Get().get(),
568 quota_policy_.get());
569 SetQuota(1024 * 1024 * 100);
570
571 quota_manager_proxy_ = base::MakeRefCounted<storage::MockQuotaManagerProxy>(
572 mock_quota_manager_.get(), base::ThreadTaskRunnerHandle::Get().get());
573
574 CreateRequests(blob_storage_context);
575
576 response_time_ = base::Time::Now();
577 for (int i = 0; i < 100; ++i)
578 expected_blob_data_ += kTestData;
579
580 blob_storage_context_->context()->RegisterFromMemory(
581 blob_remote_.BindNewPipeAndPassReceiver(), expected_blob_uuid_,
582 std::vector<uint8_t>(expected_blob_data_.begin(),
583 expected_blob_data_.end()));
584
585 // Use a mock LegacyCacheStorage object so we can use real
586 // CacheStorageCacheHandle reference counting. A LegacyCacheStorage
587 // must be present to be notified when a cache becomes unreferenced.
588 mock_cache_storage_ = std::make_unique<MockLegacyCacheStorage>(
589 temp_dir_path_, MemoryOnly(), base::ThreadTaskRunnerHandle::Get().get(),
590 base::ThreadTaskRunnerHandle::Get(), quota_manager_proxy_,
591 blob_storage_context_, /* cache_storage_manager = */ nullptr,
592 url::Origin::Create(kTestUrl), CacheStorageOwner::kCacheAPI);
593
594 InitCache(mock_cache_storage_.get());
595 }
596
TearDown()597 void TearDown() override {
598 quota_manager_proxy_->SimulateQuotaManagerDestroyed();
599 disk_cache::FlushCacheThreadForTesting();
600 content::RunAllTasksUntilIdle();
601 }
602
BodyUrl() const603 GURL BodyUrl() const {
604 GURL::Replacements replacements;
605 replacements.SetPathStr("/body.html");
606 return kTestUrl.ReplaceComponents(replacements);
607 }
608
BodyUrlWithQuery() const609 GURL BodyUrlWithQuery() const {
610 return net::AppendQueryParameter(BodyUrl(), "query", "test");
611 }
612
NoBodyUrl() const613 GURL NoBodyUrl() const {
614 GURL::Replacements replacements;
615 replacements.SetPathStr("/no_body.html");
616 return kTestUrl.ReplaceComponents(replacements);
617 }
618
InitCache(LegacyCacheStorage * cache_storage)619 void InitCache(LegacyCacheStorage* cache_storage) {
620 cache_ = std::make_unique<TestCacheStorageCache>(
621 url::Origin::Create(kTestUrl), kCacheName, temp_dir_path_,
622 cache_storage, quota_manager_proxy_, blob_storage_context_);
623 cache_->Init();
624 }
625
CreateRequests(ChromeBlobStorageContext * blob_storage_context)626 void CreateRequests(ChromeBlobStorageContext* blob_storage_context) {
627 body_request_ = CreateFetchAPIRequest(BodyUrl(), "GET", kHeaders,
628 blink::mojom::Referrer::New(), false);
629 body_request_with_query_ =
630 CreateFetchAPIRequest(BodyUrlWithQuery(), "GET", kHeaders,
631 blink::mojom::Referrer::New(), false);
632 no_body_request_ = CreateFetchAPIRequest(
633 NoBodyUrl(), "GET", kHeaders, blink::mojom::Referrer::New(), false);
634 body_head_request_ = CreateFetchAPIRequest(
635 BodyUrl(), "HEAD", kHeaders, blink::mojom::Referrer::New(), false);
636 }
637
CreateBlobBodyResponse()638 blink::mojom::FetchAPIResponsePtr CreateBlobBodyResponse() {
639 auto blob = blink::mojom::SerializedBlob::New();
640 blob->uuid = expected_blob_uuid_;
641 blob->size = expected_blob_data_.size();
642 // Use cloned blob remote for all responses with blob body.
643 blob_remote_->Clone(blob->blob.InitWithNewPipeAndPassReceiver());
644
645 blink::mojom::FetchAPIResponsePtr response = CreateNoBodyResponse();
646 response->url_list = {BodyUrl()};
647 response->blob = std::move(blob);
648 return response;
649 }
650
CreateBlobBodyResponseWithQuery()651 blink::mojom::FetchAPIResponsePtr CreateBlobBodyResponseWithQuery() {
652 blink::mojom::FetchAPIResponsePtr response = CreateBlobBodyResponse();
653 response->url_list = {BodyUrlWithQuery()};
654 response->cors_exposed_header_names = {"a"};
655 return response;
656 }
657
CreateNoBodyResponse()658 blink::mojom::FetchAPIResponsePtr CreateNoBodyResponse() {
659 return blink::mojom::FetchAPIResponse::New(
660 std::vector<GURL>({NoBodyUrl()}), 200, "OK",
661 network::mojom::FetchResponseType::kDefault,
662 network::mojom::FetchResponseSource::kUnspecified,
663 base::flat_map<std::string, std::string>(kHeaders.cbegin(),
664 kHeaders.cend()),
665 base::nullopt /* mime_type */, net::HttpRequestHeaders::kGetMethod,
666 nullptr /* blob */, blink::mojom::ServiceWorkerResponseError::kUnknown,
667 response_time_, std::string() /* cache_storage_cache_name */,
668 std::vector<std::string>() /* cors_exposed_header_names */,
669 nullptr /* side_data_blob */,
670 nullptr /* side_data_blob_for_cache_put */,
671 network::mojom::ParsedHeaders::New(),
672 net::HttpResponseInfo::CONNECTION_INFO_UNKNOWN,
673 "unknown" /* alpn_negotiated_protocol */,
674 false /* loaded_with_credentials */, false /* was_fetched_via_spdy */,
675 false /* has_range_requested */);
676 }
677
CopySideDataToResponse(const std::string & uuid,const std::string & data,blink::mojom::FetchAPIResponse * response)678 void CopySideDataToResponse(const std::string& uuid,
679 const std::string& data,
680 blink::mojom::FetchAPIResponse* response) {
681 auto& blob = response->side_data_blob_for_cache_put;
682 blob = blink::mojom::SerializedBlob::New();
683 blob->uuid = uuid;
684 blob->size = data.size();
685 blob_storage_context_->context()->RegisterFromMemory(
686 blob->blob.InitWithNewPipeAndPassReceiver(), uuid,
687 std::vector<uint8_t>(data.begin(), data.end()));
688 }
689
CopyFetchRequest(const blink::mojom::FetchAPIRequestPtr & request)690 blink::mojom::FetchAPIRequestPtr CopyFetchRequest(
691 const blink::mojom::FetchAPIRequestPtr& request) {
692 return CreateFetchAPIRequest(request->url, request->method,
693 request->headers, request->referrer.Clone(),
694 request->is_reload);
695 }
696
BatchOperation(std::vector<blink::mojom::BatchOperationPtr> operations)697 CacheStorageError BatchOperation(
698 std::vector<blink::mojom::BatchOperationPtr> operations) {
699 std::unique_ptr<base::RunLoop> loop(new base::RunLoop());
700
701 cache_->BatchOperation(
702 std::move(operations), /* trace_id = */ 0,
703 base::BindOnce(&CacheStorageCacheTest::VerboseErrorTypeCallback,
704 base::Unretained(this), base::Unretained(loop.get())),
705 base::BindOnce(&OnBadMessage, base::Unretained(&bad_message_reason_)));
706 // TODO(jkarlin): These functions should use base::RunLoop().RunUntilIdle()
707 // once the cache uses a passed in task runner instead of the CACHE thread.
708 loop->Run();
709
710 return callback_error_;
711 }
712
CheckOpHistograms(base::HistogramTester & histogram_tester,const char * op_name)713 void CheckOpHistograms(base::HistogramTester& histogram_tester,
714 const char* op_name) {
715 std::string base("ServiceWorkerCache.Cache.Scheduler.");
716 histogram_tester.ExpectTotalCount(base + "OperationDuration2." + op_name,
717 1);
718 histogram_tester.ExpectTotalCount(base + "QueueDuration2." + op_name, 1);
719 histogram_tester.ExpectTotalCount(base + "QueueLength." + op_name, 1);
720 }
721
Put(const blink::mojom::FetchAPIRequestPtr & request,blink::mojom::FetchAPIResponsePtr response)722 bool Put(const blink::mojom::FetchAPIRequestPtr& request,
723 blink::mojom::FetchAPIResponsePtr response) {
724 base::HistogramTester histogram_tester;
725 blink::mojom::BatchOperationPtr operation =
726 blink::mojom::BatchOperation::New();
727 operation->operation_type = blink::mojom::OperationType::kPut;
728 operation->request = BackgroundFetchSettledFetch::CloneRequest(request);
729 operation->response = std::move(response);
730
731 std::vector<blink::mojom::BatchOperationPtr> operations;
732 operations.emplace_back(std::move(operation));
733 CacheStorageError error = BatchOperation(std::move(operations));
734 if (callback_error_ == CacheStorageError::kSuccess)
735 CheckOpHistograms(histogram_tester, "Put");
736 return error == CacheStorageError::kSuccess;
737 }
738
Match(const blink::mojom::FetchAPIRequestPtr & request,blink::mojom::CacheQueryOptionsPtr match_options=nullptr)739 bool Match(const blink::mojom::FetchAPIRequestPtr& request,
740 blink::mojom::CacheQueryOptionsPtr match_options = nullptr) {
741 base::HistogramTester histogram_tester;
742 std::unique_ptr<base::RunLoop> loop(new base::RunLoop());
743
744 cache_->Match(
745 CopyFetchRequest(request), std::move(match_options),
746 CacheStorageSchedulerPriority::kNormal, /* trace_id = */ 0,
747 base::BindOnce(&CacheStorageCacheTest::ResponseAndErrorCallback,
748 base::Unretained(this), base::Unretained(loop.get())));
749 loop->Run();
750 if (callback_error_ == CacheStorageError::kSuccess)
751 CheckOpHistograms(histogram_tester, "Match");
752 return callback_error_ == CacheStorageError::kSuccess;
753 }
754
MatchAll(const blink::mojom::FetchAPIRequestPtr & request,blink::mojom::CacheQueryOptionsPtr match_options,std::vector<blink::mojom::FetchAPIResponsePtr> * responses)755 bool MatchAll(const blink::mojom::FetchAPIRequestPtr& request,
756 blink::mojom::CacheQueryOptionsPtr match_options,
757 std::vector<blink::mojom::FetchAPIResponsePtr>* responses) {
758 base::HistogramTester histogram_tester;
759 base::RunLoop loop;
760 cache_->MatchAll(
761 CopyFetchRequest(request), std::move(match_options),
762 /* trace_id = */ 0,
763 base::BindOnce(&CacheStorageCacheTest::ResponsesAndErrorCallback,
764 base::Unretained(this), loop.QuitClosure(), responses));
765 loop.Run();
766 if (callback_error_ == CacheStorageError::kSuccess)
767 CheckOpHistograms(histogram_tester, "MatchAll");
768 return callback_error_ == CacheStorageError::kSuccess;
769 }
770
GetAllMatchedEntries(std::vector<CacheStorageCache::CacheEntry> * cache_entries)771 bool GetAllMatchedEntries(
772 std::vector<CacheStorageCache::CacheEntry>* cache_entries) {
773 base::RunLoop loop;
774 cache_->GetAllMatchedEntries(
775 nullptr /* request */, nullptr /* options */,
776 /* trace_id = */ 0,
777 base::BindOnce(&CacheStorageCacheTest::CacheEntriesAndErrorCallback,
778 base::Unretained(this), loop.QuitClosure(),
779 cache_entries));
780 loop.Run();
781 return callback_error_ == CacheStorageError::kSuccess;
782 }
783
MatchAll(std::vector<blink::mojom::FetchAPIResponsePtr> * responses)784 bool MatchAll(std::vector<blink::mojom::FetchAPIResponsePtr>* responses) {
785 return MatchAll(blink::mojom::FetchAPIRequest::New(), nullptr, responses);
786 }
787
Delete(const blink::mojom::FetchAPIRequestPtr & request,blink::mojom::CacheQueryOptionsPtr match_options=nullptr)788 bool Delete(const blink::mojom::FetchAPIRequestPtr& request,
789 blink::mojom::CacheQueryOptionsPtr match_options = nullptr) {
790 base::HistogramTester histogram_tester;
791 blink::mojom::BatchOperationPtr operation =
792 blink::mojom::BatchOperation::New();
793 operation->operation_type = blink::mojom::OperationType::kDelete;
794 operation->request = BackgroundFetchSettledFetch::CloneRequest(request);
795 operation->match_options = std::move(match_options);
796
797 std::vector<blink::mojom::BatchOperationPtr> operations;
798 operations.emplace_back(std::move(operation));
799 CacheStorageError error = BatchOperation(std::move(operations));
800 if (callback_error_ == CacheStorageError::kSuccess)
801 CheckOpHistograms(histogram_tester, "Delete");
802 return error == CacheStorageError::kSuccess;
803 }
804
Keys(const blink::mojom::FetchAPIRequestPtr & request=blink::mojom::FetchAPIRequest::New (),blink::mojom::CacheQueryOptionsPtr match_options=nullptr)805 bool Keys(const blink::mojom::FetchAPIRequestPtr& request =
806 blink::mojom::FetchAPIRequest::New(),
807 blink::mojom::CacheQueryOptionsPtr match_options = nullptr) {
808 base::HistogramTester histogram_tester;
809 std::unique_ptr<base::RunLoop> loop(new base::RunLoop());
810
811 cache_->Keys(
812 CopyFetchRequest(request), std::move(match_options),
813 /* trace_id = */ 0,
814 base::BindOnce(&CacheStorageCacheTest::RequestsCallback,
815 base::Unretained(this), base::Unretained(loop.get())));
816 loop->Run();
817 if (callback_error_ == CacheStorageError::kSuccess)
818 CheckOpHistograms(histogram_tester, "Keys");
819 return callback_error_ == CacheStorageError::kSuccess;
820 }
821
Close()822 bool Close() {
823 base::HistogramTester histogram_tester;
824 std::unique_ptr<base::RunLoop> loop(new base::RunLoop());
825
826 cache_->Close(base::BindOnce(&CacheStorageCacheTest::CloseCallback,
827 base::Unretained(this),
828 base::Unretained(loop.get())));
829 loop->Run();
830 if (callback_error_ == CacheStorageError::kSuccess)
831 CheckOpHistograms(histogram_tester, "Close");
832 return callback_closed_;
833 }
834
WriteSideData(const GURL & url,base::Time expected_response_time,scoped_refptr<net::IOBuffer> buffer,int buf_len)835 bool WriteSideData(const GURL& url,
836 base::Time expected_response_time,
837 scoped_refptr<net::IOBuffer> buffer,
838 int buf_len) {
839 base::HistogramTester histogram_tester;
840 base::RunLoop run_loop;
841 cache_->WriteSideData(
842 base::BindOnce(&CacheStorageCacheTest::ErrorTypeCallback,
843 base::Unretained(this), base::Unretained(&run_loop)),
844 url, expected_response_time, /* trace_id = */ 0, buffer, buf_len);
845 run_loop.Run();
846 if (callback_error_ == CacheStorageError::kSuccess)
847 CheckOpHistograms(histogram_tester, "WriteSideData");
848 return callback_error_ == CacheStorageError::kSuccess;
849 }
850
Size()851 int64_t Size() {
852 base::HistogramTester histogram_tester;
853 // Storage notification happens after an operation completes. Let the any
854 // notifications complete before calling Size.
855 base::RunLoop().RunUntilIdle();
856
857 base::RunLoop run_loop;
858 bool callback_called = false;
859 int64_t result = 0;
860 cache_->Size(
861 base::BindOnce(&SizeCallback, &run_loop, &callback_called, &result));
862 run_loop.Run();
863 EXPECT_TRUE(callback_called);
864 if (callback_error_ == CacheStorageError::kSuccess)
865 CheckOpHistograms(histogram_tester, "Size");
866 return result;
867 }
868
GetSizeThenClose()869 int64_t GetSizeThenClose() {
870 base::HistogramTester histogram_tester;
871 base::RunLoop run_loop;
872 bool callback_called = false;
873 int64_t result = 0;
874 cache_->GetSizeThenClose(
875 base::BindOnce(&SizeCallback, &run_loop, &callback_called, &result));
876 run_loop.Run();
877 EXPECT_TRUE(callback_called);
878 if (callback_error_ == CacheStorageError::kSuccess)
879 CheckOpHistograms(histogram_tester, "SizeThenClose");
880 return result;
881 }
882
RequestsCallback(base::RunLoop * run_loop,CacheStorageError error,std::unique_ptr<CacheStorageCache::Requests> requests)883 void RequestsCallback(base::RunLoop* run_loop,
884 CacheStorageError error,
885 std::unique_ptr<CacheStorageCache::Requests> requests) {
886 callback_error_ = error;
887 callback_strings_.clear();
888 if (requests) {
889 for (const blink::mojom::FetchAPIRequestPtr& request : *requests)
890 callback_strings_.push_back(request->url.spec());
891 }
892 if (run_loop)
893 run_loop->Quit();
894 }
895
VerboseErrorTypeCallback(base::RunLoop * run_loop,CacheStorageVerboseErrorPtr error)896 void VerboseErrorTypeCallback(base::RunLoop* run_loop,
897 CacheStorageVerboseErrorPtr error) {
898 ErrorTypeCallback(run_loop, error->value);
899 callback_message_ = error->message;
900 }
901
ErrorTypeCallback(base::RunLoop * run_loop,CacheStorageError error)902 void ErrorTypeCallback(base::RunLoop* run_loop, CacheStorageError error) {
903 callback_message_ = base::nullopt;
904 callback_error_ = error;
905 if (run_loop)
906 run_loop->Quit();
907 }
908
SequenceCallback(int sequence,int * sequence_out,base::RunLoop * run_loop,CacheStorageVerboseErrorPtr error)909 void SequenceCallback(int sequence,
910 int* sequence_out,
911 base::RunLoop* run_loop,
912 CacheStorageVerboseErrorPtr error) {
913 *sequence_out = sequence;
914 callback_error_ = error->value;
915 if (run_loop)
916 run_loop->Quit();
917 }
918
ResponseAndErrorCallback(base::RunLoop * run_loop,CacheStorageError error,blink::mojom::FetchAPIResponsePtr response)919 void ResponseAndErrorCallback(base::RunLoop* run_loop,
920 CacheStorageError error,
921 blink::mojom::FetchAPIResponsePtr response) {
922 callback_error_ = error;
923 callback_response_ = std::move(response);
924
925 if (run_loop)
926 run_loop->Quit();
927 }
928
ResponsesAndErrorCallback(base::OnceClosure quit_closure,std::vector<blink::mojom::FetchAPIResponsePtr> * responses_out,CacheStorageError error,std::vector<blink::mojom::FetchAPIResponsePtr> responses)929 void ResponsesAndErrorCallback(
930 base::OnceClosure quit_closure,
931 std::vector<blink::mojom::FetchAPIResponsePtr>* responses_out,
932 CacheStorageError error,
933 std::vector<blink::mojom::FetchAPIResponsePtr> responses) {
934 callback_error_ = error;
935 *responses_out = std::move(responses);
936 std::move(quit_closure).Run();
937 }
938
CacheEntriesAndErrorCallback(base::OnceClosure quit_closure,std::vector<CacheStorageCache::CacheEntry> * cache_entries_out,CacheStorageError error,std::vector<CacheStorageCache::CacheEntry> cache_entries)939 void CacheEntriesAndErrorCallback(
940 base::OnceClosure quit_closure,
941 std::vector<CacheStorageCache::CacheEntry>* cache_entries_out,
942 CacheStorageError error,
943 std::vector<CacheStorageCache::CacheEntry> cache_entries) {
944 callback_error_ = error;
945 *cache_entries_out = std::move(cache_entries);
946 std::move(quit_closure).Run();
947 }
948
CloseCallback(base::RunLoop * run_loop)949 void CloseCallback(base::RunLoop* run_loop) {
950 EXPECT_FALSE(callback_closed_);
951 callback_closed_ = true;
952 if (run_loop)
953 run_loop->Quit();
954 }
955
TestResponseType(network::mojom::FetchResponseType response_type)956 bool TestResponseType(network::mojom::FetchResponseType response_type) {
957 blink::mojom::FetchAPIResponsePtr body_response = CreateBlobBodyResponse();
958 body_response->response_type = response_type;
959 EXPECT_TRUE(Put(body_request_, std::move(body_response)));
960 EXPECT_TRUE(Match(body_request_));
961 EXPECT_TRUE(Delete(body_request_));
962 return response_type == callback_response_->response_type;
963 }
964
VerifyAllOpsFail()965 void VerifyAllOpsFail() {
966 EXPECT_FALSE(Put(no_body_request_, CreateNoBodyResponse()));
967 EXPECT_FALSE(Match(no_body_request_));
968 EXPECT_FALSE(Delete(body_request_));
969 EXPECT_FALSE(Keys());
970 }
971
MemoryOnly()972 virtual bool MemoryOnly() { return false; }
973
SetQuota(uint64_t quota)974 void SetQuota(uint64_t quota) {
975 mock_quota_manager_->SetQuota(url::Origin::Create(kTestUrl),
976 blink::mojom::StorageType::kTemporary, quota);
977 }
978
SetMaxQuerySizeBytes(size_t max_bytes)979 void SetMaxQuerySizeBytes(size_t max_bytes) {
980 cache_->max_query_size_bytes_ = max_bytes;
981 }
982
EstimatedResponseSizeWithoutBlob(const blink::mojom::FetchAPIResponse & response)983 size_t EstimatedResponseSizeWithoutBlob(
984 const blink::mojom::FetchAPIResponse& response) {
985 return LegacyCacheStorageCache::EstimatedResponseSizeWithoutBlob(response);
986 }
987
988 protected:
989 base::ScopedTempDir temp_dir_;
990 BrowserTaskEnvironment task_environment_;
991 TestBrowserContext browser_context_;
992 scoped_refptr<storage::MockSpecialStoragePolicy> quota_policy_;
993 scoped_refptr<storage::MockQuotaManager> mock_quota_manager_;
994 scoped_refptr<storage::MockQuotaManagerProxy> quota_manager_proxy_;
995 scoped_refptr<BlobStorageContextWrapper> blob_storage_context_;
996 std::unique_ptr<MockLegacyCacheStorage> mock_cache_storage_;
997
998 base::FilePath temp_dir_path_;
999 std::unique_ptr<TestCacheStorageCache> cache_;
1000
1001 blink::mojom::FetchAPIRequestPtr body_request_;
1002 blink::mojom::FetchAPIRequestPtr body_request_with_query_;
1003 blink::mojom::FetchAPIRequestPtr no_body_request_;
1004 blink::mojom::FetchAPIRequestPtr body_head_request_;
1005 std::string expected_blob_uuid_ = "blob-id:myblob";
1006 // Holds a Mojo connection to the BlobImpl with uuid |expected_blob_uuid_|.
1007 mojo::Remote<blink::mojom::Blob> blob_remote_;
1008 base::Time response_time_;
1009 std::string expected_blob_data_;
1010
1011 CacheStorageError callback_error_ = CacheStorageError::kSuccess;
1012 base::Optional<std::string> callback_message_ = base::nullopt;
1013 blink::mojom::FetchAPIResponsePtr callback_response_;
1014 std::vector<std::string> callback_strings_;
1015 std::string bad_message_reason_;
1016 bool callback_closed_ = false;
1017
1018 private:
1019 const GURL kTestUrl{"http://example.com"};
1020 };
1021
1022 class CacheStorageCacheTestP : public CacheStorageCacheTest,
1023 public testing::WithParamInterface<bool> {
1024 public:
MemoryOnly()1025 bool MemoryOnly() override { return !GetParam(); }
1026 };
1027
TEST_P(CacheStorageCacheTestP,PutNoBody)1028 TEST_P(CacheStorageCacheTestP, PutNoBody) {
1029 EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
1030 }
1031
TEST_P(CacheStorageCacheTestP,PutBody)1032 TEST_P(CacheStorageCacheTestP, PutBody) {
1033 EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
1034 }
1035
TEST_P(CacheStorageCacheTestP,PutBody_Multiple)1036 TEST_P(CacheStorageCacheTestP, PutBody_Multiple) {
1037 blink::mojom::BatchOperationPtr operation1 =
1038 blink::mojom::BatchOperation::New();
1039 operation1->operation_type = blink::mojom::OperationType::kPut;
1040 operation1->request =
1041 BackgroundFetchSettledFetch::CloneRequest(body_request_);
1042 operation1->request->url = GURL("http://example.com/1");
1043 operation1->response = CreateBlobBodyResponse();
1044 operation1->response->url_list.emplace_back("http://example.com/1");
1045 blink::mojom::FetchAPIRequestPtr request1 =
1046 BackgroundFetchSettledFetch::CloneRequest(operation1->request);
1047
1048 blink::mojom::BatchOperationPtr operation2 =
1049 blink::mojom::BatchOperation::New();
1050 operation2->operation_type = blink::mojom::OperationType::kPut;
1051 operation2->request =
1052 BackgroundFetchSettledFetch::CloneRequest(body_request_);
1053 operation2->request->url = GURL("http://example.com/2");
1054 operation2->response = CreateBlobBodyResponse();
1055 operation2->response->url_list.emplace_back("http://example.com/2");
1056 blink::mojom::FetchAPIRequestPtr request2 =
1057 BackgroundFetchSettledFetch::CloneRequest(operation2->request);
1058
1059 blink::mojom::BatchOperationPtr operation3 =
1060 blink::mojom::BatchOperation::New();
1061 operation3->operation_type = blink::mojom::OperationType::kPut;
1062 operation3->request =
1063 BackgroundFetchSettledFetch::CloneRequest(body_request_);
1064 operation3->request->url = GURL("http://example.com/3");
1065 operation3->response = CreateBlobBodyResponse();
1066 operation3->response->url_list.emplace_back("http://example.com/3");
1067 blink::mojom::FetchAPIRequestPtr request3 =
1068 BackgroundFetchSettledFetch::CloneRequest(operation3->request);
1069
1070 std::vector<blink::mojom::BatchOperationPtr> operations;
1071 operations.push_back(std::move(operation1));
1072 operations.push_back(std::move(operation2));
1073 operations.push_back(std::move(operation3));
1074
1075 EXPECT_EQ(CacheStorageError::kSuccess, BatchOperation(std::move(operations)));
1076 EXPECT_TRUE(Match(request1));
1077 EXPECT_TRUE(Match(request2));
1078 EXPECT_TRUE(Match(request3));
1079 }
1080
TEST_P(CacheStorageCacheTestP,MatchLimit)1081 TEST_P(CacheStorageCacheTestP, MatchLimit) {
1082 EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
1083 EXPECT_TRUE(Match(no_body_request_));
1084
1085 size_t max_size =
1086 LegacyCacheStorageCache::EstimatedStructSize(no_body_request_) +
1087 EstimatedResponseSizeWithoutBlob(*callback_response_);
1088 SetMaxQuerySizeBytes(max_size);
1089 EXPECT_TRUE(Match(no_body_request_));
1090
1091 SetMaxQuerySizeBytes(max_size - 1);
1092 EXPECT_FALSE(Match(no_body_request_));
1093 EXPECT_EQ(CacheStorageError::kErrorQueryTooLarge, callback_error_);
1094 }
1095
TEST_P(CacheStorageCacheTestP,MatchAllLimit)1096 TEST_P(CacheStorageCacheTestP, MatchAllLimit) {
1097 EXPECT_TRUE(Put(body_request_, CreateNoBodyResponse()));
1098 EXPECT_TRUE(Put(body_request_with_query_, CreateNoBodyResponse()));
1099 EXPECT_TRUE(Match(body_request_));
1100
1101 size_t body_request_size =
1102 LegacyCacheStorageCache::EstimatedStructSize(body_request_) +
1103 EstimatedResponseSizeWithoutBlob(*callback_response_);
1104 size_t query_request_size =
1105 LegacyCacheStorageCache::EstimatedStructSize(body_request_with_query_) +
1106 EstimatedResponseSizeWithoutBlob(*callback_response_);
1107
1108 std::vector<blink::mojom::FetchAPIResponsePtr> responses;
1109 blink::mojom::CacheQueryOptionsPtr match_options =
1110 blink::mojom::CacheQueryOptions::New();
1111
1112 // There is enough room for both requests and responses
1113 SetMaxQuerySizeBytes(body_request_size + query_request_size);
1114 EXPECT_TRUE(MatchAll(body_request_, match_options->Clone(), &responses));
1115 EXPECT_EQ(1u, responses.size());
1116
1117 match_options->ignore_search = true;
1118 EXPECT_TRUE(MatchAll(body_request_, match_options->Clone(), &responses));
1119 EXPECT_EQ(2u, responses.size());
1120
1121 // There is not enough room for both requests and responses
1122 SetMaxQuerySizeBytes(body_request_size);
1123 match_options->ignore_search = false;
1124 EXPECT_TRUE(MatchAll(body_request_, match_options->Clone(), &responses));
1125 EXPECT_EQ(1u, responses.size());
1126
1127 match_options->ignore_search = true;
1128 EXPECT_FALSE(MatchAll(body_request_, match_options->Clone(), &responses));
1129 EXPECT_EQ(CacheStorageError::kErrorQueryTooLarge, callback_error_);
1130 }
1131
TEST_P(CacheStorageCacheTestP,KeysLimit)1132 TEST_P(CacheStorageCacheTestP, KeysLimit) {
1133 EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
1134 EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
1135
1136 size_t max_size =
1137 LegacyCacheStorageCache::EstimatedStructSize(no_body_request_) +
1138 LegacyCacheStorageCache::EstimatedStructSize(body_request_);
1139 SetMaxQuerySizeBytes(max_size);
1140 EXPECT_TRUE(Keys());
1141
1142 SetMaxQuerySizeBytes(
1143 LegacyCacheStorageCache::EstimatedStructSize(no_body_request_));
1144 EXPECT_FALSE(Keys());
1145 EXPECT_EQ(CacheStorageError::kErrorQueryTooLarge, callback_error_);
1146 }
1147
1148 // TODO(nhiroki): Add a test for the case where one of PUT operations fails.
1149 // Currently there is no handy way to fail only one operation in a batch.
1150 // This could be easily achieved after adding some security checks in the
1151 // browser side (http://crbug.com/425505).
1152
TEST_P(CacheStorageCacheTestP,ResponseURLDiffersFromRequestURL)1153 TEST_P(CacheStorageCacheTestP, ResponseURLDiffersFromRequestURL) {
1154 blink::mojom::FetchAPIResponsePtr no_body_response = CreateNoBodyResponse();
1155 no_body_response->url_list.clear();
1156 no_body_response->url_list.emplace_back("http://example.com/foobar");
1157 EXPECT_STRNE("http://example.com/foobar",
1158 no_body_request_->url.spec().c_str());
1159 EXPECT_TRUE(Put(no_body_request_, std::move(no_body_response)));
1160 EXPECT_TRUE(Match(no_body_request_));
1161 ASSERT_EQ(1u, callback_response_->url_list.size());
1162 EXPECT_STREQ("http://example.com/foobar",
1163 callback_response_->url_list[0].spec().c_str());
1164 }
1165
TEST_P(CacheStorageCacheTestP,ResponseURLEmpty)1166 TEST_P(CacheStorageCacheTestP, ResponseURLEmpty) {
1167 blink::mojom::FetchAPIResponsePtr no_body_response = CreateNoBodyResponse();
1168 no_body_response->url_list.clear();
1169 EXPECT_STRNE("", no_body_request_->url.spec().c_str());
1170 EXPECT_TRUE(Put(no_body_request_, std::move(no_body_response)));
1171 EXPECT_TRUE(Match(no_body_request_));
1172 EXPECT_EQ(0u, callback_response_->url_list.size());
1173 }
1174
TEST_P(CacheStorageCacheTestP,PutBodyDropBlobRef)1175 TEST_P(CacheStorageCacheTestP, PutBodyDropBlobRef) {
1176 blink::mojom::BatchOperationPtr operation =
1177 blink::mojom::BatchOperation::New();
1178 operation->operation_type = blink::mojom::OperationType::kPut;
1179 operation->request = BackgroundFetchSettledFetch::CloneRequest(body_request_);
1180 operation->response = CreateBlobBodyResponse();
1181
1182 std::vector<blink::mojom::BatchOperationPtr> operations;
1183 operations.emplace_back(std::move(operation));
1184 std::unique_ptr<base::RunLoop> loop(new base::RunLoop());
1185 cache_->BatchOperation(
1186 std::move(operations), /* trace_id = */ 0,
1187 base::BindOnce(&CacheStorageCacheTestP::VerboseErrorTypeCallback,
1188 base::Unretained(this), base::Unretained(loop.get())),
1189 CacheStorageCache::BadMessageCallback());
1190
1191 // The handle should be held by the cache now so the deref here should be
1192 // okay.
1193 blob_remote_.reset();
1194
1195 loop->Run();
1196
1197 EXPECT_EQ(CacheStorageError::kSuccess, callback_error_);
1198 }
1199
TEST_P(CacheStorageCacheTestP,PutBadMessage)1200 TEST_P(CacheStorageCacheTestP, PutBadMessage) {
1201 base::HistogramTester histogram_tester;
1202
1203 // Two unique puts that will collectively overflow unit64_t size of the
1204 // batch operation.
1205 blink::mojom::BatchOperationPtr operation1 =
1206 blink::mojom::BatchOperation::New(
1207 blink::mojom::OperationType::kPut,
1208 BackgroundFetchSettledFetch::CloneRequest(body_request_),
1209 CreateBlobBodyResponse(), nullptr /* match_options */);
1210 operation1->response->blob->size = std::numeric_limits<uint64_t>::max();
1211 blink::mojom::BatchOperationPtr operation2 =
1212 blink::mojom::BatchOperation::New(
1213 blink::mojom::OperationType::kPut,
1214 BackgroundFetchSettledFetch::CloneRequest(body_request_with_query_),
1215 CreateBlobBodyResponse(), nullptr /* match_options */);
1216 operation2->response->blob->size = std::numeric_limits<uint64_t>::max();
1217
1218 std::vector<blink::mojom::BatchOperationPtr> operations;
1219 operations.push_back(std::move(operation1));
1220 operations.push_back(std::move(operation2));
1221 EXPECT_EQ(CacheStorageError::kErrorStorage,
1222 BatchOperation(std::move(operations)));
1223 histogram_tester.ExpectBucketCount("ServiceWorkerCache.ErrorStorageType",
1224 ErrorStorageType::kBatchInvalidSpace, 1);
1225 EXPECT_EQ("CSDH_UNEXPECTED_OPERATION", bad_message_reason_);
1226
1227 EXPECT_FALSE(Match(body_request_));
1228 }
1229
TEST_P(CacheStorageCacheTestP,PutReplace)1230 TEST_P(CacheStorageCacheTestP, PutReplace) {
1231 EXPECT_TRUE(Put(body_request_, CreateNoBodyResponse()));
1232 EXPECT_TRUE(Match(body_request_));
1233 EXPECT_FALSE(callback_response_->blob);
1234
1235 EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
1236 EXPECT_TRUE(Match(body_request_));
1237 EXPECT_TRUE(callback_response_->blob);
1238
1239 EXPECT_TRUE(Put(body_request_, CreateNoBodyResponse()));
1240 EXPECT_TRUE(Match(body_request_));
1241 EXPECT_FALSE(callback_response_->blob);
1242 }
1243
TEST_P(CacheStorageCacheTestP,PutReplaceInBatchFails)1244 TEST_P(CacheStorageCacheTestP, PutReplaceInBatchFails) {
1245 blink::mojom::BatchOperationPtr operation1 =
1246 blink::mojom::BatchOperation::New();
1247 operation1->operation_type = blink::mojom::OperationType::kPut;
1248 operation1->request =
1249 BackgroundFetchSettledFetch::CloneRequest(body_request_);
1250 operation1->response = CreateNoBodyResponse();
1251
1252 blink::mojom::BatchOperationPtr operation2 =
1253 blink::mojom::BatchOperation::New();
1254 operation2->operation_type = blink::mojom::OperationType::kPut;
1255 operation2->request =
1256 BackgroundFetchSettledFetch::CloneRequest(body_request_);
1257 operation2->response = CreateBlobBodyResponse();
1258
1259 std::vector<blink::mojom::BatchOperationPtr> operations;
1260 operations.push_back(std::move(operation1));
1261 operations.push_back(std::move(operation2));
1262
1263 EXPECT_EQ(CacheStorageError::kErrorDuplicateOperation,
1264 BatchOperation(std::move(operations)));
1265
1266 // A duplicate operation error should provide an informative message
1267 // containing the URL of the duplicate request.
1268 ASSERT_TRUE(callback_message_);
1269 EXPECT_NE(std::string::npos,
1270 callback_message_.value().find(BodyUrl().spec()));
1271
1272 // Neither operation should have completed.
1273 EXPECT_FALSE(Match(body_request_));
1274 }
1275
TEST_P(CacheStorageCacheTestP,MatchNoBody)1276 TEST_P(CacheStorageCacheTestP, MatchNoBody) {
1277 EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
1278 EXPECT_TRUE(Match(no_body_request_));
1279 EXPECT_TRUE(ResponseMetadataEqual(*SetCacheName(CreateNoBodyResponse()),
1280 *callback_response_));
1281 EXPECT_FALSE(callback_response_->blob);
1282 }
1283
TEST_P(CacheStorageCacheTestP,MatchBody)1284 TEST_P(CacheStorageCacheTestP, MatchBody) {
1285 EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
1286 EXPECT_TRUE(Match(body_request_));
1287 EXPECT_TRUE(ResponseMetadataEqual(*SetCacheName(CreateBlobBodyResponse()),
1288 *callback_response_));
1289 mojo::Remote<blink::mojom::Blob> blob(
1290 std::move(callback_response_->blob->blob));
1291 EXPECT_EQ(expected_blob_data_, storage::BlobToString(blob.get()));
1292 }
1293
TEST_P(CacheStorageCacheTestP,MatchBodyHead)1294 TEST_P(CacheStorageCacheTestP, MatchBodyHead) {
1295 EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
1296 EXPECT_FALSE(Match(body_head_request_));
1297 }
1298
TEST_P(CacheStorageCacheTestP,MatchAll_Empty)1299 TEST_P(CacheStorageCacheTestP, MatchAll_Empty) {
1300 std::vector<blink::mojom::FetchAPIResponsePtr> responses;
1301 EXPECT_TRUE(MatchAll(&responses));
1302 EXPECT_TRUE(responses.empty());
1303 }
1304
TEST_P(CacheStorageCacheTestP,MatchAll_NoBody)1305 TEST_P(CacheStorageCacheTestP, MatchAll_NoBody) {
1306 EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
1307
1308 std::vector<blink::mojom::FetchAPIResponsePtr> responses;
1309 EXPECT_TRUE(MatchAll(&responses));
1310
1311 ASSERT_EQ(1u, responses.size());
1312 EXPECT_TRUE(ResponseMetadataEqual(*SetCacheName(CreateNoBodyResponse()),
1313 *responses[0]));
1314 EXPECT_FALSE(responses[0]->blob);
1315 }
1316
TEST_P(CacheStorageCacheTestP,MatchAll_Body)1317 TEST_P(CacheStorageCacheTestP, MatchAll_Body) {
1318 EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
1319
1320 std::vector<blink::mojom::FetchAPIResponsePtr> responses;
1321 EXPECT_TRUE(MatchAll(&responses));
1322
1323 ASSERT_EQ(1u, responses.size());
1324 EXPECT_TRUE(ResponseMetadataEqual(*SetCacheName(CreateBlobBodyResponse()),
1325 *responses[0]));
1326 mojo::Remote<blink::mojom::Blob> blob(std::move(responses[0]->blob->blob));
1327 EXPECT_EQ(expected_blob_data_, storage::BlobToString(blob.get()));
1328 }
1329
TEST_P(CacheStorageCacheTestP,MatchAll_TwoResponsesThenOne)1330 TEST_P(CacheStorageCacheTestP, MatchAll_TwoResponsesThenOne) {
1331 EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
1332 EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
1333
1334 std::vector<blink::mojom::FetchAPIResponsePtr> responses;
1335 EXPECT_TRUE(MatchAll(&responses));
1336 ASSERT_EQ(2u, responses.size());
1337 EXPECT_TRUE(responses[1]->blob);
1338
1339 EXPECT_TRUE(ResponseMetadataEqual(*SetCacheName(CreateNoBodyResponse()),
1340 *responses[0]));
1341 EXPECT_FALSE(responses[0]->blob);
1342 EXPECT_TRUE(ResponseMetadataEqual(*SetCacheName(CreateBlobBodyResponse()),
1343 *responses[1]));
1344 mojo::Remote<blink::mojom::Blob> blob(std::move(responses[1]->blob->blob));
1345 EXPECT_EQ(expected_blob_data_, storage::BlobToString(blob.get()));
1346
1347 responses.clear();
1348
1349 EXPECT_TRUE(Delete(body_request_));
1350 EXPECT_TRUE(MatchAll(&responses));
1351
1352 ASSERT_EQ(1u, responses.size());
1353 EXPECT_TRUE(ResponseMetadataEqual(*SetCacheName(CreateNoBodyResponse()),
1354 *responses[0]));
1355 EXPECT_FALSE(responses[0]->blob);
1356 }
1357
TEST_P(CacheStorageCacheTestP,Match_IgnoreSearch)1358 TEST_P(CacheStorageCacheTestP, Match_IgnoreSearch) {
1359 EXPECT_TRUE(Put(body_request_with_query_, CreateBlobBodyResponseWithQuery()));
1360
1361 EXPECT_FALSE(Match(body_request_));
1362 blink::mojom::CacheQueryOptionsPtr match_options =
1363 blink::mojom::CacheQueryOptions::New();
1364 match_options->ignore_search = true;
1365 EXPECT_TRUE(Match(body_request_, std::move(match_options)));
1366 }
1367
TEST_P(CacheStorageCacheTestP,Match_IgnoreMethod)1368 TEST_P(CacheStorageCacheTestP, Match_IgnoreMethod) {
1369 EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
1370
1371 blink::mojom::FetchAPIRequestPtr post_request =
1372 BackgroundFetchSettledFetch::CloneRequest(body_request_);
1373 post_request->method = "POST";
1374 EXPECT_FALSE(Match(post_request));
1375
1376 blink::mojom::CacheQueryOptionsPtr match_options =
1377 blink::mojom::CacheQueryOptions::New();
1378 match_options->ignore_method = true;
1379 EXPECT_TRUE(Match(post_request, std::move(match_options)));
1380 }
1381
TEST_P(CacheStorageCacheTestP,Match_IgnoreVary)1382 TEST_P(CacheStorageCacheTestP, Match_IgnoreVary) {
1383 body_request_->headers["vary_foo"] = "foo";
1384 blink::mojom::FetchAPIResponsePtr body_response = CreateBlobBodyResponse();
1385 body_response->headers["vary"] = "vary_foo";
1386 EXPECT_TRUE(Put(body_request_, std::move(body_response)));
1387 EXPECT_TRUE(Match(body_request_));
1388
1389 body_request_->headers["vary_foo"] = "bar";
1390 EXPECT_FALSE(Match(body_request_));
1391
1392 blink::mojom::CacheQueryOptionsPtr match_options =
1393 blink::mojom::CacheQueryOptions::New();
1394 match_options->ignore_vary = true;
1395 EXPECT_TRUE(Match(body_request_, std::move(match_options)));
1396 }
1397
TEST_P(CacheStorageCacheTestP,GetAllMatchedEntries_RequestsIncluded)1398 TEST_P(CacheStorageCacheTestP, GetAllMatchedEntries_RequestsIncluded) {
1399 EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
1400
1401 std::vector<LegacyCacheStorageCache::CacheEntry> cache_entries;
1402 EXPECT_TRUE(GetAllMatchedEntries(&cache_entries));
1403
1404 ASSERT_EQ(1u, cache_entries.size());
1405 const auto& request = cache_entries[0].first;
1406 EXPECT_EQ(request->url, body_request_->url);
1407 EXPECT_EQ(request->headers, body_request_->headers);
1408 EXPECT_EQ(request->method, body_request_->method);
1409
1410 auto& response = cache_entries[0].second;
1411 EXPECT_TRUE(ResponseMetadataEqual(*SetCacheName(CreateBlobBodyResponse()),
1412 *response));
1413 mojo::Remote<blink::mojom::Blob> blob(std::move(response->blob->blob));
1414 EXPECT_EQ(expected_blob_data_, storage::BlobToString(blob.get()));
1415 }
1416
TEST_P(CacheStorageCacheTestP,Keys_IgnoreSearch)1417 TEST_P(CacheStorageCacheTestP, Keys_IgnoreSearch) {
1418 EXPECT_TRUE(Put(body_request_with_query_, CreateBlobBodyResponseWithQuery()));
1419
1420 EXPECT_TRUE(Keys(body_request_));
1421 EXPECT_EQ(0u, callback_strings_.size());
1422
1423 blink::mojom::CacheQueryOptionsPtr match_options =
1424 blink::mojom::CacheQueryOptions::New();
1425 match_options->ignore_search = true;
1426 EXPECT_TRUE(Keys(body_request_, std::move(match_options)));
1427 EXPECT_EQ(1u, callback_strings_.size());
1428 }
1429
TEST_P(CacheStorageCacheTestP,Keys_IgnoreMethod)1430 TEST_P(CacheStorageCacheTestP, Keys_IgnoreMethod) {
1431 EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
1432
1433 blink::mojom::FetchAPIRequestPtr post_request =
1434 BackgroundFetchSettledFetch::CloneRequest(body_request_);
1435 post_request->method = "POST";
1436 EXPECT_TRUE(Keys(post_request));
1437 EXPECT_EQ(0u, callback_strings_.size());
1438
1439 blink::mojom::CacheQueryOptionsPtr match_options =
1440 blink::mojom::CacheQueryOptions::New();
1441 match_options->ignore_method = true;
1442 EXPECT_TRUE(Keys(post_request, std::move(match_options)));
1443 EXPECT_EQ(1u, callback_strings_.size());
1444 }
1445
TEST_P(CacheStorageCacheTestP,Keys_IgnoreVary)1446 TEST_P(CacheStorageCacheTestP, Keys_IgnoreVary) {
1447 body_request_->headers["vary_foo"] = "foo";
1448 blink::mojom::FetchAPIResponsePtr body_response = CreateBlobBodyResponse();
1449 body_response->headers["vary"] = "vary_foo";
1450 EXPECT_TRUE(Put(body_request_, std::move(body_response)));
1451 EXPECT_TRUE(Keys(body_request_));
1452 EXPECT_EQ(1u, callback_strings_.size());
1453
1454 body_request_->headers["vary_foo"] = "bar";
1455 EXPECT_TRUE(Keys(body_request_));
1456 EXPECT_EQ(0u, callback_strings_.size());
1457
1458 blink::mojom::CacheQueryOptionsPtr match_options =
1459 blink::mojom::CacheQueryOptions::New();
1460 match_options->ignore_vary = true;
1461 EXPECT_TRUE(Keys(body_request_, std::move(match_options)));
1462 EXPECT_EQ(1u, callback_strings_.size());
1463 }
1464
TEST_P(CacheStorageCacheTestP,Delete_IgnoreSearch)1465 TEST_P(CacheStorageCacheTestP, Delete_IgnoreSearch) {
1466 EXPECT_TRUE(Put(body_request_with_query_, CreateBlobBodyResponseWithQuery()));
1467
1468 EXPECT_FALSE(Delete(body_request_));
1469 blink::mojom::CacheQueryOptionsPtr match_options =
1470 blink::mojom::CacheQueryOptions::New();
1471 match_options->ignore_search = true;
1472 EXPECT_TRUE(Delete(body_request_, std::move(match_options)));
1473 }
1474
TEST_P(CacheStorageCacheTestP,Delete_IgnoreMethod)1475 TEST_P(CacheStorageCacheTestP, Delete_IgnoreMethod) {
1476 EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
1477
1478 blink::mojom::FetchAPIRequestPtr post_request =
1479 BackgroundFetchSettledFetch::CloneRequest(body_request_);
1480 post_request->method = "POST";
1481 EXPECT_FALSE(Delete(post_request));
1482
1483 blink::mojom::CacheQueryOptionsPtr match_options =
1484 blink::mojom::CacheQueryOptions::New();
1485 match_options->ignore_method = true;
1486 EXPECT_TRUE(Delete(post_request, std::move(match_options)));
1487 }
1488
TEST_P(CacheStorageCacheTestP,Delete_IgnoreVary)1489 TEST_P(CacheStorageCacheTestP, Delete_IgnoreVary) {
1490 body_request_->headers["vary_foo"] = "foo";
1491 blink::mojom::FetchAPIResponsePtr body_response = CreateBlobBodyResponse();
1492 body_response->headers["vary"] = "vary_foo";
1493 EXPECT_TRUE(Put(body_request_, std::move(body_response)));
1494
1495 body_request_->headers["vary_foo"] = "bar";
1496 EXPECT_FALSE(Delete(body_request_));
1497
1498 blink::mojom::CacheQueryOptionsPtr match_options =
1499 blink::mojom::CacheQueryOptions::New();
1500 match_options->ignore_vary = true;
1501 EXPECT_TRUE(Delete(body_request_, std::move(match_options)));
1502 }
1503
TEST_P(CacheStorageCacheTestP,MatchAll_IgnoreMethod)1504 TEST_P(CacheStorageCacheTestP, MatchAll_IgnoreMethod) {
1505 EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
1506
1507 blink::mojom::FetchAPIRequestPtr post_request =
1508 BackgroundFetchSettledFetch::CloneRequest(body_request_);
1509 post_request->method = "POST";
1510 std::vector<blink::mojom::FetchAPIResponsePtr> responses;
1511
1512 EXPECT_TRUE(MatchAll(post_request, nullptr, &responses));
1513 EXPECT_EQ(0u, responses.size());
1514
1515 blink::mojom::CacheQueryOptionsPtr match_options =
1516 blink::mojom::CacheQueryOptions::New();
1517 match_options->ignore_method = true;
1518 EXPECT_TRUE(MatchAll(post_request, std::move(match_options), &responses));
1519 EXPECT_EQ(1u, responses.size());
1520 }
1521
TEST_P(CacheStorageCacheTestP,MatchAll_IgnoreVary)1522 TEST_P(CacheStorageCacheTestP, MatchAll_IgnoreVary) {
1523 body_request_->headers["vary_foo"] = "foo";
1524 blink::mojom::FetchAPIResponsePtr body_response = CreateBlobBodyResponse();
1525 body_response->headers["vary"] = "vary_foo";
1526 EXPECT_TRUE(Put(body_request_, std::move(body_response)));
1527 std::vector<blink::mojom::FetchAPIResponsePtr> responses;
1528
1529 EXPECT_TRUE(MatchAll(body_request_, nullptr, &responses));
1530 EXPECT_EQ(1u, responses.size());
1531 body_request_->headers["vary_foo"] = "bar";
1532
1533 EXPECT_TRUE(MatchAll(body_request_, nullptr, &responses));
1534 EXPECT_EQ(0u, responses.size());
1535
1536 blink::mojom::CacheQueryOptionsPtr match_options =
1537 blink::mojom::CacheQueryOptions::New();
1538 match_options->ignore_vary = true;
1539 EXPECT_TRUE(MatchAll(body_request_, std::move(match_options), &responses));
1540 EXPECT_EQ(1u, responses.size());
1541 }
1542
TEST_P(CacheStorageCacheTestP,MatchAll_IgnoreSearch)1543 TEST_P(CacheStorageCacheTestP, MatchAll_IgnoreSearch) {
1544 EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
1545 EXPECT_TRUE(Put(body_request_with_query_, CreateBlobBodyResponseWithQuery()));
1546 EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
1547
1548 std::vector<blink::mojom::FetchAPIResponsePtr> responses;
1549 blink::mojom::CacheQueryOptionsPtr match_options =
1550 blink::mojom::CacheQueryOptions::New();
1551 match_options->ignore_search = true;
1552 EXPECT_TRUE(MatchAll(body_request_, std::move(match_options), &responses));
1553
1554 ASSERT_EQ(2u, responses.size());
1555
1556 // Order of returned responses is not guaranteed.
1557 std::set<std::string> matched_set;
1558 for (const blink::mojom::FetchAPIResponsePtr& response : responses) {
1559 ASSERT_EQ(1u, response->url_list.size());
1560 if (response->url_list[0] == BodyUrlWithQuery()) {
1561 EXPECT_TRUE(ResponseMetadataEqual(
1562 *SetCacheName(CreateBlobBodyResponseWithQuery()), *response));
1563 matched_set.insert(response->url_list[0].spec());
1564 } else if (response->url_list[0] == BodyUrl()) {
1565 EXPECT_TRUE(ResponseMetadataEqual(*SetCacheName(CreateBlobBodyResponse()),
1566 *response));
1567 matched_set.insert(response->url_list[0].spec());
1568 }
1569 }
1570 EXPECT_EQ(2u, matched_set.size());
1571 }
1572
TEST_P(CacheStorageCacheTestP,MatchAll_Head)1573 TEST_P(CacheStorageCacheTestP, MatchAll_Head) {
1574 EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
1575
1576 std::vector<blink::mojom::FetchAPIResponsePtr> responses;
1577 blink::mojom::CacheQueryOptionsPtr match_options =
1578 blink::mojom::CacheQueryOptions::New();
1579 match_options->ignore_search = true;
1580 EXPECT_TRUE(MatchAll(body_head_request_, match_options->Clone(), &responses));
1581 EXPECT_TRUE(responses.empty());
1582
1583 match_options->ignore_method = true;
1584 EXPECT_TRUE(MatchAll(body_head_request_, match_options->Clone(), &responses));
1585 ASSERT_EQ(1u, responses.size());
1586 EXPECT_TRUE(ResponseMetadataEqual(*SetCacheName(CreateBlobBodyResponse()),
1587 *responses[0]));
1588 mojo::Remote<blink::mojom::Blob> blob(std::move(responses[0]->blob->blob));
1589 EXPECT_EQ(expected_blob_data_, storage::BlobToString(blob.get()));
1590 }
1591
TEST_P(CacheStorageCacheTestP,Vary)1592 TEST_P(CacheStorageCacheTestP, Vary) {
1593 body_request_->headers["vary_foo"] = "foo";
1594 blink::mojom::FetchAPIResponsePtr body_response = CreateBlobBodyResponse();
1595 body_response->headers["vary"] = "vary_foo";
1596 EXPECT_TRUE(Put(body_request_, std::move(body_response)));
1597 EXPECT_TRUE(Match(body_request_));
1598
1599 body_request_->headers["vary_foo"] = "bar";
1600 EXPECT_FALSE(Match(body_request_));
1601
1602 body_request_->headers.erase(std::string("vary_foo"));
1603 EXPECT_FALSE(Match(body_request_));
1604 }
1605
TEST_P(CacheStorageCacheTestP,EmptyVary)1606 TEST_P(CacheStorageCacheTestP, EmptyVary) {
1607 blink::mojom::FetchAPIResponsePtr body_response = CreateBlobBodyResponse();
1608 body_response->headers["vary"] = "";
1609 EXPECT_TRUE(Put(body_request_, std::move(body_response)));
1610 EXPECT_TRUE(Match(body_request_));
1611
1612 body_request_->headers["zoo"] = "zoo";
1613 EXPECT_TRUE(Match(body_request_));
1614 }
1615
TEST_P(CacheStorageCacheTestP,NoVaryButDiffHeaders)1616 TEST_P(CacheStorageCacheTestP, NoVaryButDiffHeaders) {
1617 EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
1618 EXPECT_TRUE(Match(body_request_));
1619
1620 body_request_->headers["zoo"] = "zoo";
1621 EXPECT_TRUE(Match(body_request_));
1622 }
1623
TEST_P(CacheStorageCacheTestP,VaryMultiple)1624 TEST_P(CacheStorageCacheTestP, VaryMultiple) {
1625 body_request_->headers["vary_foo"] = "foo";
1626 body_request_->headers["vary_bar"] = "bar";
1627 blink::mojom::FetchAPIResponsePtr body_response = CreateBlobBodyResponse();
1628 body_response->headers["vary"] = " vary_foo , vary_bar";
1629 EXPECT_TRUE(Put(body_request_, std::move(body_response)));
1630 EXPECT_TRUE(Match(body_request_));
1631
1632 body_request_->headers["vary_bar"] = "foo";
1633 EXPECT_FALSE(Match(body_request_));
1634
1635 body_request_->headers.erase(std::string("vary_bar"));
1636 EXPECT_FALSE(Match(body_request_));
1637 }
1638
TEST_P(CacheStorageCacheTestP,VaryNewHeader)1639 TEST_P(CacheStorageCacheTestP, VaryNewHeader) {
1640 body_request_->headers["vary_foo"] = "foo";
1641 blink::mojom::FetchAPIResponsePtr body_response = CreateBlobBodyResponse();
1642 body_response->headers["vary"] = " vary_foo, vary_bar";
1643 EXPECT_TRUE(Put(body_request_, std::move(body_response)));
1644 EXPECT_TRUE(Match(body_request_));
1645
1646 body_request_->headers["vary_bar"] = "bar";
1647 EXPECT_FALSE(Match(body_request_));
1648 }
1649
TEST_P(CacheStorageCacheTestP,VaryStar)1650 TEST_P(CacheStorageCacheTestP, VaryStar) {
1651 blink::mojom::FetchAPIResponsePtr body_response = CreateBlobBodyResponse();
1652 body_response->headers["vary"] = "*";
1653 EXPECT_TRUE(Put(body_request_, std::move(body_response)));
1654 EXPECT_FALSE(Match(body_request_));
1655 }
1656
TEST_P(CacheStorageCacheTestP,EmptyKeys)1657 TEST_P(CacheStorageCacheTestP, EmptyKeys) {
1658 EXPECT_TRUE(Keys());
1659 EXPECT_EQ(0u, callback_strings_.size());
1660 }
1661
TEST_P(CacheStorageCacheTestP,TwoKeys)1662 TEST_P(CacheStorageCacheTestP, TwoKeys) {
1663 EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
1664 EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
1665 EXPECT_TRUE(Keys());
1666 std::vector<std::string> expected_keys{no_body_request_->url.spec(),
1667 body_request_->url.spec()};
1668 EXPECT_EQ(expected_keys, callback_strings_);
1669 }
1670
TEST_P(CacheStorageCacheTestP,TwoKeysThenOne)1671 TEST_P(CacheStorageCacheTestP, TwoKeysThenOne) {
1672 EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
1673 EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
1674 EXPECT_TRUE(Keys());
1675 std::vector<std::string> expected_keys{no_body_request_->url.spec(),
1676 body_request_->url.spec()};
1677 EXPECT_EQ(expected_keys, callback_strings_);
1678
1679 EXPECT_TRUE(Delete(body_request_));
1680 EXPECT_TRUE(Keys());
1681 std::vector<std::string> expected_keys2{no_body_request_->url.spec()};
1682 EXPECT_EQ(expected_keys2, callback_strings_);
1683 }
1684
TEST_P(CacheStorageCacheTestP,KeysWithIgnoreSearchTrue)1685 TEST_P(CacheStorageCacheTestP, KeysWithIgnoreSearchTrue) {
1686 EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
1687 EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
1688 EXPECT_TRUE(Put(body_request_with_query_, CreateBlobBodyResponseWithQuery()));
1689
1690 blink::mojom::CacheQueryOptionsPtr match_options =
1691 blink::mojom::CacheQueryOptions::New();
1692 match_options->ignore_search = true;
1693
1694 EXPECT_TRUE(Keys(body_request_with_query_, std::move(match_options)));
1695 std::vector<std::string> expected_keys = {
1696 body_request_->url.spec(), body_request_with_query_->url.spec()};
1697 EXPECT_EQ(expected_keys, callback_strings_);
1698 }
1699
TEST_P(CacheStorageCacheTestP,KeysWithIgnoreSearchFalse)1700 TEST_P(CacheStorageCacheTestP, KeysWithIgnoreSearchFalse) {
1701 EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
1702 EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
1703 EXPECT_TRUE(Put(body_request_with_query_, CreateBlobBodyResponseWithQuery()));
1704
1705 // Default value of ignore_search is false.
1706 blink::mojom::CacheQueryOptionsPtr match_options =
1707 blink::mojom::CacheQueryOptions::New();
1708 EXPECT_EQ(match_options->ignore_search, false);
1709
1710 EXPECT_TRUE(Keys(body_request_with_query_, std::move(match_options)));
1711 std::vector<std::string> expected_keys = {
1712 body_request_with_query_->url.spec()};
1713 EXPECT_EQ(expected_keys, callback_strings_);
1714 }
1715
TEST_P(CacheStorageCacheTestP,DeleteNoBody)1716 TEST_P(CacheStorageCacheTestP, DeleteNoBody) {
1717 EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
1718 EXPECT_TRUE(Match(no_body_request_));
1719 EXPECT_TRUE(Delete(no_body_request_));
1720 EXPECT_FALSE(Match(no_body_request_));
1721 EXPECT_FALSE(Delete(no_body_request_));
1722 EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
1723 EXPECT_TRUE(Match(no_body_request_));
1724 EXPECT_TRUE(Delete(no_body_request_));
1725 }
1726
TEST_P(CacheStorageCacheTestP,DeleteBody)1727 TEST_P(CacheStorageCacheTestP, DeleteBody) {
1728 EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
1729 EXPECT_TRUE(Match(body_request_));
1730 EXPECT_TRUE(Delete(body_request_));
1731 EXPECT_FALSE(Match(body_request_));
1732 EXPECT_FALSE(Delete(body_request_));
1733 EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
1734 EXPECT_TRUE(Match(body_request_));
1735 EXPECT_TRUE(Delete(body_request_));
1736 }
1737
TEST_P(CacheStorageCacheTestP,DeleteWithIgnoreSearchTrue)1738 TEST_P(CacheStorageCacheTestP, DeleteWithIgnoreSearchTrue) {
1739 EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
1740 EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
1741 EXPECT_TRUE(Put(body_request_with_query_, CreateBlobBodyResponseWithQuery()));
1742
1743 EXPECT_TRUE(Keys());
1744 std::vector<std::string> expected_keys{no_body_request_->url.spec(),
1745 body_request_->url.spec(),
1746 body_request_with_query_->url.spec()};
1747 EXPECT_EQ(expected_keys, callback_strings_);
1748
1749 // The following delete operation will remove both of body_request_ and
1750 // body_request_with_query_ from cache storage.
1751 blink::mojom::CacheQueryOptionsPtr match_options =
1752 blink::mojom::CacheQueryOptions::New();
1753 match_options->ignore_search = true;
1754 EXPECT_TRUE(Delete(body_request_with_query_, std::move(match_options)));
1755
1756 EXPECT_TRUE(Keys());
1757 expected_keys.clear();
1758 std::vector<std::string> expected_keys2{no_body_request_->url.spec()};
1759 EXPECT_EQ(expected_keys2, callback_strings_);
1760 }
1761
TEST_P(CacheStorageCacheTestP,DeleteWithIgnoreSearchFalse)1762 TEST_P(CacheStorageCacheTestP, DeleteWithIgnoreSearchFalse) {
1763 EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
1764 EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
1765 EXPECT_TRUE(Put(body_request_with_query_, CreateBlobBodyResponseWithQuery()));
1766
1767 EXPECT_TRUE(Keys());
1768 std::vector<std::string> expected_keys{no_body_request_->url.spec(),
1769 body_request_->url.spec(),
1770 body_request_with_query_->url.spec()};
1771 EXPECT_EQ(expected_keys, callback_strings_);
1772
1773 // Default value of ignore_search is false.
1774 blink::mojom::CacheQueryOptionsPtr match_options =
1775 blink::mojom::CacheQueryOptions::New();
1776 EXPECT_EQ(match_options->ignore_search, false);
1777
1778 EXPECT_TRUE(Delete(body_request_with_query_, std::move(match_options)));
1779
1780 EXPECT_TRUE(Keys());
1781 std::vector<std::string> expected_keys2{no_body_request_->url.spec(),
1782 body_request_->url.spec()};
1783 EXPECT_EQ(expected_keys2, callback_strings_);
1784 }
1785
TEST_P(CacheStorageCacheTestP,QuickStressNoBody)1786 TEST_P(CacheStorageCacheTestP, QuickStressNoBody) {
1787 for (int i = 0; i < 100; ++i) {
1788 EXPECT_FALSE(Match(no_body_request_));
1789 EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
1790 EXPECT_TRUE(Match(no_body_request_));
1791 EXPECT_TRUE(Delete(no_body_request_));
1792 }
1793 }
1794
TEST_P(CacheStorageCacheTestP,QuickStressBody)1795 TEST_P(CacheStorageCacheTestP, QuickStressBody) {
1796 for (int i = 0; i < 100; ++i) {
1797 ASSERT_FALSE(Match(body_request_));
1798 ASSERT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
1799 ASSERT_TRUE(Match(body_request_));
1800 ASSERT_TRUE(Delete(body_request_));
1801 }
1802 }
1803
TEST_P(CacheStorageCacheTestP,PutResponseType)1804 TEST_P(CacheStorageCacheTestP, PutResponseType) {
1805 EXPECT_TRUE(TestResponseType(network::mojom::FetchResponseType::kBasic));
1806 EXPECT_TRUE(TestResponseType(network::mojom::FetchResponseType::kCors));
1807 EXPECT_TRUE(TestResponseType(network::mojom::FetchResponseType::kDefault));
1808 EXPECT_TRUE(TestResponseType(network::mojom::FetchResponseType::kError));
1809 EXPECT_TRUE(TestResponseType(network::mojom::FetchResponseType::kOpaque));
1810 EXPECT_TRUE(
1811 TestResponseType(network::mojom::FetchResponseType::kOpaqueRedirect));
1812 }
1813
TEST_P(CacheStorageCacheTestP,PutWithSideData)1814 TEST_P(CacheStorageCacheTestP, PutWithSideData) {
1815 blink::mojom::FetchAPIResponsePtr response = CreateBlobBodyResponse();
1816
1817 const std::string expected_side_data = "SideData";
1818 CopySideDataToResponse("blob-id:mysideblob", expected_side_data,
1819 response.get());
1820 EXPECT_TRUE(Put(body_request_, std::move(response)));
1821
1822 EXPECT_TRUE(Match(body_request_));
1823 ASSERT_TRUE(callback_response_->blob);
1824 mojo::Remote<blink::mojom::Blob> blob(
1825 std::move(callback_response_->blob->blob));
1826 EXPECT_EQ(expected_blob_data_, storage::BlobToString(blob.get()));
1827 EXPECT_EQ(expected_side_data, CopySideData(blob.get()));
1828 }
1829
TEST_P(CacheStorageCacheTestP,PutWithSideData_QuotaExceeded)1830 TEST_P(CacheStorageCacheTestP, PutWithSideData_QuotaExceeded) {
1831 blink::mojom::FetchAPIResponsePtr response = CreateBlobBodyResponse();
1832 base::CheckedNumeric<uint64_t> safe_expected_entry_size =
1833 cache_->GetRequiredSafeSpaceForRequest(body_request_) +
1834 cache_->GetRequiredSafeSpaceForResponse(response);
1835 SetQuota(uint64_t{safe_expected_entry_size.ValueOrDie()} - 1);
1836 const std::string expected_side_data = "SideData";
1837 CopySideDataToResponse("blob-id:mysideblob", expected_side_data,
1838 response.get());
1839 // When the available space is not enough for the body, Put operation must
1840 // fail.
1841 EXPECT_FALSE(Put(body_request_, std::move(response)));
1842 EXPECT_EQ(CacheStorageError::kErrorQuotaExceeded, callback_error_);
1843 }
1844
TEST_P(CacheStorageCacheTestP,PutWithSideData_QuotaExceededSkipSideData)1845 TEST_P(CacheStorageCacheTestP, PutWithSideData_QuotaExceededSkipSideData) {
1846 blink::mojom::FetchAPIResponsePtr response = CreateBlobBodyResponse();
1847 base::CheckedNumeric<uint64_t> safe_expected_entry_size =
1848 cache_->GetRequiredSafeSpaceForRequest(body_request_) +
1849 cache_->GetRequiredSafeSpaceForResponse(response);
1850 SetQuota(safe_expected_entry_size.ValueOrDie());
1851 const std::string expected_side_data = "SideData";
1852 CopySideDataToResponse("blob-id:mysideblob", expected_side_data,
1853 response.get());
1854 // When the available space is enough for the body but not enough for the side
1855 // data, Put operation must succeed.
1856 EXPECT_TRUE(Put(body_request_, std::move(response)));
1857
1858 EXPECT_TRUE(Match(body_request_));
1859 ASSERT_TRUE(callback_response_->blob);
1860 mojo::Remote<blink::mojom::Blob> blob(
1861 std::move(callback_response_->blob->blob));
1862 EXPECT_EQ(expected_blob_data_, storage::BlobToString(blob.get()));
1863 // The side data should not be written.
1864 EXPECT_EQ("", CopySideData(blob.get()));
1865 }
1866
TEST_P(CacheStorageCacheTestP,PutWithSideData_BadMessage)1867 TEST_P(CacheStorageCacheTestP, PutWithSideData_BadMessage) {
1868 base::HistogramTester histogram_tester;
1869 blink::mojom::FetchAPIResponsePtr response = CreateBlobBodyResponse();
1870
1871 const std::string expected_side_data = "SideData";
1872 CopySideDataToResponse("blob-id:mysideblob", expected_side_data,
1873 response.get());
1874
1875 blink::mojom::BatchOperationPtr operation =
1876 blink::mojom::BatchOperation::New();
1877 operation->operation_type = blink::mojom::OperationType::kPut;
1878 operation->request = BackgroundFetchSettledFetch::CloneRequest(body_request_);
1879 operation->response = std::move(response);
1880 operation->response->side_data_blob_for_cache_put->size =
1881 std::numeric_limits<uint64_t>::max();
1882
1883 std::vector<blink::mojom::BatchOperationPtr> operations;
1884 operations.emplace_back(std::move(operation));
1885 EXPECT_EQ(CacheStorageError::kErrorStorage,
1886 BatchOperation(std::move(operations)));
1887 histogram_tester.ExpectBucketCount(
1888 "ServiceWorkerCache.ErrorStorageType",
1889 ErrorStorageType::kBatchDidGetUsageAndQuotaInvalidSpace, 1);
1890 EXPECT_EQ("CSDH_UNEXPECTED_OPERATION", bad_message_reason_);
1891
1892 EXPECT_FALSE(Match(body_request_));
1893 }
1894
TEST_P(CacheStorageCacheTestP,WriteSideData)1895 TEST_P(CacheStorageCacheTestP, WriteSideData) {
1896 base::Time response_time(base::Time::Now());
1897 blink::mojom::FetchAPIResponsePtr response = CreateBlobBodyResponse();
1898 response->response_time = response_time;
1899 EXPECT_TRUE(Put(body_request_, std::move(response)));
1900
1901 const std::string expected_side_data1 = "SideDataSample";
1902 scoped_refptr<net::IOBuffer> buffer1 =
1903 base::MakeRefCounted<net::StringIOBuffer>(expected_side_data1);
1904 EXPECT_TRUE(WriteSideData(body_request_->url, response_time, buffer1,
1905 expected_side_data1.length()));
1906
1907 EXPECT_TRUE(Match(body_request_));
1908 ASSERT_TRUE(callback_response_->blob);
1909 mojo::Remote<blink::mojom::Blob> blob1(
1910 std::move(callback_response_->blob->blob));
1911 EXPECT_EQ(expected_blob_data_, storage::BlobToString(blob1.get()));
1912 EXPECT_EQ(expected_side_data1, CopySideData(blob1.get()));
1913
1914 const std::string expected_side_data2 = "New data";
1915 scoped_refptr<net::IOBuffer> buffer2 =
1916 base::MakeRefCounted<net::StringIOBuffer>(expected_side_data2);
1917 EXPECT_TRUE(WriteSideData(body_request_->url, response_time, buffer2,
1918 expected_side_data2.length()));
1919 EXPECT_TRUE(Match(body_request_));
1920 ASSERT_TRUE(callback_response_->blob);
1921 mojo::Remote<blink::mojom::Blob> blob2(
1922 std::move(callback_response_->blob->blob));
1923 EXPECT_EQ(expected_blob_data_, storage::BlobToString(blob2.get()));
1924 EXPECT_EQ(expected_side_data2, CopySideData(blob2.get()));
1925
1926 ASSERT_TRUE(Delete(body_request_));
1927 }
1928
TEST_P(CacheStorageCacheTestP,WriteSideData_QuotaExceeded)1929 TEST_P(CacheStorageCacheTestP, WriteSideData_QuotaExceeded) {
1930 SetQuota(1024 * 1023);
1931 base::Time response_time(base::Time::Now());
1932 blink::mojom::FetchAPIResponsePtr response(CreateNoBodyResponse());
1933 response->response_time = response_time;
1934 EXPECT_TRUE(Put(no_body_request_, std::move(response)));
1935
1936 const size_t kSize = 1024 * 1024;
1937 scoped_refptr<net::IOBuffer> buffer =
1938 base::MakeRefCounted<net::IOBuffer>(kSize);
1939 memset(buffer->data(), 0, kSize);
1940 EXPECT_FALSE(
1941 WriteSideData(no_body_request_->url, response_time, buffer, kSize));
1942 EXPECT_EQ(CacheStorageError::kErrorQuotaExceeded, callback_error_);
1943 ASSERT_TRUE(Delete(no_body_request_));
1944 }
1945
TEST_P(CacheStorageCacheTestP,WriteSideData_QuotaManagerModified)1946 TEST_P(CacheStorageCacheTestP, WriteSideData_QuotaManagerModified) {
1947 base::Time response_time(base::Time::Now());
1948 blink::mojom::FetchAPIResponsePtr response(CreateNoBodyResponse());
1949 response->response_time = response_time;
1950 EXPECT_EQ(0, quota_manager_proxy_->notify_storage_modified_count());
1951 EXPECT_TRUE(Put(no_body_request_, std::move(response)));
1952 // Storage notification happens after the operation returns, so continue the
1953 // event loop.
1954 base::RunLoop().RunUntilIdle();
1955 EXPECT_EQ(1, quota_manager_proxy_->notify_storage_modified_count());
1956
1957 const size_t kSize = 10;
1958 scoped_refptr<net::IOBuffer> buffer =
1959 base::MakeRefCounted<net::IOBuffer>(kSize);
1960 memset(buffer->data(), 0, kSize);
1961 EXPECT_TRUE(
1962 WriteSideData(no_body_request_->url, response_time, buffer, kSize));
1963 base::RunLoop().RunUntilIdle();
1964 EXPECT_EQ(2, quota_manager_proxy_->notify_storage_modified_count());
1965 ASSERT_TRUE(Delete(no_body_request_));
1966 }
1967
TEST_P(CacheStorageCacheTestP,WriteSideData_DifferentTimeStamp)1968 TEST_P(CacheStorageCacheTestP, WriteSideData_DifferentTimeStamp) {
1969 base::Time response_time(base::Time::Now());
1970 blink::mojom::FetchAPIResponsePtr response(CreateNoBodyResponse());
1971 response->response_time = response_time;
1972 EXPECT_TRUE(Put(no_body_request_, std::move(response)));
1973
1974 const size_t kSize = 10;
1975 scoped_refptr<net::IOBuffer> buffer =
1976 base::MakeRefCounted<net::IOBuffer>(kSize);
1977 memset(buffer->data(), 0, kSize);
1978 EXPECT_FALSE(WriteSideData(no_body_request_->url,
1979 response_time + base::TimeDelta::FromSeconds(1),
1980 buffer, kSize));
1981 EXPECT_EQ(CacheStorageError::kErrorNotFound, callback_error_);
1982 ASSERT_TRUE(Delete(no_body_request_));
1983 }
1984
TEST_P(CacheStorageCacheTestP,WriteSideData_NotFound)1985 TEST_P(CacheStorageCacheTestP, WriteSideData_NotFound) {
1986 const size_t kSize = 10;
1987 scoped_refptr<net::IOBuffer> buffer =
1988 base::MakeRefCounted<net::IOBuffer>(kSize);
1989 memset(buffer->data(), 0, kSize);
1990 EXPECT_FALSE(WriteSideData(GURL("http://www.example.com/not_exist"),
1991 base::Time::Now(), buffer, kSize));
1992 EXPECT_EQ(CacheStorageError::kErrorNotFound, callback_error_);
1993 }
1994
TEST_F(CacheStorageCacheTest,CaselessServiceWorkerFetchRequestHeaders)1995 TEST_F(CacheStorageCacheTest, CaselessServiceWorkerFetchRequestHeaders) {
1996 // CacheStorageCache depends on blink::mojom::FetchAPIRequest having caseless
1997 // headers so that it can quickly lookup vary headers.
1998 auto request = blink::mojom::FetchAPIRequest::New();
1999 request->url = GURL("http://www.example.com");
2000 request->method = "GET";
2001 request->referrer = blink::mojom::Referrer::New();
2002 request->is_reload = false;
2003
2004 request->headers["content-type"] = "foo";
2005 request->headers["Content-Type"] = "bar";
2006 EXPECT_EQ("bar", request->headers["content-type"]);
2007 }
2008
TEST_P(CacheStorageCacheTestP,QuotaManagerModified)2009 TEST_P(CacheStorageCacheTestP, QuotaManagerModified) {
2010 EXPECT_EQ(0, quota_manager_proxy_->notify_storage_modified_count());
2011
2012 EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
2013 // Storage notification happens after the operation returns, so continue the
2014 // event loop.
2015 base::RunLoop().RunUntilIdle();
2016 EXPECT_EQ(1, quota_manager_proxy_->notify_storage_modified_count());
2017 EXPECT_LT(0, quota_manager_proxy_->last_notified_delta());
2018 int64_t sum_delta = quota_manager_proxy_->last_notified_delta();
2019
2020 EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
2021 base::RunLoop().RunUntilIdle();
2022 EXPECT_EQ(2, quota_manager_proxy_->notify_storage_modified_count());
2023 EXPECT_LT(sum_delta, quota_manager_proxy_->last_notified_delta());
2024 sum_delta += quota_manager_proxy_->last_notified_delta();
2025
2026 EXPECT_TRUE(Delete(body_request_));
2027 base::RunLoop().RunUntilIdle();
2028 EXPECT_EQ(3, quota_manager_proxy_->notify_storage_modified_count());
2029 sum_delta += quota_manager_proxy_->last_notified_delta();
2030
2031 EXPECT_TRUE(Delete(no_body_request_));
2032 base::RunLoop().RunUntilIdle();
2033 EXPECT_EQ(4, quota_manager_proxy_->notify_storage_modified_count());
2034 sum_delta += quota_manager_proxy_->last_notified_delta();
2035
2036 EXPECT_EQ(0, sum_delta);
2037 }
2038
TEST_P(CacheStorageCacheTestP,PutObeysQuotaLimits)2039 TEST_P(CacheStorageCacheTestP, PutObeysQuotaLimits) {
2040 SetQuota(0);
2041 EXPECT_FALSE(Put(body_request_, CreateBlobBodyResponse()));
2042 EXPECT_EQ(CacheStorageError::kErrorQuotaExceeded, callback_error_);
2043 }
2044
TEST_P(CacheStorageCacheTestP,PutObeysQuotaLimitsWithEmptyResponse)2045 TEST_P(CacheStorageCacheTestP, PutObeysQuotaLimitsWithEmptyResponse) {
2046 blink::mojom::FetchAPIResponsePtr response = CreateBlobBodyResponse();
2047 base::CheckedNumeric<uint64_t> safe_expected_entry_size =
2048 cache_->GetRequiredSafeSpaceForRequest(body_request_) +
2049 cache_->GetRequiredSafeSpaceForResponse(response);
2050 SetQuota(safe_expected_entry_size.ValueOrDie());
2051
2052 // The first Put will completely fill the quota, leaving no space for the
2053 // second operation, which will fail even with empty response, due to the size
2054 // of the headers.
2055 EXPECT_TRUE(Put(body_request_, std::move(response)));
2056 EXPECT_FALSE(Put(no_body_request_, CreateNoBodyResponse()));
2057 EXPECT_EQ(CacheStorageError::kErrorQuotaExceeded, callback_error_);
2058 }
2059
TEST_P(CacheStorageCacheTestP,PutSafeSpaceIsEnough)2060 TEST_P(CacheStorageCacheTestP, PutSafeSpaceIsEnough) {
2061 blink::mojom::FetchAPIResponsePtr response = CreateBlobBodyResponse();
2062 base::CheckedNumeric<uint64_t> safe_expected_entry_size =
2063 cache_->GetRequiredSafeSpaceForRequest(body_request_) +
2064 cache_->GetRequiredSafeSpaceForResponse(response);
2065 SetQuota(safe_expected_entry_size.ValueOrDie());
2066
2067 EXPECT_TRUE(Put(body_request_, std::move(response)));
2068 }
2069
TEST_P(CacheStorageCacheTestP,PutRequestUrlObeysQuotaLimits)2070 TEST_P(CacheStorageCacheTestP, PutRequestUrlObeysQuotaLimits) {
2071 const GURL url("http://example.com/body.html");
2072 const GURL longerUrl("http://example.com/longer-body.html");
2073 blink::mojom::FetchAPIRequestPtr request = CreateFetchAPIRequest(
2074 url, "GET", kHeaders, blink::mojom::Referrer::New(), false);
2075 blink::mojom::FetchAPIResponsePtr response = CreateBlobBodyResponse();
2076 base::CheckedNumeric<uint64_t> safe_expected_entry_size =
2077 cache_->GetRequiredSafeSpaceForRequest(request) +
2078 cache_->GetRequiredSafeSpaceForResponse(response);
2079 SetQuota(safe_expected_entry_size.ValueOrDie());
2080
2081 request->url = longerUrl;
2082 EXPECT_FALSE(Put(request, std::move(response)));
2083 EXPECT_EQ(CacheStorageError::kErrorQuotaExceeded, callback_error_);
2084 }
2085
TEST_P(CacheStorageCacheTestP,PutRequestMethodObeysQuotaLimits)2086 TEST_P(CacheStorageCacheTestP, PutRequestMethodObeysQuotaLimits) {
2087 blink::mojom::FetchAPIRequestPtr request = CreateFetchAPIRequest(
2088 BodyUrl(), "GET", kHeaders, blink::mojom::Referrer::New(), false);
2089 blink::mojom::FetchAPIResponsePtr response = CreateBlobBodyResponse();
2090 base::CheckedNumeric<uint64_t> safe_expected_entry_size =
2091 cache_->GetRequiredSafeSpaceForRequest(request) +
2092 cache_->GetRequiredSafeSpaceForResponse(response);
2093 SetQuota(safe_expected_entry_size.ValueOrDie());
2094
2095 request->method = "LongerMethodThanGet";
2096 EXPECT_FALSE(Put(request, std::move(response)));
2097 EXPECT_EQ(CacheStorageError::kErrorQuotaExceeded, callback_error_);
2098 }
2099
TEST_P(CacheStorageCacheTestP,PutRequestHeadersObeyQuotaLimits)2100 TEST_P(CacheStorageCacheTestP, PutRequestHeadersObeyQuotaLimits) {
2101 blink::mojom::FetchAPIRequestPtr request = CreateFetchAPIRequest(
2102 BodyUrl(), "GET", kHeaders, blink::mojom::Referrer::New(), false);
2103 blink::mojom::FetchAPIResponsePtr response = CreateBlobBodyResponse();
2104 base::CheckedNumeric<uint64_t> safe_expected_entry_size =
2105 cache_->GetRequiredSafeSpaceForRequest(request) +
2106 cache_->GetRequiredSafeSpaceForResponse(response);
2107 SetQuota(safe_expected_entry_size.ValueOrDie());
2108
2109 request->headers["New-Header"] = "foo";
2110 EXPECT_FALSE(Put(request, std::move(response)));
2111 EXPECT_EQ(CacheStorageError::kErrorQuotaExceeded, callback_error_);
2112 }
2113
TEST_P(CacheStorageCacheTestP,PutResponseStatusObeysQuotaLimits)2114 TEST_P(CacheStorageCacheTestP, PutResponseStatusObeysQuotaLimits) {
2115 blink::mojom::FetchAPIResponsePtr response = CreateBlobBodyResponse();
2116 base::CheckedNumeric<uint64_t> safe_expected_entry_size =
2117 cache_->GetRequiredSafeSpaceForRequest(body_request_) +
2118 cache_->GetRequiredSafeSpaceForResponse(response);
2119 SetQuota(safe_expected_entry_size.ValueOrDie());
2120
2121 response->status_text = "LongerThanOK";
2122 EXPECT_FALSE(Put(body_request_, std::move(response)));
2123 EXPECT_EQ(CacheStorageError::kErrorQuotaExceeded, callback_error_);
2124 }
2125
TEST_P(CacheStorageCacheTestP,PutResponseBlobObeysQuotaLimits)2126 TEST_P(CacheStorageCacheTestP, PutResponseBlobObeysQuotaLimits) {
2127 blink::mojom::FetchAPIResponsePtr response = CreateBlobBodyResponse();
2128 base::CheckedNumeric<uint64_t> safe_expected_entry_size =
2129 cache_->GetRequiredSafeSpaceForRequest(body_request_) +
2130 cache_->GetRequiredSafeSpaceForResponse(response);
2131 SetQuota(safe_expected_entry_size.ValueOrDie());
2132
2133 response->blob->size += 1;
2134 EXPECT_FALSE(Put(body_request_, std::move(response)));
2135 EXPECT_EQ(CacheStorageError::kErrorQuotaExceeded, callback_error_);
2136 }
2137
TEST_P(CacheStorageCacheTestP,PutResponseHeadersObeyQuotaLimits)2138 TEST_P(CacheStorageCacheTestP, PutResponseHeadersObeyQuotaLimits) {
2139 blink::mojom::FetchAPIResponsePtr response = CreateBlobBodyResponse();
2140 base::CheckedNumeric<uint64_t> safe_expected_entry_size =
2141 cache_->GetRequiredSafeSpaceForRequest(body_request_) +
2142 cache_->GetRequiredSafeSpaceForResponse(response);
2143 SetQuota(safe_expected_entry_size.ValueOrDie());
2144
2145 response->headers["New-Header"] = "foo";
2146 EXPECT_FALSE(Put(body_request_, std::move(response)));
2147 EXPECT_EQ(CacheStorageError::kErrorQuotaExceeded, callback_error_);
2148 }
2149
TEST_P(CacheStorageCacheTestP,PutResponseCorsHeadersObeyQuotaLimits)2150 TEST_P(CacheStorageCacheTestP, PutResponseCorsHeadersObeyQuotaLimits) {
2151 blink::mojom::FetchAPIResponsePtr response = CreateBlobBodyResponse();
2152 base::CheckedNumeric<uint64_t> safe_expected_entry_size =
2153 cache_->GetRequiredSafeSpaceForRequest(body_request_) +
2154 cache_->GetRequiredSafeSpaceForResponse(response);
2155 SetQuota(safe_expected_entry_size.ValueOrDie());
2156
2157 response->cors_exposed_header_names.push_back("AnotherOne");
2158 EXPECT_FALSE(Put(body_request_, std::move(response)));
2159 EXPECT_EQ(CacheStorageError::kErrorQuotaExceeded, callback_error_);
2160 }
2161
TEST_P(CacheStorageCacheTestP,PutResponseUrlListObeysQuotaLimits)2162 TEST_P(CacheStorageCacheTestP, PutResponseUrlListObeysQuotaLimits) {
2163 blink::mojom::FetchAPIResponsePtr response = CreateBlobBodyResponse();
2164 base::CheckedNumeric<uint64_t> safe_expected_entry_size =
2165 cache_->GetRequiredSafeSpaceForRequest(body_request_) +
2166 cache_->GetRequiredSafeSpaceForResponse(response);
2167 SetQuota(safe_expected_entry_size.ValueOrDie());
2168
2169 response->url_list.emplace_back("http://example.com/another-url");
2170 EXPECT_FALSE(Put(body_request_, std::move(response)));
2171 EXPECT_EQ(CacheStorageError::kErrorQuotaExceeded, callback_error_);
2172 }
2173
TEST_P(CacheStorageCacheTestP,PutObeysQuotaLimitsWithEmptyResponseZeroQuota)2174 TEST_P(CacheStorageCacheTestP, PutObeysQuotaLimitsWithEmptyResponseZeroQuota) {
2175 SetQuota(0);
2176 EXPECT_FALSE(Put(body_request_, CreateNoBodyResponse()));
2177 EXPECT_EQ(CacheStorageError::kErrorQuotaExceeded, callback_error_);
2178 }
2179
TEST_P(CacheStorageCacheTestP,Size)2180 TEST_P(CacheStorageCacheTestP, Size) {
2181 EXPECT_EQ(0, Size());
2182 EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
2183 EXPECT_LT(0, Size());
2184 int64_t no_body_size = Size();
2185
2186 EXPECT_TRUE(Delete(no_body_request_));
2187 EXPECT_EQ(0, Size());
2188
2189 EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
2190 EXPECT_LT(no_body_size, Size());
2191
2192 EXPECT_TRUE(Delete(body_request_));
2193 EXPECT_EQ(0, Size());
2194 }
2195
TEST_F(CacheStorageCacheTest,VerifyOpaqueSizePadding)2196 TEST_F(CacheStorageCacheTest, VerifyOpaqueSizePadding) {
2197 base::Time response_time(base::Time::Now());
2198
2199 blink::mojom::FetchAPIRequestPtr non_opaque_request =
2200 BackgroundFetchSettledFetch::CloneRequest(body_request_);
2201 non_opaque_request->url = GURL("http://example.com/no-pad.html");
2202 blink::mojom::FetchAPIResponsePtr non_opaque_response =
2203 CreateBlobBodyResponse();
2204 non_opaque_response->response_time = response_time;
2205 EXPECT_EQ(0, LegacyCacheStorageCache::CalculateResponsePadding(
2206 *non_opaque_response, CreateTestPaddingKey().get(),
2207 0 /* side_data_size */));
2208 EXPECT_TRUE(Put(non_opaque_request, std::move(non_opaque_response)));
2209 int64_t unpadded_no_data_cache_size = Size();
2210
2211 // Now write some side data to that cache.
2212 const std::string expected_side_data(2048, 'X');
2213 scoped_refptr<net::IOBuffer> side_data_buffer =
2214 base::MakeRefCounted<net::StringIOBuffer>(expected_side_data);
2215 EXPECT_TRUE(WriteSideData(non_opaque_request->url, response_time,
2216 side_data_buffer, expected_side_data.length()));
2217 int64_t unpadded_total_resource_size = Size();
2218 int64_t unpadded_side_data_size =
2219 unpadded_total_resource_size - unpadded_no_data_cache_size;
2220 EXPECT_EQ(expected_side_data.size(),
2221 static_cast<size_t>(unpadded_side_data_size));
2222 blink::mojom::FetchAPIResponsePtr non_opaque_response_clone =
2223 CreateBlobBodyResponse();
2224 non_opaque_response_clone->response_time = response_time;
2225 EXPECT_EQ(0, LegacyCacheStorageCache::CalculateResponsePadding(
2226 *non_opaque_response_clone, CreateTestPaddingKey().get(),
2227 unpadded_side_data_size));
2228
2229 // Now write an identically sized opaque response.
2230 blink::mojom::FetchAPIRequestPtr opaque_request =
2231 BackgroundFetchSettledFetch::CloneRequest(non_opaque_request);
2232 opaque_request->url = GURL("http://example.com/opaque.html");
2233 // Same URL length means same cache sizes (ignoring padding).
2234 EXPECT_EQ(opaque_request->url.spec().length(),
2235 non_opaque_request->url.spec().length());
2236 blink::mojom::FetchAPIResponsePtr opaque_response(CreateBlobBodyResponse());
2237 opaque_response->response_type = network::mojom::FetchResponseType::kOpaque;
2238 opaque_response->response_time = response_time;
2239
2240 EXPECT_TRUE(Put(opaque_request, std::move(opaque_response)));
2241 // This test is fragile. Right now it deterministically adds non-zero padding.
2242 // But if the url, padding key, or padding algorithm change it might become
2243 // zero.
2244 int64_t size_after_opaque_put = Size();
2245 int64_t opaque_padding = size_after_opaque_put -
2246 2 * unpadded_no_data_cache_size -
2247 unpadded_side_data_size;
2248 ASSERT_GT(opaque_padding, 0);
2249
2250 // Now write side data and expect to see the padding change.
2251 EXPECT_TRUE(WriteSideData(opaque_request->url, response_time,
2252 side_data_buffer, expected_side_data.length()));
2253 int64_t current_padding = Size() - 2 * unpadded_total_resource_size;
2254 EXPECT_NE(opaque_padding, current_padding);
2255
2256 // Now reset opaque side data back to zero.
2257 const std::string expected_side_data2;
2258 scoped_refptr<net::IOBuffer> buffer2 =
2259 base::MakeRefCounted<net::StringIOBuffer>(expected_side_data2);
2260 EXPECT_TRUE(WriteSideData(opaque_request->url, response_time, buffer2,
2261 expected_side_data2.length()));
2262 EXPECT_EQ(size_after_opaque_put, Size());
2263
2264 // And delete the opaque response entirely.
2265 EXPECT_TRUE(Delete(opaque_request));
2266 EXPECT_EQ(unpadded_total_resource_size, Size());
2267
2268 // Now write an identically sized opaque response with the
2269 // loaded_with_credentials flag set.
2270 blink::mojom::FetchAPIRequestPtr credentialed_opaque_request =
2271 BackgroundFetchSettledFetch::CloneRequest(non_opaque_request);
2272 credentialed_opaque_request->url = GURL("http://example.com/opaque.html");
2273 // Same URL length means same cache sizes (ignoring padding).
2274 EXPECT_EQ(credentialed_opaque_request->url.spec().length(),
2275 non_opaque_request->url.spec().length());
2276 blink::mojom::FetchAPIResponsePtr credentialed_opaque_response(
2277 CreateBlobBodyResponse());
2278 credentialed_opaque_response->response_type =
2279 network::mojom::FetchResponseType::kOpaque;
2280 credentialed_opaque_response->response_time = response_time;
2281 credentialed_opaque_response->loaded_with_credentials = true;
2282
2283 EXPECT_TRUE(Put(credentialed_opaque_request,
2284 std::move(credentialed_opaque_response)));
2285
2286 int64_t size_after_credentialed_opaque_put = Size();
2287 int64_t credentialed_opaque_padding = size_after_credentialed_opaque_put -
2288 2 * unpadded_no_data_cache_size -
2289 unpadded_side_data_size;
2290 ASSERT_NE(credentialed_opaque_padding, opaque_padding);
2291 }
2292
TEST_F(CacheStorageCacheTest,TestDifferentOpaqueSideDataSizes)2293 TEST_F(CacheStorageCacheTest, TestDifferentOpaqueSideDataSizes) {
2294 blink::mojom::FetchAPIRequestPtr request =
2295 BackgroundFetchSettledFetch::CloneRequest(body_request_);
2296 blink::mojom::FetchAPIResponsePtr response(CreateBlobBodyResponse());
2297 response->response_type = network::mojom::FetchResponseType::kOpaque;
2298 base::Time response_time(base::Time::Now());
2299 response->response_time = response_time;
2300 EXPECT_TRUE(Put(request, std::move(response)));
2301 int64_t opaque_cache_size_no_side_data = Size();
2302
2303 const std::string small_side_data(1024, 'X');
2304 scoped_refptr<net::IOBuffer> buffer1 =
2305 base::MakeRefCounted<net::StringIOBuffer>(small_side_data);
2306 EXPECT_TRUE(WriteSideData(request->url, response_time, buffer1,
2307 small_side_data.length()));
2308 int64_t opaque_cache_size_with_side_data = Size();
2309 EXPECT_NE(opaque_cache_size_with_side_data, opaque_cache_size_no_side_data);
2310
2311 // Write side data of a different size. The size should not affect the padding
2312 // at all.
2313 const std::string large_side_data(2048, 'X');
2314 EXPECT_NE(large_side_data.length(), small_side_data.length());
2315 scoped_refptr<net::IOBuffer> buffer2 =
2316 base::MakeRefCounted<net::StringIOBuffer>(large_side_data);
2317 EXPECT_TRUE(WriteSideData(request->url, response_time, buffer2,
2318 large_side_data.length()));
2319 int side_data_delta = large_side_data.length() - small_side_data.length();
2320 EXPECT_EQ(opaque_cache_size_with_side_data + side_data_delta, Size());
2321 }
2322
TEST_F(CacheStorageCacheTest,TestDoubleOpaquePut)2323 TEST_F(CacheStorageCacheTest, TestDoubleOpaquePut) {
2324 blink::mojom::FetchAPIRequestPtr request =
2325 BackgroundFetchSettledFetch::CloneRequest(body_request_);
2326
2327 base::Time response_time(base::Time::Now());
2328
2329 blink::mojom::FetchAPIResponsePtr response(CreateBlobBodyResponse());
2330 response->response_type = network::mojom::FetchResponseType::kOpaque;
2331 response->response_time = response_time;
2332 EXPECT_TRUE(Put(request, std::move(response)));
2333 int64_t size_after_first_put = Size();
2334
2335 blink::mojom::FetchAPIRequestPtr request2 =
2336 BackgroundFetchSettledFetch::CloneRequest(body_request_);
2337 blink::mojom::FetchAPIResponsePtr response2(CreateBlobBodyResponse());
2338 response2->response_type = network::mojom::FetchResponseType::kOpaque;
2339 response2->response_time = response_time;
2340 EXPECT_TRUE(Put(request2, std::move(response2)));
2341
2342 EXPECT_EQ(size_after_first_put, Size());
2343 }
2344
TEST_P(CacheStorageCacheTestP,GetSizeThenClose)2345 TEST_P(CacheStorageCacheTestP, GetSizeThenClose) {
2346 // Create the backend and put something in it.
2347 EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
2348 // Get a reference to the response in the cache.
2349 EXPECT_TRUE(Match(body_request_));
2350 mojo::Remote<blink::mojom::Blob> blob(
2351 std::move(callback_response_->blob->blob));
2352 callback_response_ = nullptr;
2353
2354 int64_t cache_size = Size();
2355 EXPECT_EQ(cache_size, GetSizeThenClose());
2356 VerifyAllOpsFail();
2357
2358 // Reading blob should fail.
2359 EXPECT_EQ("", storage::BlobToString(blob.get()));
2360 }
2361
TEST_P(CacheStorageCacheTestP,OpsFailOnClosedBackend)2362 TEST_P(CacheStorageCacheTestP, OpsFailOnClosedBackend) {
2363 // Create the backend and put something in it.
2364 EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
2365 EXPECT_TRUE(Close());
2366 VerifyAllOpsFail();
2367 }
2368
2369 // Shutdown the cache in the middle of its writing the response body. Upon
2370 // restarting, that response shouldn't be available. See crbug.com/617683.
TEST_P(CacheStorageCacheTestP,UnfinishedPutsShouldNotBeReusable)2371 TEST_P(CacheStorageCacheTestP, UnfinishedPutsShouldNotBeReusable) {
2372 // Create a response with a blob that takes forever to write its bytes to the
2373 // mojo pipe. Guaranteeing that the response isn't finished writing by the
2374 // time we close the backend.
2375 base::RunLoop run_loop;
2376 auto blob = blink::mojom::SerializedBlob::New();
2377 blob->uuid = "mock blob";
2378 blob->size = 100;
2379 mojo::MakeSelfOwnedReceiver(
2380 std::make_unique<SlowBlob>(run_loop.QuitClosure()),
2381 blob->blob.InitWithNewPipeAndPassReceiver());
2382 blink::mojom::FetchAPIResponsePtr response = CreateNoBodyResponse();
2383 response->url_list = {BodyUrl()};
2384 response->blob = std::move(blob);
2385
2386 blink::mojom::BatchOperationPtr operation =
2387 blink::mojom::BatchOperation::New();
2388 operation->operation_type = blink::mojom::OperationType::kPut;
2389 operation->request = BackgroundFetchSettledFetch::CloneRequest(body_request_);
2390 operation->response = std::move(response);
2391 std::vector<blink::mojom::BatchOperationPtr> operations;
2392 operations.emplace_back(std::move(operation));
2393
2394 // Start the put operation and let it run until the blob is supposed to write
2395 // to its pipe.
2396 cache_->BatchOperation(std::move(operations), /* trace_id = */ 0,
2397 base::DoNothing(), base::DoNothing());
2398 run_loop.Run();
2399
2400 // Shut down the cache. Doing so causes the write to cease, and the entry
2401 // should be erased.
2402 cache_ = nullptr;
2403 base::RunLoop().RunUntilIdle();
2404
2405 // Create a new Cache in the same space.
2406 InitCache(nullptr);
2407
2408 // Now attempt to read the same response from the cache. It should fail.
2409 EXPECT_FALSE(Match(body_request_));
2410 }
2411
TEST_P(CacheStorageCacheTestP,BlobReferenceDelaysClose)2412 TEST_P(CacheStorageCacheTestP, BlobReferenceDelaysClose) {
2413 // Create the backend and put something in it.
2414 EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
2415 // Get a reference to the response in the cache.
2416 EXPECT_TRUE(Match(body_request_));
2417 mojo::Remote<blink::mojom::Blob> blob(
2418 std::move(callback_response_->blob->blob));
2419 callback_response_ = nullptr;
2420
2421 base::RunLoop loop;
2422 cache_->Close(base::BindOnce(&CacheStorageCacheTest::CloseCallback,
2423 base::Unretained(this),
2424 base::Unretained(&loop)));
2425 task_environment_.RunUntilIdle();
2426 // If MemoryOnly closing does succeed right away.
2427 EXPECT_EQ(MemoryOnly(), callback_closed_);
2428
2429 // Reading blob should succeed.
2430 EXPECT_EQ(expected_blob_data_, storage::BlobToString(blob.get()));
2431 blob.reset();
2432
2433 loop.Run();
2434 EXPECT_TRUE(callback_closed_);
2435 }
2436
TEST_P(CacheStorageCacheTestP,VerifySerialScheduling)2437 TEST_P(CacheStorageCacheTestP, VerifySerialScheduling) {
2438 // Start two operations, the first one is delayed but the second isn't. The
2439 // second should wait for the first.
2440 EXPECT_TRUE(Keys()); // Opens the backend.
2441 DelayableBackend* delayable_backend = cache_->UseDelayableBackend();
2442 delayable_backend->set_delay_open_entry(true);
2443
2444 base::RunLoop open_started_loop;
2445 delayable_backend->set_open_entry_started_callback(
2446 open_started_loop.QuitClosure());
2447
2448 int sequence_out = -1;
2449
2450 blink::mojom::BatchOperationPtr operation1 =
2451 blink::mojom::BatchOperation::New();
2452 operation1->operation_type = blink::mojom::OperationType::kPut;
2453 operation1->request =
2454 BackgroundFetchSettledFetch::CloneRequest(body_request_);
2455 operation1->response = CreateBlobBodyResponse();
2456
2457 std::unique_ptr<base::RunLoop> close_loop1(new base::RunLoop());
2458 std::vector<blink::mojom::BatchOperationPtr> operations1;
2459 operations1.emplace_back(std::move(operation1));
2460 cache_->BatchOperation(
2461 std::move(operations1), /* trace_id = */ 0,
2462 base::BindOnce(&CacheStorageCacheTest::SequenceCallback,
2463 base::Unretained(this), 1, &sequence_out,
2464 close_loop1.get()),
2465 CacheStorageCache::BadMessageCallback());
2466
2467 // Wait until the first operation attempts to open the entry and becomes
2468 // delayed.
2469 open_started_loop.Run();
2470
2471 blink::mojom::BatchOperationPtr operation2 =
2472 blink::mojom::BatchOperation::New();
2473 operation2->operation_type = blink::mojom::OperationType::kPut;
2474 operation2->request =
2475 BackgroundFetchSettledFetch::CloneRequest(body_request_);
2476 operation2->response = CreateBlobBodyResponse();
2477
2478 delayable_backend->set_delay_open_entry(false);
2479 std::unique_ptr<base::RunLoop> close_loop2(new base::RunLoop());
2480 std::vector<blink::mojom::BatchOperationPtr> operations2;
2481 operations2.emplace_back(std::move(operation2));
2482 cache_->BatchOperation(
2483 std::move(operations2), /* trace_id = */ 0,
2484 base::BindOnce(&CacheStorageCacheTest::SequenceCallback,
2485 base::Unretained(this), 2, &sequence_out,
2486 close_loop2.get()),
2487 CacheStorageCache::BadMessageCallback());
2488
2489 // The second put operation should wait for the first to complete.
2490 base::RunLoop().RunUntilIdle();
2491 EXPECT_EQ(-1, sequence_out);
2492
2493 EXPECT_TRUE(delayable_backend->OpenEntryContinue());
2494 close_loop1->Run();
2495 EXPECT_EQ(1, sequence_out);
2496 close_loop2->Run();
2497 EXPECT_EQ(2, sequence_out);
2498 }
2499
2500 #if defined(OS_WIN)
2501 // TODO(crbug.com/936129): Flaky on Windows.
2502 #define MAYBE_KeysWithManyCacheEntries DISABLED_KeysWithManyCacheEntries
2503 #else
2504 #define MAYBE_KeysWithManyCacheEntries KeysWithManyCacheEntries
2505 #endif
TEST_P(CacheStorageCacheTestP,MAYBE_KeysWithManyCacheEntries)2506 TEST_P(CacheStorageCacheTestP, MAYBE_KeysWithManyCacheEntries) {
2507 // Use a smaller list in disk mode to reduce test runtime.
2508 const int kNumEntries = MemoryOnly() ? 1000 : 250;
2509
2510 std::vector<std::string> expected_keys;
2511 for (int i = 0; i < kNumEntries; ++i) {
2512 GURL url =
2513 net::AppendQueryParameter(NoBodyUrl(), "n", base::NumberToString(i));
2514 expected_keys.push_back(url.spec());
2515 blink::mojom::FetchAPIRequestPtr request = CreateFetchAPIRequest(
2516 url, "GET", kHeaders, blink::mojom::Referrer::New(), false);
2517 EXPECT_TRUE(Put(request, CreateNoBodyResponse()));
2518 }
2519
2520 EXPECT_TRUE(Keys());
2521 EXPECT_EQ(expected_keys.size(), callback_strings_.size());
2522 EXPECT_EQ(expected_keys, callback_strings_);
2523 }
2524
TEST_P(CacheStorageCacheTestP,SelfRefsDuringMatch)2525 TEST_P(CacheStorageCacheTestP, SelfRefsDuringMatch) {
2526 EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
2527
2528 // When there are no operations outstanding and we're not holding an
2529 // explicit reference the cache should consider itself unreferenced.
2530 EXPECT_TRUE(cache_->IsUnreferenced());
2531
2532 DelayableBackend* delayable_backend = cache_->UseDelayableBackend();
2533 delayable_backend->set_delay_open_entry(true);
2534
2535 std::unique_ptr<base::RunLoop> loop(new base::RunLoop());
2536 cache_->Match(CopyFetchRequest(body_request_), /* match_options = */ nullptr,
2537 CacheStorageSchedulerPriority::kNormal, /* trace_id = */ 0,
2538 base::BindOnce(&CacheStorageCacheTest::ResponseAndErrorCallback,
2539 base::Unretained(this), loop.get()));
2540
2541 // Blocks on opening the cache entry.
2542 base::RunLoop().RunUntilIdle();
2543
2544 // Since an operation is outstanding the cache should consider itself
2545 // referenced.
2546 EXPECT_FALSE(cache_->IsUnreferenced());
2547
2548 // Allow the operation to continue.
2549 EXPECT_TRUE(delayable_backend->OpenEntryContinue());
2550 loop->Run();
2551
2552 // The operation should succeed.
2553 EXPECT_EQ(CacheStorageError::kSuccess, callback_error_);
2554 }
2555
TEST_P(CacheStorageCacheTestP,SelfRefsDuringMatchAll)2556 TEST_P(CacheStorageCacheTestP, SelfRefsDuringMatchAll) {
2557 EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
2558
2559 // When there are no operations outstanding and we're not holding an
2560 // explicit reference the cache should consider itself unreferenced.
2561 EXPECT_TRUE(cache_->IsUnreferenced());
2562
2563 DelayableBackend* delayable_backend = cache_->UseDelayableBackend();
2564 delayable_backend->set_delay_open_entry(true);
2565
2566 std::vector<blink::mojom::FetchAPIResponsePtr> responses;
2567
2568 std::unique_ptr<base::RunLoop> loop(new base::RunLoop());
2569 cache_->MatchAll(
2570 CopyFetchRequest(body_request_), /* match_options = */ nullptr,
2571 /* trace_id = */ 0,
2572 base::BindOnce(&CacheStorageCacheTest::ResponsesAndErrorCallback,
2573 base::Unretained(this), loop->QuitClosure(), &responses));
2574
2575 // Blocks on opening the cache entry.
2576 base::RunLoop().RunUntilIdle();
2577
2578 // Since an operation is outstanding the cache should consider itself
2579 // referenced.
2580 EXPECT_FALSE(cache_->IsUnreferenced());
2581
2582 // Allow the operation to continue.
2583 EXPECT_TRUE(delayable_backend->OpenEntryContinue());
2584 loop->Run();
2585
2586 // The operation should succeed.
2587 EXPECT_EQ(CacheStorageError::kSuccess, callback_error_);
2588 EXPECT_EQ(1u, responses.size());
2589 }
2590
TEST_P(CacheStorageCacheTestP,SelfRefsDuringWriteSideData)2591 TEST_P(CacheStorageCacheTestP, SelfRefsDuringWriteSideData) {
2592 base::Time response_time(base::Time::Now());
2593 blink::mojom::FetchAPIResponsePtr response = CreateBlobBodyResponse();
2594 response->response_time = response_time;
2595 EXPECT_TRUE(Put(body_request_, std::move(response)));
2596
2597 // When there are no operations outstanding and we're not holding an
2598 // explicit reference the cache should consider itself unreferenced.
2599 EXPECT_TRUE(cache_->IsUnreferenced());
2600
2601 DelayableBackend* delayable_backend = cache_->UseDelayableBackend();
2602 delayable_backend->set_delay_open_entry(true);
2603
2604 const std::string expected_side_data = "SideDataSample";
2605 scoped_refptr<net::IOBuffer> buffer =
2606 base::MakeRefCounted<net::StringIOBuffer>(expected_side_data);
2607
2608 std::unique_ptr<base::RunLoop> loop(new base::RunLoop());
2609 cache_->WriteSideData(
2610 base::BindOnce(&CacheStorageCacheTest::ErrorTypeCallback,
2611 base::Unretained(this), base::Unretained(loop.get())),
2612 BodyUrl(), response_time, /* trace_id = */ 0, buffer,
2613 expected_side_data.length());
2614
2615 // Blocks on opening the cache entry.
2616 base::RunLoop().RunUntilIdle();
2617
2618 // Since an operation is outstanding the cache should consider itself
2619 // referenced.
2620 EXPECT_FALSE(cache_->IsUnreferenced());
2621
2622 // Allow the operation to continue.
2623 EXPECT_TRUE(delayable_backend->OpenEntryContinue());
2624 loop->Run();
2625
2626 // The operation should succeed.
2627 EXPECT_EQ(CacheStorageError::kSuccess, callback_error_);
2628 }
2629
TEST_P(CacheStorageCacheTestP,SelfRefsDuringBatchOperation)2630 TEST_P(CacheStorageCacheTestP, SelfRefsDuringBatchOperation) {
2631 // Open the backend
2632 EXPECT_TRUE(Keys());
2633
2634 blink::mojom::BatchOperationPtr operation =
2635 blink::mojom::BatchOperation::New();
2636 operation->operation_type = blink::mojom::OperationType::kPut;
2637 operation->request = BackgroundFetchSettledFetch::CloneRequest(body_request_);
2638 operation->request->url = GURL("http://example.com/1");
2639 operation->response = CreateBlobBodyResponse();
2640 operation->response->url_list.emplace_back("http://example.com/1");
2641
2642 std::vector<blink::mojom::BatchOperationPtr> operations;
2643 operations.push_back(std::move(operation));
2644
2645 // When there are no operations outstanding and we're not holding an
2646 // explicit reference the cache should consider itself unreferenced.
2647 EXPECT_TRUE(cache_->IsUnreferenced());
2648
2649 DelayableBackend* delayable_backend = cache_->UseDelayableBackend();
2650 delayable_backend->set_delay_open_entry(true);
2651
2652 std::unique_ptr<base::RunLoop> loop(new base::RunLoop());
2653 cache_->BatchOperation(
2654 std::move(operations), /* trace_id = */ 0,
2655 base::BindOnce(&CacheStorageCacheTest::VerboseErrorTypeCallback,
2656 base::Unretained(this), base::Unretained(loop.get())),
2657 base::BindOnce(&OnBadMessage, base::Unretained(&bad_message_reason_)));
2658
2659 // Blocks on opening the cache entry.
2660 base::RunLoop().RunUntilIdle();
2661
2662 // Since an operation is outstanding the cache should consider itself
2663 // referenced.
2664 EXPECT_FALSE(cache_->IsUnreferenced());
2665
2666 // Allow the operation to continue.
2667 EXPECT_TRUE(delayable_backend->OpenEntryContinue());
2668 loop->Run();
2669
2670 // The operation should succeed.
2671 EXPECT_EQ(CacheStorageError::kSuccess, callback_error_);
2672 }
2673
TEST_P(CacheStorageCacheTestP,SelfRefsDuringKeys)2674 TEST_P(CacheStorageCacheTestP, SelfRefsDuringKeys) {
2675 EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
2676
2677 // When there are no operations outstanding and we're not holding an
2678 // explicit reference the cache should consider itself unreferenced.
2679 EXPECT_TRUE(cache_->IsUnreferenced());
2680
2681 DelayableBackend* delayable_backend = cache_->UseDelayableBackend();
2682 delayable_backend->set_delay_open_entry(true);
2683
2684 std::unique_ptr<base::RunLoop> loop(new base::RunLoop());
2685 cache_->Keys(
2686 BackgroundFetchSettledFetch::CloneRequest(body_request_),
2687 /* match_options = */ nullptr,
2688 /* trace_id = */ 0,
2689 base::BindOnce(&CacheStorageCacheTest::RequestsCallback,
2690 base::Unretained(this), base::Unretained(loop.get())));
2691
2692 // Blocks on opening the cache entry.
2693 base::RunLoop().RunUntilIdle();
2694
2695 // Since an operation is outstanding the cache should consider itself
2696 // referenced.
2697 EXPECT_FALSE(cache_->IsUnreferenced());
2698
2699 // Allow the operation to continue.
2700 EXPECT_TRUE(delayable_backend->OpenEntryContinue());
2701 loop->Run();
2702
2703 // The operation should succeed.
2704 EXPECT_EQ(CacheStorageError::kSuccess, callback_error_);
2705 }
2706
TEST_P(CacheStorageCacheTestP,SelfRefsDuringPut)2707 TEST_P(CacheStorageCacheTestP, SelfRefsDuringPut) {
2708 // Open the backend
2709 EXPECT_TRUE(Keys());
2710
2711 // When there are no operations outstanding and we're not holding an
2712 // explicit reference the cache should consider itself unreferenced.
2713 EXPECT_TRUE(cache_->IsUnreferenced());
2714
2715 DelayableBackend* delayable_backend = cache_->UseDelayableBackend();
2716 delayable_backend->set_delay_open_entry(true);
2717
2718 std::unique_ptr<base::RunLoop> loop(new base::RunLoop());
2719 cache_->Put(
2720 BackgroundFetchSettledFetch::CloneRequest(body_request_),
2721 CreateBlobBodyResponse(), /* trace_id = */ 0,
2722 base::BindOnce(&CacheStorageCacheTest::ErrorTypeCallback,
2723 base::Unretained(this), base::Unretained(loop.get())));
2724
2725 // Blocks on opening the cache entry.
2726 base::RunLoop().RunUntilIdle();
2727
2728 // Since an operation is outstanding the cache should consider itself
2729 // referenced.
2730 EXPECT_FALSE(cache_->IsUnreferenced());
2731
2732 // Allow the operation to continue.
2733 EXPECT_TRUE(delayable_backend->OpenEntryContinue());
2734 loop->Run();
2735
2736 // The operation should succeed.
2737 EXPECT_EQ(CacheStorageError::kSuccess, callback_error_);
2738 }
2739
TEST_P(CacheStorageCacheTestP,PutFailCreateEntry)2740 TEST_P(CacheStorageCacheTestP, PutFailCreateEntry) {
2741 // Open the backend.
2742 EXPECT_TRUE(Keys());
2743 std::unique_ptr<base::RunLoop> run_loop;
2744 cache_->UseFailableBackend(FailableBackend::FailureStage::CREATE_ENTRY);
2745 cache_->Put(
2746 BackgroundFetchSettledFetch::CloneRequest(body_request_),
2747 CreateBlobBodyResponse(), /* trace_id = */ 0,
2748 base::BindOnce(&CacheStorageCacheTest::ErrorTypeCallback,
2749 base::Unretained(this), base::Unretained(run_loop.get())));
2750
2751 // Blocks on opening the cache entry.
2752 base::RunLoop().RunUntilIdle();
2753
2754 // The operation should fail.
2755 EXPECT_EQ(CacheStorageError::kErrorExists, callback_error_);
2756
2757 // QuotaManager should have been notified of write failures.
2758 ASSERT_EQ(1U, mock_quota_manager_->write_error_tracker().size());
2759 EXPECT_EQ(1,
2760 /*error_count*/ mock_quota_manager_->write_error_tracker()
2761 .begin()
2762 ->second);
2763
2764 EXPECT_FALSE(Put(body_request_, CreateBlobBodyResponse()));
2765 ASSERT_EQ(1U, mock_quota_manager_->write_error_tracker().size());
2766 EXPECT_EQ(2,
2767 /*error_count*/ mock_quota_manager_->write_error_tracker()
2768 .begin()
2769 ->second);
2770 }
2771
TEST_P(CacheStorageCacheTestP,PutFailWriteHeaders)2772 TEST_P(CacheStorageCacheTestP, PutFailWriteHeaders) {
2773 // Only interested in quota being notified for disk write errors
2774 // as opposed to errors from a memory only scenario.
2775 if (MemoryOnly()) {
2776 return;
2777 }
2778
2779 // Open the backend.
2780 EXPECT_TRUE(Keys());
2781
2782 std::unique_ptr<base::RunLoop> run_loop;
2783 cache_->UseFailableBackend(FailableBackend::FailureStage::WRITE_HEADERS);
2784
2785 EXPECT_FALSE(Put(body_request_, CreateBlobBodyResponse()));
2786 // Blocks on opening the cache entry.
2787 base::RunLoop().RunUntilIdle();
2788
2789 // The operation should fail.
2790 EXPECT_EQ(CacheStorageError::kErrorStorage, callback_error_);
2791
2792 // QuotaManager should have been notified of write failures.
2793 ASSERT_EQ(1U, mock_quota_manager_->write_error_tracker().size());
2794 EXPECT_EQ(1,
2795 /*error_count*/ mock_quota_manager_->write_error_tracker()
2796 .begin()
2797 ->second);
2798
2799 EXPECT_FALSE(Put(body_request_, CreateBlobBodyResponse()));
2800 ASSERT_EQ(1U, mock_quota_manager_->write_error_tracker().size());
2801 EXPECT_EQ(2,
2802 /*error_count*/ mock_quota_manager_->write_error_tracker()
2803 .begin()
2804 ->second);
2805 }
2806
2807 INSTANTIATE_TEST_SUITE_P(CacheStorageCacheTest,
2808 CacheStorageCacheTestP,
2809 ::testing::Values(false, true));
2810 } // namespace cache_storage_cache_unittest
2811 } // namespace content
2812