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