xref: /aosp_15_r20/external/cronet/base/files/important_file_writer_cleaner_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2020 The Chromium Authors
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 "base/files/important_file_writer_cleaner.h"
6 
7 #include <optional>
8 
9 #include "base/check.h"
10 #include "base/files/file.h"
11 #include "base/files/file_path.h"
12 #include "base/files/file_util.h"
13 #include "base/files/scoped_temp_dir.h"
14 #include "base/task/thread_pool.h"
15 #include "base/test/bind.h"
16 #include "base/test/task_environment.h"
17 #include "base/test/test_waitable_event.h"
18 #include "base/time/time.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 
22 using ::testing::ElementsAre;
23 
24 namespace base {
25 
26 class ImportantFileWriterCleanerTest : public ::testing::Test {
27  public:
ImportantFileWriterCleanerTest()28   ImportantFileWriterCleanerTest()
29       : old_file_time_(ImportantFileWriterCleaner::GetInstance()
30                            .GetUpperBoundTimeForTest() -
31                        Milliseconds(1)) {}
32 
33  protected:
34   // Initializes and Starts the global cleaner at construction and Stops it
35   // at destruction. ("Lifetime" refers to its activity rather than existence.)
36   class ScopedCleanerLifetime {
37    public:
ScopedCleanerLifetime()38     ScopedCleanerLifetime() {
39       auto& instance = ImportantFileWriterCleaner::GetInstance();
40       instance.Initialize();
41       instance.Start();
42     }
43     ScopedCleanerLifetime(const ScopedCleanerLifetime&) = delete;
44     ScopedCleanerLifetime& operator=(const ScopedCleanerLifetime&) = delete;
~ScopedCleanerLifetime()45     ~ScopedCleanerLifetime() {
46       ImportantFileWriterCleaner::GetInstance().Stop();
47     }
48   };
49 
50   void SetUp() override;
51   void TearDown() override;
52 
dir_1() const53   const FilePath& dir_1() const { return dir_1_; }
dir_1_file_new() const54   const FilePath& dir_1_file_new() const { return dir_1_file_new_; }
dir_1_file_old() const55   const FilePath& dir_1_file_old() const { return dir_1_file_old_; }
dir_1_file_other() const56   const FilePath& dir_1_file_other() const { return dir_1_file_other_; }
dir_2() const57   const FilePath& dir_2() const { return dir_2_; }
dir_2_file_new() const58   const FilePath& dir_2_file_new() const { return dir_2_file_new_; }
dir_2_file_old() const59   const FilePath& dir_2_file_old() const { return dir_2_file_old_; }
dir_2_file_other() const60   const FilePath& dir_2_file_other() const { return dir_2_file_other_; }
61 
StartCleaner()62   void StartCleaner() {
63     DCHECK(!cleaner_lifetime_.has_value());
64     cleaner_lifetime_.emplace();
65   }
66 
StopCleaner()67   void StopCleaner() {
68     DCHECK(cleaner_lifetime_.has_value());
69     cleaner_lifetime_.reset();
70   }
71 
CreateNewFileInDir(const FilePath & dir,FilePath & path)72   void CreateNewFileInDir(const FilePath& dir, FilePath& path) {
73     File file = CreateAndOpenTemporaryFileInDir(dir, &path);
74     ASSERT_TRUE(file.IsValid());
75   }
76 
CreateOldFileInDir(const FilePath & dir,FilePath & path)77   void CreateOldFileInDir(const FilePath& dir, FilePath& path) {
78     File file = CreateAndOpenTemporaryFileInDir(dir, &path);
79     ASSERT_TRUE(file.IsValid());
80     ASSERT_TRUE(file.SetTimes(Time::Now(), old_file_time_));
81   }
82 
CreateOldFile(const FilePath & path)83   void CreateOldFile(const FilePath& path) {
84     File file(path, File::FLAG_CREATE | File::FLAG_WRITE);
85     ASSERT_TRUE(file.IsValid());
86     ASSERT_TRUE(file.SetTimes(Time::Now(), old_file_time_));
87   }
88 
89   ScopedTempDir temp_dir_;
90   test::TaskEnvironment task_environment_;
91 
92  private:
93   const Time old_file_time_;
94   FilePath dir_1_;
95   FilePath dir_2_;
96   FilePath dir_1_file_new_;
97   FilePath dir_1_file_old_;
98   FilePath dir_1_file_other_;
99   FilePath dir_2_file_new_;
100   FilePath dir_2_file_old_;
101   FilePath dir_2_file_other_;
102   std::optional<ScopedCleanerLifetime> cleaner_lifetime_;
103 };
104 
SetUp()105 void ImportantFileWriterCleanerTest::SetUp() {
106   ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
107 
108   // Create two directories that will hold files to be cleaned.
109   dir_1_ = temp_dir_.GetPath().Append(FILE_PATH_LITERAL("dir_1"));
110   ASSERT_TRUE(CreateDirectory(dir_1_));
111   dir_2_ = temp_dir_.GetPath().Append(FILE_PATH_LITERAL("dir_2"));
112   ASSERT_TRUE(CreateDirectory(dir_2_));
113 
114   // Create some old and new files in each dir.
115   ASSERT_NO_FATAL_FAILURE(CreateNewFileInDir(dir_1_, dir_1_file_new_));
116 
117   ASSERT_NO_FATAL_FAILURE(CreateOldFileInDir(dir_1_, dir_1_file_old_));
118 
119   dir_1_file_other_ = dir_1_.Append(FILE_PATH_LITERAL("other.nottmp"));
120   ASSERT_NO_FATAL_FAILURE(CreateOldFile(dir_1_file_other_));
121 
122   ASSERT_NO_FATAL_FAILURE(CreateNewFileInDir(dir_2_, dir_2_file_new_));
123 
124   ASSERT_NO_FATAL_FAILURE(CreateOldFileInDir(dir_2_, dir_2_file_old_));
125 
126   dir_2_file_other_ = dir_2_.Append(FILE_PATH_LITERAL("other.nottmp"));
127   ASSERT_NO_FATAL_FAILURE(CreateOldFile(dir_2_file_other_));
128 }
129 
TearDown()130 void ImportantFileWriterCleanerTest::TearDown() {
131   cleaner_lifetime_.reset();
132   task_environment_.RunUntilIdle();
133   ImportantFileWriterCleaner::GetInstance().UninitializeForTesting();
134   EXPECT_TRUE(temp_dir_.Delete());
135 }
136 
137 // Tests that adding a directory without initializing the cleaner does nothing.
TEST_F(ImportantFileWriterCleanerTest,NotInitializedNoOpAdd)138 TEST_F(ImportantFileWriterCleanerTest, NotInitializedNoOpAdd) {
139   ImportantFileWriterCleaner::AddDirectory(dir_1());
140   task_environment_.RunUntilIdle();
141   EXPECT_TRUE(PathExists(dir_1_file_new()));
142   EXPECT_TRUE(PathExists(dir_1_file_old()));
143   EXPECT_TRUE(PathExists(dir_1_file_other()));
144   EXPECT_TRUE(PathExists(dir_2_file_new()));
145   EXPECT_TRUE(PathExists(dir_2_file_old()));
146   EXPECT_TRUE(PathExists(dir_2_file_other()));
147 }
148 
149 // Tests that adding a directory without starting the cleaner does nothing.
TEST_F(ImportantFileWriterCleanerTest,NotStartedNoOpAdd)150 TEST_F(ImportantFileWriterCleanerTest, NotStartedNoOpAdd) {
151   ImportantFileWriterCleaner::GetInstance().Initialize();
152   ImportantFileWriterCleaner::AddDirectory(dir_1());
153   task_environment_.RunUntilIdle();
154   EXPECT_TRUE(PathExists(dir_1_file_new()));
155   EXPECT_TRUE(PathExists(dir_1_file_old()));
156   EXPECT_TRUE(PathExists(dir_1_file_other()));
157   EXPECT_TRUE(PathExists(dir_2_file_new()));
158   EXPECT_TRUE(PathExists(dir_2_file_old()));
159   EXPECT_TRUE(PathExists(dir_2_file_other()));
160 }
161 
162 // Tests that starting and stopping does no harm.
TEST_F(ImportantFileWriterCleanerTest,StartStop)163 TEST_F(ImportantFileWriterCleanerTest, StartStop) {
164   StartCleaner();
165   StopCleaner();
166 }
167 
168 // Tests that adding a directory then starting the cleaner works.
TEST_F(ImportantFileWriterCleanerTest,AddStart)169 TEST_F(ImportantFileWriterCleanerTest, AddStart) {
170   ImportantFileWriterCleaner::GetInstance().Initialize();
171   ImportantFileWriterCleaner::AddDirectory(dir_1());
172   StartCleaner();
173   task_environment_.RunUntilIdle();
174 
175   // The old file should have been cleaned from the added dir.
176   EXPECT_TRUE(PathExists(dir_1_file_new()));
177   EXPECT_FALSE(PathExists(dir_1_file_old()));
178   EXPECT_TRUE(PathExists(dir_1_file_other()));
179   EXPECT_TRUE(PathExists(dir_2_file_new()));
180   EXPECT_TRUE(PathExists(dir_2_file_old()));
181   EXPECT_TRUE(PathExists(dir_2_file_other()));
182 }
183 
184 // Tests that adding multiple directories before starting cleans both.
TEST_F(ImportantFileWriterCleanerTest,AddAddStart)185 TEST_F(ImportantFileWriterCleanerTest, AddAddStart) {
186   ImportantFileWriterCleaner::GetInstance().Initialize();
187   ImportantFileWriterCleaner::AddDirectory(dir_1());
188   ImportantFileWriterCleaner::AddDirectory(dir_2());
189   StartCleaner();
190   task_environment_.RunUntilIdle();
191 
192   // The old file should have been cleaned from both added dirs.
193   EXPECT_TRUE(PathExists(dir_1_file_new()));
194   EXPECT_FALSE(PathExists(dir_1_file_old()));
195   EXPECT_TRUE(PathExists(dir_1_file_other()));
196   EXPECT_TRUE(PathExists(dir_2_file_new()));
197   EXPECT_FALSE(PathExists(dir_2_file_old()));
198   EXPECT_TRUE(PathExists(dir_2_file_other()));
199 }
200 
201 // Tests that starting the cleaner then adding a directory works.
TEST_F(ImportantFileWriterCleanerTest,StartAdd)202 TEST_F(ImportantFileWriterCleanerTest, StartAdd) {
203   StartCleaner();
204   ImportantFileWriterCleaner::AddDirectory(dir_1());
205   task_environment_.RunUntilIdle();
206 
207   // The old file should have been cleaned from the added dir.
208   EXPECT_TRUE(PathExists(dir_1_file_new()));
209   EXPECT_FALSE(PathExists(dir_1_file_old()));
210   EXPECT_TRUE(PathExists(dir_1_file_other()));
211   EXPECT_TRUE(PathExists(dir_2_file_new()));
212   EXPECT_TRUE(PathExists(dir_2_file_old()));
213   EXPECT_TRUE(PathExists(dir_2_file_other()));
214 }
215 
216 // Tests that starting the cleaner twice doesn't cause it to clean twice.
TEST_F(ImportantFileWriterCleanerTest,StartTwice)217 TEST_F(ImportantFileWriterCleanerTest, StartTwice) {
218   StartCleaner();
219   ImportantFileWriterCleaner::AddDirectory(dir_1());
220   task_environment_.RunUntilIdle();
221 
222   // Recreate the old file that was just cleaned.
223   ASSERT_NO_FATAL_FAILURE(CreateOldFile(dir_1_file_old()));
224 
225   // Start again and make sure it wasn't cleaned again.
226   ImportantFileWriterCleaner::GetInstance().Start();
227   task_environment_.RunUntilIdle();
228 
229   EXPECT_TRUE(PathExists(dir_1_file_old()));
230 }
231 
232 // Tests that adding a dir twice doesn't cause it to clean twice.
TEST_F(ImportantFileWriterCleanerTest,AddTwice)233 TEST_F(ImportantFileWriterCleanerTest, AddTwice) {
234   StartCleaner();
235   ImportantFileWriterCleaner::AddDirectory(dir_1());
236   task_environment_.RunUntilIdle();
237 
238   // Recreate the old file that was just cleaned.
239   ASSERT_NO_FATAL_FAILURE(CreateOldFile(dir_1_file_old()));
240 
241   // Add the directory again and make sure nothing else is cleaned.
242   ImportantFileWriterCleaner::AddDirectory(dir_1());
243   task_environment_.RunUntilIdle();
244 
245   EXPECT_TRUE(PathExists(dir_1_file_old()));
246 }
247 
248 // Tests that AddDirectory called from another thread properly bounces back to
249 // the main thread for processing.
TEST_F(ImportantFileWriterCleanerTest,StartAddFromOtherThread)250 TEST_F(ImportantFileWriterCleanerTest, StartAddFromOtherThread) {
251   StartCleaner();
252 
253   // Add from the ThreadPool and wait for it to finish.
254   TestWaitableEvent waitable_event;
255   ThreadPool::PostTask(FROM_HERE, BindLambdaForTesting([&]() {
256                          ImportantFileWriterCleaner::AddDirectory(dir_1());
257                          waitable_event.Signal();
258                        }));
259   waitable_event.Wait();
260 
261   // Allow the cleaner to run.
262   task_environment_.RunUntilIdle();
263 
264   // The old file should have been cleaned from the added dir.
265   EXPECT_TRUE(PathExists(dir_1_file_new()));
266   EXPECT_FALSE(PathExists(dir_1_file_old()));
267   EXPECT_TRUE(PathExists(dir_1_file_other()));
268   EXPECT_TRUE(PathExists(dir_2_file_new()));
269   EXPECT_TRUE(PathExists(dir_2_file_old()));
270   EXPECT_TRUE(PathExists(dir_2_file_other()));
271 }
272 
273 // Tests that adding a directory while a session is processing a previous
274 // directory works.
TEST_F(ImportantFileWriterCleanerTest,AddStartAdd)275 TEST_F(ImportantFileWriterCleanerTest, AddStartAdd) {
276   ImportantFileWriterCleaner::GetInstance().Initialize();
277   ImportantFileWriterCleaner::AddDirectory(dir_1());
278   StartCleaner();
279   ImportantFileWriterCleaner::AddDirectory(dir_2());
280   task_environment_.RunUntilIdle();
281 
282   // The old file should have been cleaned from both added dirs.
283   EXPECT_TRUE(PathExists(dir_1_file_new()));
284   EXPECT_FALSE(PathExists(dir_1_file_old()));
285   EXPECT_TRUE(PathExists(dir_1_file_other()));
286   EXPECT_TRUE(PathExists(dir_2_file_new()));
287   EXPECT_FALSE(PathExists(dir_2_file_old()));
288   EXPECT_TRUE(PathExists(dir_2_file_other()));
289 }
290 
291 // Tests stopping while the background task is running.
TEST_F(ImportantFileWriterCleanerTest,StopWhileRunning)292 TEST_F(ImportantFileWriterCleanerTest, StopWhileRunning) {
293   ImportantFileWriterCleaner::GetInstance().Initialize();
294 
295   // Create a great many old files in dir1.
296   for (int i = 0; i < 100; ++i) {
297     FilePath path;
298     CreateOldFileInDir(dir_1(), path);
299   }
300 
301   ImportantFileWriterCleaner::AddDirectory(dir_1());
302   StartCleaner();
303 
304   // It's possible that the background task will quickly delete all 100 files.
305   // In all likelihood, though, the stop flag will be read and processed before
306   // then. Either case is a success.
307   StopCleaner();
308   task_environment_.RunUntilIdle();
309 }
310 
311 }  // namespace base
312