1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "content/browser/service_worker/service_worker_disk_cache.h"
6 
7 #include "base/callback_helpers.h"
8 #include "base/files/file_util.h"
9 #include "base/files/scoped_temp_dir.h"
10 #include "base/test/bind.h"
11 #include "base/test/task_environment.h"
12 #include "net/base/net_errors.h"
13 #include "net/base/test_completion_callback.h"
14 #include "net/disk_cache/disk_cache.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 
17 namespace content {
18 
19 class ServiceWorkerDiskCacheTest : public testing::Test {
20  public:
21   ServiceWorkerDiskCacheTest() = default;
22 
SetUp()23   void SetUp() override { ASSERT_TRUE(directory_.CreateUniqueTempDir()); }
24 
TearDown()25   void TearDown() override { FlushCacheTasks(); }
26 
FlushCacheTasks()27   void FlushCacheTasks() {
28     disk_cache::FlushCacheThreadForTesting();
29     task_environment_.RunUntilIdle();
30   }
31 
InitializeDiskCache(ServiceWorkerDiskCache * disk_cache)32   void InitializeDiskCache(ServiceWorkerDiskCache* disk_cache) {
33     base::RunLoop loop;
34     disk_cache->InitWithDiskBackend(
35         GetPath(), false,
36         /*post_cleanup_callback=*/base::DoNothing::Once(),
37         base::BindLambdaForTesting([&](int rv) {
38           ASSERT_EQ(rv, net::OK);
39           loop.Quit();
40         }));
41     loop.Run();
42   }
43 
GetPath()44   base::FilePath GetPath() { return directory_.GetPath(); }
45 
46  private:
47   base::test::TaskEnvironment task_environment_;
48   base::ScopedTempDir directory_;
49 };
50 
51 // Tests that callbacks of operations are invoked even when these operations are
52 // called at the same time for the same key.
TEST_F(ServiceWorkerDiskCacheTest,MultipleCallsForSameKey)53 TEST_F(ServiceWorkerDiskCacheTest, MultipleCallsForSameKey) {
54   auto disk_cache = std::make_unique<ServiceWorkerDiskCache>();
55 
56   bool create_entry_called = false;
57   bool open_entry_called = false;
58   bool doom_entry_called = false;
59 
60   const int64_t kKey = 1;
61   disk_cache->CreateEntry(
62       kKey, base::BindLambdaForTesting(
63                 [&](int rv, std::unique_ptr<ServiceWorkerDiskCacheEntry>) {
64                   create_entry_called = true;
65                 }));
66   disk_cache->OpenEntry(
67       kKey, base::BindLambdaForTesting(
68                 [&](int rv, std::unique_ptr<ServiceWorkerDiskCacheEntry>) {
69                   open_entry_called = true;
70                 }));
71   disk_cache->DoomEntry(kKey, base::BindLambdaForTesting(
72                                   [&](int rv) { doom_entry_called = true; }));
73 
74   InitializeDiskCache(disk_cache.get());
75   FlushCacheTasks();
76 
77   EXPECT_TRUE(create_entry_called);
78   EXPECT_TRUE(open_entry_called);
79   EXPECT_TRUE(doom_entry_called);
80 }
81 
TEST_F(ServiceWorkerDiskCacheTest,DisablePriorToInitCompletion)82 TEST_F(ServiceWorkerDiskCacheTest, DisablePriorToInitCompletion) {
83   // Create an instance and start it initializing, queue up
84   // one of each kind of "entry" function.
85   auto disk_cache = std::make_unique<ServiceWorkerDiskCache>();
86   EXPECT_FALSE(disk_cache->is_disabled());
87 
88   size_t callback_count = 0;
89   auto completion_callback = base::BindLambdaForTesting([&](int rv) {
90     EXPECT_EQ(rv, net::ERR_ABORTED);
91     ++callback_count;
92   });
93   auto entry_callback = base::BindLambdaForTesting(
94       [&](int rv, std::unique_ptr<ServiceWorkerDiskCacheEntry> entry) {
95         EXPECT_EQ(rv, net::ERR_ABORTED);
96         EXPECT_FALSE(entry);
97         ++callback_count;
98       });
99   disk_cache->InitWithDiskBackend(GetPath(), false,
100                                   /*post_cleanup_callback=*/base::DoNothing(),
101                                   completion_callback);
102   disk_cache->CreateEntry(1, entry_callback);
103   disk_cache->OpenEntry(2, entry_callback);
104   disk_cache->DoomEntry(3, completion_callback);
105 
106   // Pull the plug on all that.
107   EXPECT_FALSE(disk_cache->is_disabled());
108   disk_cache->Disable();
109   EXPECT_TRUE(disk_cache->is_disabled());
110 
111   FlushCacheTasks();
112 
113   EXPECT_EQ(callback_count, 4u);
114 
115   // Ensure the directory can be deleted at this point.
116   EXPECT_TRUE(base::DirectoryExists(GetPath()));
117   EXPECT_FALSE(base::IsDirectoryEmpty(GetPath()));
118   EXPECT_TRUE(base::DeletePathRecursively(GetPath()));
119   EXPECT_FALSE(base::DirectoryExists(GetPath()));
120 }
121 
TEST_F(ServiceWorkerDiskCacheTest,DisableAfterInitted)122 TEST_F(ServiceWorkerDiskCacheTest, DisableAfterInitted) {
123   // Create an instance and start it initializing, queue up
124   // one of each kind of "entry" function.
125   auto disk_cache = std::make_unique<ServiceWorkerDiskCache>();
126   EXPECT_FALSE(disk_cache->is_disabled());
127   InitializeDiskCache(disk_cache.get());
128 
129   // Pull the plug
130   disk_cache->Disable();
131   FlushCacheTasks();
132 
133   // Ensure the directory can be deleted at this point.
134   EXPECT_TRUE(base::DirectoryExists(GetPath()));
135   EXPECT_FALSE(base::IsDirectoryEmpty(GetPath()));
136   EXPECT_TRUE(base::DeletePathRecursively(GetPath()));
137   EXPECT_FALSE(base::DirectoryExists(GetPath()));
138 
139   // Methods should fail.
140   size_t callback_count = 0;
141   auto completion_callback = base::BindLambdaForTesting([&](int rv) {
142     EXPECT_EQ(rv, net::ERR_ABORTED);
143     ++callback_count;
144   });
145   auto entry_callback = base::BindLambdaForTesting(
146       [&](int rv, std::unique_ptr<ServiceWorkerDiskCacheEntry> entry) {
147         EXPECT_EQ(rv, net::ERR_ABORTED);
148         EXPECT_FALSE(entry);
149         ++callback_count;
150       });
151   disk_cache->CreateEntry(1, entry_callback);
152   disk_cache->OpenEntry(2, entry_callback);
153   disk_cache->DoomEntry(3, completion_callback);
154   FlushCacheTasks();
155 
156   EXPECT_EQ(callback_count, 3u);
157 }
158 
TEST_F(ServiceWorkerDiskCacheTest,CleanupCallback)159 TEST_F(ServiceWorkerDiskCacheTest, CleanupCallback) {
160   // Test that things delete fine when we disable the cache and wait for
161   // the cleanup callback.
162 
163   net::TestClosure cleanup_done;
164   net::TestCompletionCallback init_done;
165   auto disk_cache = std::make_unique<ServiceWorkerDiskCache>();
166   EXPECT_FALSE(disk_cache->is_disabled());
167   disk_cache->InitWithDiskBackend(GetPath(), false, cleanup_done.closure(),
168                                   init_done.callback());
169   EXPECT_EQ(net::OK, init_done.WaitForResult());
170 
171   disk_cache->Disable();
172   cleanup_done.WaitForResult();
173 
174   // Ensure the directory can be deleted at this point.
175   EXPECT_TRUE(base::DirectoryExists(GetPath()));
176   EXPECT_FALSE(base::IsDirectoryEmpty(GetPath()));
177   EXPECT_TRUE(base::DeletePathRecursively(GetPath()));
178   EXPECT_FALSE(base::DirectoryExists(GetPath()));
179 }
180 
181 }  // namespace content
182