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