xref: /aosp_15_r20/external/cronet/base/files/file_proxy_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2014 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/file_proxy.h"
6 
7 #include <stddef.h>
8 #include <stdint.h>
9 
10 #include <string_view>
11 #include <utility>
12 
13 #include "base/containers/heap_array.h"
14 #include "base/files/file.h"
15 #include "base/files/file_util.h"
16 #include "base/files/scoped_temp_dir.h"
17 #include "base/functional/bind.h"
18 #include "base/memory/weak_ptr.h"
19 #include "base/run_loop.h"
20 #include "base/test/task_environment.h"
21 #include "base/threading/platform_thread.h"
22 #include "base/threading/thread.h"
23 #include "base/threading/thread_restrictions.h"
24 #include "build/build_config.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26 
27 namespace base {
28 
29 class FileProxyTest : public testing::Test {
30  public:
FileProxyTest()31   FileProxyTest()
32       : task_environment_(test::TaskEnvironment::MainThreadType::IO),
33         file_thread_("FileProxyTestFileThread"),
34         error_(File::FILE_OK),
35         bytes_written_(-1) {}
36 
SetUp()37   void SetUp() override {
38     ASSERT_TRUE(dir_.CreateUniqueTempDir());
39     ASSERT_TRUE(file_thread_.Start());
40   }
41 
DidFinish(base::RepeatingClosure continuation,File::Error error)42   void DidFinish(base::RepeatingClosure continuation, File::Error error) {
43     error_ = error;
44     continuation.Run();
45   }
46 
DidCreateOrOpen(base::RepeatingClosure continuation,File::Error error)47   void DidCreateOrOpen(base::RepeatingClosure continuation, File::Error error) {
48     error_ = error;
49     continuation.Run();
50   }
51 
DidCreateTemporary(base::RepeatingClosure continuation,File::Error error,const FilePath & path)52   void DidCreateTemporary(base::RepeatingClosure continuation,
53                           File::Error error,
54                           const FilePath& path) {
55     error_ = error;
56     path_ = path;
57     continuation.Run();
58   }
59 
DidGetFileInfo(base::RepeatingClosure continuation,File::Error error,const File::Info & file_info)60   void DidGetFileInfo(base::RepeatingClosure continuation,
61                       File::Error error,
62                       const File::Info& file_info) {
63     error_ = error;
64     file_info_ = file_info;
65     continuation.Run();
66   }
67 
DidRead(base::RepeatingClosure continuation,File::Error error,base::span<const char> data)68   void DidRead(base::RepeatingClosure continuation,
69                File::Error error,
70                base::span<const char> data) {
71     error_ = error;
72     buffer_ = base::HeapArray<char>::CopiedFrom(data);
73     continuation.Run();
74   }
75 
DidWrite(base::RepeatingClosure continuation,File::Error error,int bytes_written)76   void DidWrite(base::RepeatingClosure continuation,
77                 File::Error error,
78                 int bytes_written) {
79     error_ = error;
80     bytes_written_ = bytes_written;
81     continuation.Run();
82   }
83 
84  protected:
CreateProxy(uint32_t flags,FileProxy * proxy)85   void CreateProxy(uint32_t flags, FileProxy* proxy) {
86     RunLoop run_loop;
87     proxy->CreateOrOpen(
88         TestPath(), flags,
89         BindOnce(&FileProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr(),
90                  run_loop.QuitWhenIdleClosure()));
91     run_loop.Run();
92     EXPECT_TRUE(proxy->IsValid());
93   }
94 
file_task_runner() const95   TaskRunner* file_task_runner() const {
96     return file_thread_.task_runner().get();
97   }
TestDirPath() const98   const FilePath& TestDirPath() const { return dir_.GetPath(); }
TestPath() const99   const FilePath TestPath() const { return dir_.GetPath().AppendASCII("test"); }
100 
101   ScopedTempDir dir_;
102   test::TaskEnvironment task_environment_;
103   Thread file_thread_;
104 
105   File::Error error_;
106   FilePath path_;
107   File::Info file_info_;
108   base::HeapArray<char> buffer_;
109   int bytes_written_;
110   WeakPtrFactory<FileProxyTest> weak_factory_{this};
111 };
112 
TEST_F(FileProxyTest,CreateOrOpen_Create)113 TEST_F(FileProxyTest, CreateOrOpen_Create) {
114   FileProxy proxy(file_task_runner());
115   RunLoop run_loop;
116   proxy.CreateOrOpen(
117       TestPath(), File::FLAG_CREATE | File::FLAG_READ,
118       BindOnce(&FileProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr(),
119                run_loop.QuitWhenIdleClosure()));
120   run_loop.Run();
121 
122   EXPECT_EQ(File::FILE_OK, error_);
123   EXPECT_TRUE(proxy.IsValid());
124   EXPECT_TRUE(proxy.created());
125   EXPECT_TRUE(PathExists(TestPath()));
126 }
127 
TEST_F(FileProxyTest,CreateOrOpen_Open)128 TEST_F(FileProxyTest, CreateOrOpen_Open) {
129   // Creates a file.
130   base::WriteFile(TestPath(), base::StringPiece());
131   ASSERT_TRUE(PathExists(TestPath()));
132 
133   // Opens the created file.
134   FileProxy proxy(file_task_runner());
135   RunLoop run_loop;
136   proxy.CreateOrOpen(
137       TestPath(), File::FLAG_OPEN | File::FLAG_READ,
138       BindOnce(&FileProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr(),
139                run_loop.QuitWhenIdleClosure()));
140   run_loop.Run();
141 
142   EXPECT_EQ(File::FILE_OK, error_);
143   EXPECT_TRUE(proxy.IsValid());
144   EXPECT_FALSE(proxy.created());
145 }
146 
TEST_F(FileProxyTest,CreateOrOpen_OpenNonExistent)147 TEST_F(FileProxyTest, CreateOrOpen_OpenNonExistent) {
148   FileProxy proxy(file_task_runner());
149   RunLoop run_loop;
150   proxy.CreateOrOpen(
151       TestPath(), File::FLAG_OPEN | File::FLAG_READ,
152       BindOnce(&FileProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr(),
153                run_loop.QuitWhenIdleClosure()));
154   run_loop.Run();
155   EXPECT_EQ(File::FILE_ERROR_NOT_FOUND, error_);
156   EXPECT_FALSE(proxy.IsValid());
157   EXPECT_FALSE(proxy.created());
158   EXPECT_FALSE(PathExists(TestPath()));
159 }
160 
TEST_F(FileProxyTest,CreateOrOpen_AbandonedCreate)161 TEST_F(FileProxyTest, CreateOrOpen_AbandonedCreate) {
162   {
163     base::ScopedDisallowBlocking disallow_blocking;
164     RunLoop run_loop;
165     {
166       FileProxy proxy(file_task_runner());
167       proxy.CreateOrOpen(
168           TestPath(), File::FLAG_CREATE | File::FLAG_READ,
169           BindOnce(&FileProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr(),
170                    run_loop.QuitWhenIdleClosure()));
171     }
172     run_loop.Run();
173   }
174 
175   EXPECT_TRUE(PathExists(TestPath()));
176 }
177 
TEST_F(FileProxyTest,Close)178 TEST_F(FileProxyTest, Close) {
179   // Creates a file.
180   FileProxy proxy(file_task_runner());
181   CreateProxy(File::FLAG_CREATE | File::FLAG_WRITE, &proxy);
182 
183 #if BUILDFLAG(IS_WIN)
184   // This fails on Windows if the file is not closed.
185   EXPECT_FALSE(base::Move(TestPath(), TestDirPath().AppendASCII("new")));
186 #endif
187 
188   RunLoop run_loop;
189   proxy.Close(BindOnce(&FileProxyTest::DidFinish, weak_factory_.GetWeakPtr(),
190                        run_loop.QuitWhenIdleClosure()));
191   run_loop.Run();
192   EXPECT_EQ(File::FILE_OK, error_);
193   EXPECT_FALSE(proxy.IsValid());
194 
195   // Now it should pass on all platforms.
196   EXPECT_TRUE(base::Move(TestPath(), TestDirPath().AppendASCII("new")));
197 }
198 
TEST_F(FileProxyTest,CreateTemporary)199 TEST_F(FileProxyTest, CreateTemporary) {
200   {
201     FileProxy proxy(file_task_runner());
202     {
203       RunLoop run_loop;
204       proxy.CreateTemporary(
205           0 /* additional_file_flags */,
206           BindOnce(&FileProxyTest::DidCreateTemporary,
207                    weak_factory_.GetWeakPtr(), run_loop.QuitWhenIdleClosure()));
208       run_loop.Run();
209     }
210 
211     EXPECT_TRUE(proxy.IsValid());
212     EXPECT_EQ(File::FILE_OK, error_);
213     EXPECT_TRUE(PathExists(path_));
214 
215     // The file should be writable.
216     {
217       RunLoop run_loop;
218       proxy.Write(0, base::as_byte_span(std::string_view("test")),
219                   BindOnce(&FileProxyTest::DidWrite, weak_factory_.GetWeakPtr(),
220                            run_loop.QuitWhenIdleClosure()));
221       run_loop.Run();
222     }
223     EXPECT_EQ(File::FILE_OK, error_);
224     EXPECT_EQ(4, bytes_written_);
225   }
226 
227   // Make sure the written data can be read from the returned path.
228   std::string data;
229   EXPECT_TRUE(ReadFileToString(path_, &data));
230   EXPECT_EQ("test", data);
231 
232   // Make sure we can & do delete the created file to prevent leaks on the bots.
233   // Try a few times because files may be locked by anti-virus or other.
234   bool deleted_temp_file = false;
235   for (int i = 0; !deleted_temp_file && i < 3; ++i) {
236     if (base::DeleteFile(path_))
237       deleted_temp_file = true;
238     else
239       // Wait one second and then try again
240       PlatformThread::Sleep(Seconds(1));
241   }
242   EXPECT_TRUE(deleted_temp_file);
243 }
244 
TEST_F(FileProxyTest,SetAndTake)245 TEST_F(FileProxyTest, SetAndTake) {
246   File file(TestPath(), File::FLAG_CREATE | File::FLAG_READ);
247   ASSERT_TRUE(file.IsValid());
248   FileProxy proxy(file_task_runner());
249   EXPECT_FALSE(proxy.IsValid());
250   proxy.SetFile(std::move(file));
251   EXPECT_TRUE(proxy.IsValid());
252   EXPECT_FALSE(file.IsValid());
253 
254   file = proxy.TakeFile();
255   EXPECT_FALSE(proxy.IsValid());
256   EXPECT_TRUE(file.IsValid());
257 }
258 
TEST_F(FileProxyTest,DuplicateFile)259 TEST_F(FileProxyTest, DuplicateFile) {
260   FileProxy proxy(file_task_runner());
261   CreateProxy(File::FLAG_CREATE | File::FLAG_WRITE, &proxy);
262   ASSERT_TRUE(proxy.IsValid());
263 
264   base::File duplicate = proxy.DuplicateFile();
265   EXPECT_TRUE(proxy.IsValid());
266   EXPECT_TRUE(duplicate.IsValid());
267 
268   FileProxy invalid_proxy(file_task_runner());
269   ASSERT_FALSE(invalid_proxy.IsValid());
270 
271   base::File invalid_duplicate = invalid_proxy.DuplicateFile();
272   EXPECT_FALSE(invalid_proxy.IsValid());
273   EXPECT_FALSE(invalid_duplicate.IsValid());
274 }
275 
TEST_F(FileProxyTest,GetInfo)276 TEST_F(FileProxyTest, GetInfo) {
277   // Setup.
278   ASSERT_TRUE(base::WriteFile(TestPath(), "test"));
279   File::Info expected_info;
280   GetFileInfo(TestPath(), &expected_info);
281 
282   // Run.
283   FileProxy proxy(file_task_runner());
284   CreateProxy(File::FLAG_OPEN | File::FLAG_READ, &proxy);
285   RunLoop run_loop;
286   proxy.GetInfo(BindOnce(&FileProxyTest::DidGetFileInfo,
287                          weak_factory_.GetWeakPtr(),
288                          run_loop.QuitWhenIdleClosure()));
289   run_loop.Run();
290 
291   // Verify.
292   EXPECT_EQ(File::FILE_OK, error_);
293   EXPECT_EQ(expected_info.size, file_info_.size);
294   EXPECT_EQ(expected_info.is_directory, file_info_.is_directory);
295   EXPECT_EQ(expected_info.is_symbolic_link, file_info_.is_symbolic_link);
296   EXPECT_EQ(expected_info.last_modified, file_info_.last_modified);
297   EXPECT_EQ(expected_info.creation_time, file_info_.creation_time);
298 }
299 
TEST_F(FileProxyTest,Read)300 TEST_F(FileProxyTest, Read) {
301   // Setup.
302   constexpr base::StringPiece expected_data = "bleh";
303   ASSERT_TRUE(base::WriteFile(TestPath(), expected_data));
304 
305   // Run.
306   FileProxy proxy(file_task_runner());
307   CreateProxy(File::FLAG_OPEN | File::FLAG_READ, &proxy);
308 
309   RunLoop run_loop;
310   proxy.Read(0, 128,
311              BindOnce(&FileProxyTest::DidRead, weak_factory_.GetWeakPtr(),
312                       run_loop.QuitWhenIdleClosure()));
313   run_loop.Run();
314 
315   // Verify.
316   EXPECT_EQ(File::FILE_OK, error_);
317   EXPECT_EQ(expected_data, base::StringPiece(buffer_.data(), buffer_.size()));
318 }
319 
TEST_F(FileProxyTest,WriteAndFlush)320 TEST_F(FileProxyTest, WriteAndFlush) {
321   FileProxy proxy(file_task_runner());
322   CreateProxy(File::FLAG_CREATE | File::FLAG_WRITE, &proxy);
323 
324   auto write_span = base::as_byte_span("foo!");
325   EXPECT_EQ(write_span.size(), 5u);  // Includes the NUL, too.
326   {
327     RunLoop run_loop;
328     proxy.Write(0, write_span,
329                 BindOnce(&FileProxyTest::DidWrite, weak_factory_.GetWeakPtr(),
330                          run_loop.QuitWhenIdleClosure()));
331     run_loop.Run();
332   }
333   EXPECT_EQ(File::FILE_OK, error_);
334   EXPECT_EQ(write_span.size(), static_cast<size_t>(bytes_written_));
335 
336   // Flush the written data.  (So that the following read should always
337   // succeed.  On some platforms it may work with or without this flush.)
338   {
339     RunLoop run_loop;
340     proxy.Flush(BindOnce(&FileProxyTest::DidFinish, weak_factory_.GetWeakPtr(),
341                          run_loop.QuitWhenIdleClosure()));
342     run_loop.Run();
343   }
344   EXPECT_EQ(File::FILE_OK, error_);
345 
346   // Verify the written data.
347   char read_buffer[10];
348   EXPECT_GE(std::size(read_buffer), write_span.size());
349   EXPECT_EQ(write_span.size(), base::ReadFile(TestPath(), read_buffer));
350   for (size_t i = 0; i < write_span.size(); ++i) {
351     EXPECT_EQ(write_span[i], read_buffer[i]);
352   }
353 }
354 
355 #if BUILDFLAG(IS_ANDROID)
356 // Flaky on Android, see http://crbug.com/489602
357 #define MAYBE_SetTimes DISABLED_SetTimes
358 #else
359 #define MAYBE_SetTimes SetTimes
360 #endif
TEST_F(FileProxyTest,MAYBE_SetTimes)361 TEST_F(FileProxyTest, MAYBE_SetTimes) {
362   FileProxy proxy(file_task_runner());
363   CreateProxy(
364       File::FLAG_CREATE | File::FLAG_WRITE | File::FLAG_WRITE_ATTRIBUTES,
365       &proxy);
366 
367   Time last_accessed_time = Time::Now() - Days(12345);
368   Time last_modified_time = Time::Now() - Hours(98765);
369 
370   RunLoop run_loop;
371   proxy.SetTimes(last_accessed_time, last_modified_time,
372                  BindOnce(&FileProxyTest::DidFinish, weak_factory_.GetWeakPtr(),
373                           run_loop.QuitWhenIdleClosure()));
374   run_loop.Run();
375   EXPECT_EQ(File::FILE_OK, error_);
376 
377   File::Info info;
378   GetFileInfo(TestPath(), &info);
379 
380   // The returned values may only have the seconds precision, so we cast
381   // the double values to int here.
382   EXPECT_EQ(static_cast<int>(last_modified_time.InSecondsFSinceUnixEpoch()),
383             static_cast<int>(info.last_modified.InSecondsFSinceUnixEpoch()));
384 
385 #if !BUILDFLAG(IS_FUCHSIA)
386   // On Fuchsia, /tmp is noatime
387   EXPECT_EQ(static_cast<int>(last_accessed_time.InSecondsFSinceUnixEpoch()),
388             static_cast<int>(info.last_accessed.InSecondsFSinceUnixEpoch()));
389 #endif  // BUILDFLAG(IS_FUCHSIA)
390 }
391 
TEST_F(FileProxyTest,SetLength_Shrink)392 TEST_F(FileProxyTest, SetLength_Shrink) {
393   // Setup.
394   const char kTestData[] = "0123456789";
395   ASSERT_TRUE(base::WriteFile(TestPath(), kTestData));
396   File::Info info;
397   GetFileInfo(TestPath(), &info);
398   ASSERT_EQ(10, info.size);
399 
400   // Run.
401   FileProxy proxy(file_task_runner());
402   CreateProxy(File::FLAG_OPEN | File::FLAG_WRITE, &proxy);
403   RunLoop run_loop;
404   proxy.SetLength(
405       7, BindOnce(&FileProxyTest::DidFinish, weak_factory_.GetWeakPtr(),
406                   run_loop.QuitWhenIdleClosure()));
407   run_loop.Run();
408 
409   // Verify.
410   GetFileInfo(TestPath(), &info);
411   ASSERT_EQ(7, info.size);
412 
413   char buffer[7];
414   EXPECT_EQ(7, base::ReadFile(TestPath(), buffer));
415   int i = 0;
416   for (; i < 7; ++i)
417     EXPECT_EQ(kTestData[i], buffer[i]);
418 }
419 
TEST_F(FileProxyTest,SetLength_Expand)420 TEST_F(FileProxyTest, SetLength_Expand) {
421   // Setup.
422   const char kTestData[] = "9876543210";
423   ASSERT_TRUE(base::WriteFile(TestPath(), kTestData));
424   File::Info info;
425   GetFileInfo(TestPath(), &info);
426   ASSERT_EQ(10, info.size);
427 
428   // Run.
429   FileProxy proxy(file_task_runner());
430   CreateProxy(File::FLAG_OPEN | File::FLAG_WRITE, &proxy);
431   RunLoop run_loop;
432   proxy.SetLength(
433       53, BindOnce(&FileProxyTest::DidFinish, weak_factory_.GetWeakPtr(),
434                    run_loop.QuitWhenIdleClosure()));
435   run_loop.Run();
436 
437   // Verify.
438   GetFileInfo(TestPath(), &info);
439   ASSERT_EQ(53, info.size);
440 
441   char buffer[53];
442   EXPECT_EQ(53, base::ReadFile(TestPath(), buffer));
443   int i = 0;
444   for (; i < 10; ++i)
445     EXPECT_EQ(kTestData[i], buffer[i]);
446   for (; i < 53; ++i)
447     EXPECT_EQ(0, buffer[i]);
448 }
449 
450 }  // namespace base
451