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