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