OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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 "net/base/file_stream.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/callback.h" | |
9 #include "base/files/file.h" | |
10 #include "base/files/file_util.h" | |
11 #include "base/message_loop/message_loop.h" | |
12 #include "base/message_loop/message_loop_proxy.h" | |
13 #include "base/path_service.h" | |
14 #include "base/run_loop.h" | |
15 #include "base/strings/string_util.h" | |
16 #include "base/synchronization/waitable_event.h" | |
17 #include "base/test/test_timeouts.h" | |
18 #include "base/threading/sequenced_worker_pool.h" | |
19 #include "base/threading/thread_restrictions.h" | |
20 #include "net/base/capturing_net_log.h" | |
21 #include "net/base/io_buffer.h" | |
22 #include "net/base/net_errors.h" | |
23 #include "net/base/test_completion_callback.h" | |
24 #include "testing/gtest/include/gtest/gtest.h" | |
25 #include "testing/platform_test.h" | |
26 | |
27 #if defined(OS_ANDROID) | |
28 #include "base/test/test_file_util.h" | |
29 #endif | |
30 | |
31 namespace net { | |
32 | |
33 namespace { | |
34 | |
35 const char kTestData[] = "0123456789"; | |
36 const int kTestDataSize = arraysize(kTestData) - 1; | |
37 | |
38 // Creates an IOBufferWithSize that contains the kTestDataSize. | |
39 IOBufferWithSize* CreateTestDataBuffer() { | |
40 IOBufferWithSize* buf = new IOBufferWithSize(kTestDataSize); | |
41 memcpy(buf->data(), kTestData, kTestDataSize); | |
42 return buf; | |
43 } | |
44 | |
45 } // namespace | |
46 | |
47 class FileStreamTest : public PlatformTest { | |
48 public: | |
49 void SetUp() override { | |
50 PlatformTest::SetUp(); | |
51 | |
52 base::CreateTemporaryFile(&temp_file_path_); | |
53 base::WriteFile(temp_file_path_, kTestData, kTestDataSize); | |
54 } | |
55 void TearDown() override { | |
56 // FileStreamContexts must be asynchronously closed on the file task runner | |
57 // before they can be deleted. Pump the RunLoop to avoid leaks. | |
58 base::RunLoop().RunUntilIdle(); | |
59 EXPECT_TRUE(base::DeleteFile(temp_file_path_, false)); | |
60 | |
61 PlatformTest::TearDown(); | |
62 } | |
63 | |
64 const base::FilePath temp_file_path() const { return temp_file_path_; } | |
65 | |
66 private: | |
67 base::FilePath temp_file_path_; | |
68 }; | |
69 | |
70 namespace { | |
71 | |
72 TEST_F(FileStreamTest, OpenExplicitClose) { | |
73 TestCompletionCallback callback; | |
74 FileStream stream(base::MessageLoopProxy::current()); | |
75 int flags = base::File::FLAG_OPEN | | |
76 base::File::FLAG_READ | | |
77 base::File::FLAG_ASYNC; | |
78 int rv = stream.Open(temp_file_path(), flags, callback.callback()); | |
79 EXPECT_EQ(ERR_IO_PENDING, rv); | |
80 EXPECT_EQ(OK, callback.WaitForResult()); | |
81 EXPECT_TRUE(stream.IsOpen()); | |
82 EXPECT_TRUE(stream.GetFileForTesting().IsValid()); | |
83 EXPECT_EQ(ERR_IO_PENDING, stream.Close(callback.callback())); | |
84 EXPECT_EQ(OK, callback.WaitForResult()); | |
85 EXPECT_FALSE(stream.IsOpen()); | |
86 EXPECT_FALSE(stream.GetFileForTesting().IsValid()); | |
87 } | |
88 | |
89 TEST_F(FileStreamTest, OpenExplicitCloseOrphaned) { | |
90 TestCompletionCallback callback; | |
91 scoped_ptr<FileStream> stream(new FileStream( | |
92 base::MessageLoopProxy::current())); | |
93 int flags = base::File::FLAG_OPEN | base::File::FLAG_READ | | |
94 base::File::FLAG_ASYNC; | |
95 int rv = stream->Open(temp_file_path(), flags, callback.callback()); | |
96 EXPECT_EQ(ERR_IO_PENDING, rv); | |
97 EXPECT_EQ(OK, callback.WaitForResult()); | |
98 EXPECT_TRUE(stream->IsOpen()); | |
99 EXPECT_TRUE(stream->GetFileForTesting().IsValid()); | |
100 EXPECT_EQ(ERR_IO_PENDING, stream->Close(callback.callback())); | |
101 stream.reset(); | |
102 // File isn't actually closed yet. | |
103 base::RunLoop runloop; | |
104 runloop.RunUntilIdle(); | |
105 // The file should now be closed, though the callback has not been called. | |
106 } | |
107 | |
108 // Test the use of FileStream with a file handle provided at construction. | |
109 TEST_F(FileStreamTest, UseFileHandle) { | |
110 int rv = 0; | |
111 TestCompletionCallback callback; | |
112 TestInt64CompletionCallback callback64; | |
113 // 1. Test reading with a file handle. | |
114 ASSERT_EQ(kTestDataSize, | |
115 base::WriteFile(temp_file_path(), kTestData, kTestDataSize)); | |
116 int flags = base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_READ | | |
117 base::File::FLAG_ASYNC; | |
118 base::File file(temp_file_path(), flags); | |
119 | |
120 // Seek to the beginning of the file and read. | |
121 scoped_ptr<FileStream> read_stream( | |
122 new FileStream(file.Pass(), base::MessageLoopProxy::current())); | |
123 ASSERT_EQ(ERR_IO_PENDING, | |
124 read_stream->Seek(base::File::FROM_BEGIN, 0, | |
125 callback64.callback())); | |
126 ASSERT_EQ(0, callback64.WaitForResult()); | |
127 // Read into buffer and compare. | |
128 scoped_refptr<IOBufferWithSize> read_buffer = | |
129 new IOBufferWithSize(kTestDataSize); | |
130 rv = read_stream->Read(read_buffer.get(), kTestDataSize, callback.callback()); | |
131 ASSERT_EQ(kTestDataSize, callback.GetResult(rv)); | |
132 ASSERT_EQ(0, memcmp(kTestData, read_buffer->data(), kTestDataSize)); | |
133 read_stream.reset(); | |
134 | |
135 // 2. Test writing with a file handle. | |
136 base::DeleteFile(temp_file_path(), false); | |
137 flags = base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_WRITE | | |
138 base::File::FLAG_ASYNC; | |
139 file.Initialize(temp_file_path(), flags); | |
140 | |
141 scoped_ptr<FileStream> write_stream( | |
142 new FileStream(file.Pass(), base::MessageLoopProxy::current())); | |
143 ASSERT_EQ(ERR_IO_PENDING, | |
144 write_stream->Seek(base::File::FROM_BEGIN, 0, | |
145 callback64.callback())); | |
146 ASSERT_EQ(0, callback64.WaitForResult()); | |
147 scoped_refptr<IOBufferWithSize> write_buffer = CreateTestDataBuffer(); | |
148 rv = write_stream->Write(write_buffer.get(), kTestDataSize, | |
149 callback.callback()); | |
150 ASSERT_EQ(kTestDataSize, callback.GetResult(rv)); | |
151 write_stream.reset(); | |
152 | |
153 // Read into buffer and compare to make sure the handle worked fine. | |
154 ASSERT_EQ(kTestDataSize, | |
155 base::ReadFile(temp_file_path(), read_buffer->data(), | |
156 kTestDataSize)); | |
157 ASSERT_EQ(0, memcmp(kTestData, read_buffer->data(), kTestDataSize)); | |
158 } | |
159 | |
160 TEST_F(FileStreamTest, UseClosedStream) { | |
161 int rv = 0; | |
162 TestCompletionCallback callback; | |
163 TestInt64CompletionCallback callback64; | |
164 | |
165 FileStream stream(base::MessageLoopProxy::current()); | |
166 | |
167 EXPECT_FALSE(stream.IsOpen()); | |
168 | |
169 // Try seeking... | |
170 rv = stream.Seek(base::File::FROM_BEGIN, 5, callback64.callback()); | |
171 EXPECT_EQ(ERR_UNEXPECTED, callback64.GetResult(rv)); | |
172 | |
173 // Try reading... | |
174 scoped_refptr<IOBufferWithSize> buf = new IOBufferWithSize(10); | |
175 rv = stream.Read(buf.get(), buf->size(), callback.callback()); | |
176 EXPECT_EQ(ERR_UNEXPECTED, callback.GetResult(rv)); | |
177 } | |
178 | |
179 TEST_F(FileStreamTest, Read) { | |
180 int64 file_size; | |
181 EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size)); | |
182 | |
183 FileStream stream(base::MessageLoopProxy::current()); | |
184 int flags = base::File::FLAG_OPEN | base::File::FLAG_READ | | |
185 base::File::FLAG_ASYNC; | |
186 TestCompletionCallback callback; | |
187 int rv = stream.Open(temp_file_path(), flags, callback.callback()); | |
188 EXPECT_EQ(OK, callback.GetResult(rv)); | |
189 | |
190 int total_bytes_read = 0; | |
191 | |
192 std::string data_read; | |
193 for (;;) { | |
194 scoped_refptr<IOBufferWithSize> buf = new IOBufferWithSize(4); | |
195 rv = stream.Read(buf.get(), buf->size(), callback.callback()); | |
196 rv = callback.GetResult(rv); | |
197 EXPECT_LE(0, rv); | |
198 if (rv <= 0) | |
199 break; | |
200 total_bytes_read += rv; | |
201 data_read.append(buf->data(), rv); | |
202 } | |
203 EXPECT_EQ(file_size, total_bytes_read); | |
204 EXPECT_EQ(kTestData, data_read); | |
205 } | |
206 | |
207 TEST_F(FileStreamTest, Read_EarlyDelete) { | |
208 int64 file_size; | |
209 EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size)); | |
210 | |
211 scoped_ptr<FileStream> stream( | |
212 new FileStream(base::MessageLoopProxy::current())); | |
213 int flags = base::File::FLAG_OPEN | base::File::FLAG_READ | | |
214 base::File::FLAG_ASYNC; | |
215 TestCompletionCallback callback; | |
216 int rv = stream->Open(temp_file_path(), flags, callback.callback()); | |
217 EXPECT_EQ(ERR_IO_PENDING, rv); | |
218 EXPECT_EQ(OK, callback.WaitForResult()); | |
219 | |
220 scoped_refptr<IOBufferWithSize> buf = new IOBufferWithSize(4); | |
221 rv = stream->Read(buf.get(), buf->size(), callback.callback()); | |
222 stream.reset(); // Delete instead of closing it. | |
223 if (rv < 0) { | |
224 EXPECT_EQ(ERR_IO_PENDING, rv); | |
225 // The callback should not be called if the request is cancelled. | |
226 base::RunLoop().RunUntilIdle(); | |
227 EXPECT_FALSE(callback.have_result()); | |
228 } else { | |
229 EXPECT_EQ(std::string(kTestData, rv), std::string(buf->data(), rv)); | |
230 } | |
231 } | |
232 | |
233 TEST_F(FileStreamTest, Read_FromOffset) { | |
234 int64 file_size; | |
235 EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size)); | |
236 | |
237 FileStream stream(base::MessageLoopProxy::current()); | |
238 int flags = base::File::FLAG_OPEN | base::File::FLAG_READ | | |
239 base::File::FLAG_ASYNC; | |
240 TestCompletionCallback callback; | |
241 int rv = stream.Open(temp_file_path(), flags, callback.callback()); | |
242 EXPECT_EQ(ERR_IO_PENDING, rv); | |
243 EXPECT_EQ(OK, callback.WaitForResult()); | |
244 | |
245 TestInt64CompletionCallback callback64; | |
246 const int64 kOffset = 3; | |
247 rv = stream.Seek(base::File::FROM_BEGIN, kOffset, callback64.callback()); | |
248 ASSERT_EQ(ERR_IO_PENDING, rv); | |
249 int64 new_offset = callback64.WaitForResult(); | |
250 EXPECT_EQ(kOffset, new_offset); | |
251 | |
252 int total_bytes_read = 0; | |
253 | |
254 std::string data_read; | |
255 for (;;) { | |
256 scoped_refptr<IOBufferWithSize> buf = new IOBufferWithSize(4); | |
257 rv = stream.Read(buf.get(), buf->size(), callback.callback()); | |
258 if (rv == ERR_IO_PENDING) | |
259 rv = callback.WaitForResult(); | |
260 EXPECT_LE(0, rv); | |
261 if (rv <= 0) | |
262 break; | |
263 total_bytes_read += rv; | |
264 data_read.append(buf->data(), rv); | |
265 } | |
266 EXPECT_EQ(file_size - kOffset, total_bytes_read); | |
267 EXPECT_EQ(kTestData + kOffset, data_read); | |
268 } | |
269 | |
270 TEST_F(FileStreamTest, SeekAround) { | |
271 FileStream stream(base::MessageLoopProxy::current()); | |
272 int flags = base::File::FLAG_OPEN | base::File::FLAG_ASYNC | | |
273 base::File::FLAG_READ; | |
274 TestCompletionCallback callback; | |
275 int rv = stream.Open(temp_file_path(), flags, callback.callback()); | |
276 EXPECT_EQ(ERR_IO_PENDING, rv); | |
277 EXPECT_EQ(OK, callback.WaitForResult()); | |
278 | |
279 TestInt64CompletionCallback callback64; | |
280 | |
281 const int64 kOffset = 3; | |
282 rv = stream.Seek(base::File::FROM_BEGIN, kOffset, callback64.callback()); | |
283 ASSERT_EQ(ERR_IO_PENDING, rv); | |
284 int64 new_offset = callback64.WaitForResult(); | |
285 EXPECT_EQ(kOffset, new_offset); | |
286 | |
287 rv = stream.Seek(base::File::FROM_CURRENT, kOffset, callback64.callback()); | |
288 ASSERT_EQ(ERR_IO_PENDING, rv); | |
289 new_offset = callback64.WaitForResult(); | |
290 EXPECT_EQ(2 * kOffset, new_offset); | |
291 | |
292 rv = stream.Seek(base::File::FROM_CURRENT, -kOffset, callback64.callback()); | |
293 ASSERT_EQ(ERR_IO_PENDING, rv); | |
294 new_offset = callback64.WaitForResult(); | |
295 EXPECT_EQ(kOffset, new_offset); | |
296 | |
297 const int kTestDataLen = arraysize(kTestData) - 1; | |
298 | |
299 rv = stream.Seek(base::File::FROM_END, -kTestDataLen, callback64.callback()); | |
300 ASSERT_EQ(ERR_IO_PENDING, rv); | |
301 new_offset = callback64.WaitForResult(); | |
302 EXPECT_EQ(0, new_offset); | |
303 } | |
304 | |
305 TEST_F(FileStreamTest, Write) { | |
306 FileStream stream(base::MessageLoopProxy::current()); | |
307 int flags = base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE | | |
308 base::File::FLAG_ASYNC; | |
309 TestCompletionCallback callback; | |
310 int rv = stream.Open(temp_file_path(), flags, callback.callback()); | |
311 EXPECT_EQ(OK, callback.GetResult(rv)); | |
312 | |
313 int64 file_size; | |
314 EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size)); | |
315 EXPECT_EQ(0, file_size); | |
316 | |
317 scoped_refptr<IOBuffer> buf = CreateTestDataBuffer(); | |
318 rv = stream.Write(buf.get(), kTestDataSize, callback.callback()); | |
319 rv = callback.GetResult(rv); | |
320 EXPECT_EQ(kTestDataSize, rv); | |
321 | |
322 EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size)); | |
323 EXPECT_EQ(kTestDataSize, file_size); | |
324 | |
325 std::string data_read; | |
326 EXPECT_TRUE(base::ReadFileToString(temp_file_path(), &data_read)); | |
327 EXPECT_EQ(kTestData, data_read); | |
328 } | |
329 | |
330 TEST_F(FileStreamTest, Write_EarlyDelete) { | |
331 scoped_ptr<FileStream> stream( | |
332 new FileStream(base::MessageLoopProxy::current())); | |
333 int flags = base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE | | |
334 base::File::FLAG_ASYNC; | |
335 TestCompletionCallback callback; | |
336 int rv = stream->Open(temp_file_path(), flags, callback.callback()); | |
337 EXPECT_EQ(ERR_IO_PENDING, rv); | |
338 EXPECT_EQ(OK, callback.WaitForResult()); | |
339 | |
340 int64 file_size; | |
341 EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size)); | |
342 EXPECT_EQ(0, file_size); | |
343 | |
344 scoped_refptr<IOBufferWithSize> buf = CreateTestDataBuffer(); | |
345 rv = stream->Write(buf.get(), buf->size(), callback.callback()); | |
346 stream.reset(); | |
347 if (rv < 0) { | |
348 EXPECT_EQ(ERR_IO_PENDING, rv); | |
349 // The callback should not be called if the request is cancelled. | |
350 base::RunLoop().RunUntilIdle(); | |
351 EXPECT_FALSE(callback.have_result()); | |
352 } else { | |
353 EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size)); | |
354 EXPECT_EQ(file_size, rv); | |
355 } | |
356 } | |
357 | |
358 TEST_F(FileStreamTest, Write_FromOffset) { | |
359 int64 file_size; | |
360 EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size)); | |
361 | |
362 FileStream stream(base::MessageLoopProxy::current()); | |
363 int flags = base::File::FLAG_OPEN | base::File::FLAG_WRITE | | |
364 base::File::FLAG_ASYNC; | |
365 TestCompletionCallback callback; | |
366 int rv = stream.Open(temp_file_path(), flags, callback.callback()); | |
367 EXPECT_EQ(ERR_IO_PENDING, rv); | |
368 EXPECT_EQ(OK, callback.WaitForResult()); | |
369 | |
370 TestInt64CompletionCallback callback64; | |
371 const int64 kOffset = 0; | |
372 rv = stream.Seek(base::File::FROM_END, kOffset, callback64.callback()); | |
373 ASSERT_EQ(ERR_IO_PENDING, rv); | |
374 int64 new_offset = callback64.WaitForResult(); | |
375 EXPECT_EQ(kTestDataSize, new_offset); | |
376 | |
377 int total_bytes_written = 0; | |
378 | |
379 scoped_refptr<IOBufferWithSize> buf = CreateTestDataBuffer(); | |
380 scoped_refptr<DrainableIOBuffer> drainable = | |
381 new DrainableIOBuffer(buf.get(), buf->size()); | |
382 while (total_bytes_written != kTestDataSize) { | |
383 rv = stream.Write(drainable.get(), drainable->BytesRemaining(), | |
384 callback.callback()); | |
385 if (rv == ERR_IO_PENDING) | |
386 rv = callback.WaitForResult(); | |
387 EXPECT_LT(0, rv); | |
388 if (rv <= 0) | |
389 break; | |
390 drainable->DidConsume(rv); | |
391 total_bytes_written += rv; | |
392 } | |
393 EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size)); | |
394 EXPECT_EQ(file_size, kTestDataSize * 2); | |
395 } | |
396 | |
397 TEST_F(FileStreamTest, BasicReadWrite) { | |
398 int64 file_size; | |
399 EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size)); | |
400 | |
401 scoped_ptr<FileStream> stream( | |
402 new FileStream(base::MessageLoopProxy::current())); | |
403 int flags = base::File::FLAG_OPEN | base::File::FLAG_READ | | |
404 base::File::FLAG_WRITE | base::File::FLAG_ASYNC; | |
405 TestCompletionCallback callback; | |
406 int rv = stream->Open(temp_file_path(), flags, callback.callback()); | |
407 EXPECT_EQ(ERR_IO_PENDING, rv); | |
408 EXPECT_EQ(OK, callback.WaitForResult()); | |
409 | |
410 int64 total_bytes_read = 0; | |
411 | |
412 std::string data_read; | |
413 for (;;) { | |
414 scoped_refptr<IOBufferWithSize> buf = new IOBufferWithSize(4); | |
415 rv = stream->Read(buf.get(), buf->size(), callback.callback()); | |
416 if (rv == ERR_IO_PENDING) | |
417 rv = callback.WaitForResult(); | |
418 EXPECT_LE(0, rv); | |
419 if (rv <= 0) | |
420 break; | |
421 total_bytes_read += rv; | |
422 data_read.append(buf->data(), rv); | |
423 } | |
424 EXPECT_EQ(file_size, total_bytes_read); | |
425 EXPECT_TRUE(data_read == kTestData); | |
426 | |
427 int total_bytes_written = 0; | |
428 | |
429 scoped_refptr<IOBufferWithSize> buf = CreateTestDataBuffer(); | |
430 scoped_refptr<DrainableIOBuffer> drainable = | |
431 new DrainableIOBuffer(buf.get(), buf->size()); | |
432 while (total_bytes_written != kTestDataSize) { | |
433 rv = stream->Write(drainable.get(), drainable->BytesRemaining(), | |
434 callback.callback()); | |
435 if (rv == ERR_IO_PENDING) | |
436 rv = callback.WaitForResult(); | |
437 EXPECT_LT(0, rv); | |
438 if (rv <= 0) | |
439 break; | |
440 drainable->DidConsume(rv); | |
441 total_bytes_written += rv; | |
442 } | |
443 | |
444 stream.reset(); | |
445 | |
446 EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size)); | |
447 EXPECT_EQ(kTestDataSize * 2, file_size); | |
448 } | |
449 | |
450 TEST_F(FileStreamTest, BasicWriteRead) { | |
451 int64 file_size; | |
452 EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size)); | |
453 | |
454 scoped_ptr<FileStream> stream( | |
455 new FileStream(base::MessageLoopProxy::current())); | |
456 int flags = base::File::FLAG_OPEN | base::File::FLAG_READ | | |
457 base::File::FLAG_WRITE | base::File::FLAG_ASYNC; | |
458 TestCompletionCallback callback; | |
459 int rv = stream->Open(temp_file_path(), flags, callback.callback()); | |
460 EXPECT_EQ(ERR_IO_PENDING, rv); | |
461 EXPECT_EQ(OK, callback.WaitForResult()); | |
462 | |
463 TestInt64CompletionCallback callback64; | |
464 rv = stream->Seek(base::File::FROM_END, 0, callback64.callback()); | |
465 ASSERT_EQ(ERR_IO_PENDING, rv); | |
466 int64 offset = callback64.WaitForResult(); | |
467 EXPECT_EQ(offset, file_size); | |
468 | |
469 int total_bytes_written = 0; | |
470 | |
471 scoped_refptr<IOBufferWithSize> buf = CreateTestDataBuffer(); | |
472 scoped_refptr<DrainableIOBuffer> drainable = | |
473 new DrainableIOBuffer(buf.get(), buf->size()); | |
474 while (total_bytes_written != kTestDataSize) { | |
475 rv = stream->Write(drainable.get(), drainable->BytesRemaining(), | |
476 callback.callback()); | |
477 if (rv == ERR_IO_PENDING) | |
478 rv = callback.WaitForResult(); | |
479 EXPECT_LT(0, rv); | |
480 if (rv <= 0) | |
481 break; | |
482 drainable->DidConsume(rv); | |
483 total_bytes_written += rv; | |
484 } | |
485 | |
486 EXPECT_EQ(kTestDataSize, total_bytes_written); | |
487 | |
488 rv = stream->Seek(base::File::FROM_BEGIN, 0, callback64.callback()); | |
489 ASSERT_EQ(ERR_IO_PENDING, rv); | |
490 offset = callback64.WaitForResult(); | |
491 EXPECT_EQ(0, offset); | |
492 | |
493 int total_bytes_read = 0; | |
494 | |
495 std::string data_read; | |
496 for (;;) { | |
497 scoped_refptr<IOBufferWithSize> buf = new IOBufferWithSize(4); | |
498 rv = stream->Read(buf.get(), buf->size(), callback.callback()); | |
499 if (rv == ERR_IO_PENDING) | |
500 rv = callback.WaitForResult(); | |
501 EXPECT_LE(0, rv); | |
502 if (rv <= 0) | |
503 break; | |
504 total_bytes_read += rv; | |
505 data_read.append(buf->data(), rv); | |
506 } | |
507 stream.reset(); | |
508 | |
509 EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size)); | |
510 EXPECT_EQ(kTestDataSize * 2, file_size); | |
511 | |
512 EXPECT_EQ(kTestDataSize * 2, total_bytes_read); | |
513 const std::string kExpectedFileData = | |
514 std::string(kTestData) + std::string(kTestData); | |
515 EXPECT_EQ(kExpectedFileData, data_read); | |
516 } | |
517 | |
518 class TestWriteReadCompletionCallback { | |
519 public: | |
520 TestWriteReadCompletionCallback(FileStream* stream, | |
521 int* total_bytes_written, | |
522 int* total_bytes_read, | |
523 std::string* data_read) | |
524 : result_(0), | |
525 have_result_(false), | |
526 waiting_for_result_(false), | |
527 stream_(stream), | |
528 total_bytes_written_(total_bytes_written), | |
529 total_bytes_read_(total_bytes_read), | |
530 data_read_(data_read), | |
531 callback_(base::Bind(&TestWriteReadCompletionCallback::OnComplete, | |
532 base::Unretained(this))), | |
533 test_data_(CreateTestDataBuffer()), | |
534 drainable_(new DrainableIOBuffer(test_data_.get(), kTestDataSize)) {} | |
535 | |
536 int WaitForResult() { | |
537 DCHECK(!waiting_for_result_); | |
538 while (!have_result_) { | |
539 waiting_for_result_ = true; | |
540 base::RunLoop().Run(); | |
541 waiting_for_result_ = false; | |
542 } | |
543 have_result_ = false; // auto-reset for next callback | |
544 return result_; | |
545 } | |
546 | |
547 const CompletionCallback& callback() const { return callback_; } | |
548 | |
549 void ValidateWrittenData() { | |
550 TestCompletionCallback callback; | |
551 int rv = 0; | |
552 for (;;) { | |
553 scoped_refptr<IOBufferWithSize> buf = new IOBufferWithSize(4); | |
554 rv = stream_->Read(buf.get(), buf->size(), callback.callback()); | |
555 if (rv == ERR_IO_PENDING) { | |
556 base::MessageLoop::ScopedNestableTaskAllower allow( | |
557 base::MessageLoop::current()); | |
558 rv = callback.WaitForResult(); | |
559 } | |
560 EXPECT_LE(0, rv); | |
561 if (rv <= 0) | |
562 break; | |
563 *total_bytes_read_ += rv; | |
564 data_read_->append(buf->data(), rv); | |
565 } | |
566 } | |
567 | |
568 private: | |
569 void OnComplete(int result) { | |
570 DCHECK_LT(0, result); | |
571 *total_bytes_written_ += result; | |
572 | |
573 int rv; | |
574 | |
575 if (*total_bytes_written_ != kTestDataSize) { | |
576 // Recurse to finish writing all data. | |
577 int total_bytes_written = 0, total_bytes_read = 0; | |
578 std::string data_read; | |
579 TestWriteReadCompletionCallback callback( | |
580 stream_, &total_bytes_written, &total_bytes_read, &data_read); | |
581 rv = stream_->Write( | |
582 drainable_.get(), drainable_->BytesRemaining(), callback.callback()); | |
583 DCHECK_EQ(ERR_IO_PENDING, rv); | |
584 rv = callback.WaitForResult(); | |
585 drainable_->DidConsume(total_bytes_written); | |
586 *total_bytes_written_ += total_bytes_written; | |
587 *total_bytes_read_ += total_bytes_read; | |
588 *data_read_ += data_read; | |
589 } else { // We're done writing all data. Start reading the data. | |
590 TestInt64CompletionCallback callback64; | |
591 EXPECT_EQ(ERR_IO_PENDING, | |
592 stream_->Seek(base::File::FROM_BEGIN, 0, | |
593 callback64.callback())); | |
594 { | |
595 base::MessageLoop::ScopedNestableTaskAllower allow( | |
596 base::MessageLoop::current()); | |
597 EXPECT_LE(0, callback64.WaitForResult()); | |
598 } | |
599 } | |
600 | |
601 result_ = *total_bytes_written_; | |
602 have_result_ = true; | |
603 if (waiting_for_result_) | |
604 base::MessageLoop::current()->Quit(); | |
605 } | |
606 | |
607 int result_; | |
608 bool have_result_; | |
609 bool waiting_for_result_; | |
610 FileStream* stream_; | |
611 int* total_bytes_written_; | |
612 int* total_bytes_read_; | |
613 std::string* data_read_; | |
614 const CompletionCallback callback_; | |
615 scoped_refptr<IOBufferWithSize> test_data_; | |
616 scoped_refptr<DrainableIOBuffer> drainable_; | |
617 | |
618 DISALLOW_COPY_AND_ASSIGN(TestWriteReadCompletionCallback); | |
619 }; | |
620 | |
621 TEST_F(FileStreamTest, WriteRead) { | |
622 int64 file_size; | |
623 EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size)); | |
624 | |
625 scoped_ptr<FileStream> stream( | |
626 new FileStream(base::MessageLoopProxy::current())); | |
627 int flags = base::File::FLAG_OPEN | base::File::FLAG_READ | | |
628 base::File::FLAG_WRITE | base::File::FLAG_ASYNC; | |
629 TestCompletionCallback open_callback; | |
630 int rv = stream->Open(temp_file_path(), flags, open_callback.callback()); | |
631 EXPECT_EQ(ERR_IO_PENDING, rv); | |
632 EXPECT_EQ(OK, open_callback.WaitForResult()); | |
633 | |
634 TestInt64CompletionCallback callback64; | |
635 EXPECT_EQ(ERR_IO_PENDING, | |
636 stream->Seek(base::File::FROM_END, 0, callback64.callback())); | |
637 EXPECT_EQ(file_size, callback64.WaitForResult()); | |
638 | |
639 int total_bytes_written = 0; | |
640 int total_bytes_read = 0; | |
641 std::string data_read; | |
642 TestWriteReadCompletionCallback callback(stream.get(), &total_bytes_written, | |
643 &total_bytes_read, &data_read); | |
644 | |
645 scoped_refptr<IOBufferWithSize> buf = CreateTestDataBuffer(); | |
646 rv = stream->Write(buf.get(), buf->size(), callback.callback()); | |
647 if (rv == ERR_IO_PENDING) | |
648 rv = callback.WaitForResult(); | |
649 EXPECT_LT(0, rv); | |
650 EXPECT_EQ(kTestDataSize, total_bytes_written); | |
651 | |
652 callback.ValidateWrittenData(); | |
653 | |
654 stream.reset(); | |
655 | |
656 EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size)); | |
657 EXPECT_EQ(kTestDataSize * 2, file_size); | |
658 | |
659 EXPECT_EQ(kTestDataSize * 2, total_bytes_read); | |
660 const std::string kExpectedFileData = | |
661 std::string(kTestData) + std::string(kTestData); | |
662 EXPECT_EQ(kExpectedFileData, data_read); | |
663 } | |
664 | |
665 class TestWriteCloseCompletionCallback { | |
666 public: | |
667 TestWriteCloseCompletionCallback(FileStream* stream, int* total_bytes_written) | |
668 : result_(0), | |
669 have_result_(false), | |
670 waiting_for_result_(false), | |
671 stream_(stream), | |
672 total_bytes_written_(total_bytes_written), | |
673 callback_(base::Bind(&TestWriteCloseCompletionCallback::OnComplete, | |
674 base::Unretained(this))), | |
675 test_data_(CreateTestDataBuffer()), | |
676 drainable_(new DrainableIOBuffer(test_data_.get(), kTestDataSize)) {} | |
677 | |
678 int WaitForResult() { | |
679 DCHECK(!waiting_for_result_); | |
680 while (!have_result_) { | |
681 waiting_for_result_ = true; | |
682 base::RunLoop().Run(); | |
683 waiting_for_result_ = false; | |
684 } | |
685 have_result_ = false; // auto-reset for next callback | |
686 return result_; | |
687 } | |
688 | |
689 const CompletionCallback& callback() const { return callback_; } | |
690 | |
691 private: | |
692 void OnComplete(int result) { | |
693 DCHECK_LT(0, result); | |
694 *total_bytes_written_ += result; | |
695 | |
696 int rv; | |
697 | |
698 if (*total_bytes_written_ != kTestDataSize) { | |
699 // Recurse to finish writing all data. | |
700 int total_bytes_written = 0; | |
701 TestWriteCloseCompletionCallback callback(stream_, &total_bytes_written); | |
702 rv = stream_->Write( | |
703 drainable_.get(), drainable_->BytesRemaining(), callback.callback()); | |
704 DCHECK_EQ(ERR_IO_PENDING, rv); | |
705 rv = callback.WaitForResult(); | |
706 drainable_->DidConsume(total_bytes_written); | |
707 *total_bytes_written_ += total_bytes_written; | |
708 } | |
709 | |
710 result_ = *total_bytes_written_; | |
711 have_result_ = true; | |
712 if (waiting_for_result_) | |
713 base::MessageLoop::current()->Quit(); | |
714 } | |
715 | |
716 int result_; | |
717 bool have_result_; | |
718 bool waiting_for_result_; | |
719 FileStream* stream_; | |
720 int* total_bytes_written_; | |
721 const CompletionCallback callback_; | |
722 scoped_refptr<IOBufferWithSize> test_data_; | |
723 scoped_refptr<DrainableIOBuffer> drainable_; | |
724 | |
725 DISALLOW_COPY_AND_ASSIGN(TestWriteCloseCompletionCallback); | |
726 }; | |
727 | |
728 TEST_F(FileStreamTest, WriteClose) { | |
729 int64 file_size; | |
730 EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size)); | |
731 | |
732 scoped_ptr<FileStream> stream( | |
733 new FileStream(base::MessageLoopProxy::current())); | |
734 int flags = base::File::FLAG_OPEN | base::File::FLAG_READ | | |
735 base::File::FLAG_WRITE | base::File::FLAG_ASYNC; | |
736 TestCompletionCallback open_callback; | |
737 int rv = stream->Open(temp_file_path(), flags, open_callback.callback()); | |
738 EXPECT_EQ(ERR_IO_PENDING, rv); | |
739 EXPECT_EQ(OK, open_callback.WaitForResult()); | |
740 | |
741 TestInt64CompletionCallback callback64; | |
742 EXPECT_EQ(ERR_IO_PENDING, | |
743 stream->Seek(base::File::FROM_END, 0, callback64.callback())); | |
744 EXPECT_EQ(file_size, callback64.WaitForResult()); | |
745 | |
746 int total_bytes_written = 0; | |
747 TestWriteCloseCompletionCallback callback(stream.get(), &total_bytes_written); | |
748 | |
749 scoped_refptr<IOBufferWithSize> buf = CreateTestDataBuffer(); | |
750 rv = stream->Write(buf.get(), buf->size(), callback.callback()); | |
751 if (rv == ERR_IO_PENDING) | |
752 total_bytes_written = callback.WaitForResult(); | |
753 EXPECT_LT(0, total_bytes_written); | |
754 EXPECT_EQ(kTestDataSize, total_bytes_written); | |
755 | |
756 stream.reset(); | |
757 | |
758 EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size)); | |
759 EXPECT_EQ(kTestDataSize * 2, file_size); | |
760 } | |
761 | |
762 TEST_F(FileStreamTest, OpenAndDelete) { | |
763 scoped_refptr<base::SequencedWorkerPool> pool( | |
764 new base::SequencedWorkerPool(1, "StreamTest")); | |
765 | |
766 bool prev = base::ThreadRestrictions::SetIOAllowed(false); | |
767 scoped_ptr<FileStream> stream(new FileStream(pool.get())); | |
768 int flags = base::File::FLAG_OPEN | base::File::FLAG_WRITE | | |
769 base::File::FLAG_ASYNC; | |
770 TestCompletionCallback open_callback; | |
771 int rv = stream->Open(temp_file_path(), flags, open_callback.callback()); | |
772 EXPECT_EQ(ERR_IO_PENDING, rv); | |
773 | |
774 // Delete the stream without waiting for the open operation to be | |
775 // complete. Should be safe. | |
776 stream.reset(); | |
777 | |
778 // Force an operation through the pool. | |
779 scoped_ptr<FileStream> stream2(new FileStream(pool.get())); | |
780 TestCompletionCallback open_callback2; | |
781 rv = stream2->Open(temp_file_path(), flags, open_callback2.callback()); | |
782 EXPECT_EQ(OK, open_callback2.GetResult(rv)); | |
783 stream2.reset(); | |
784 | |
785 pool->Shutdown(); | |
786 | |
787 // open_callback won't be called. | |
788 base::RunLoop().RunUntilIdle(); | |
789 EXPECT_FALSE(open_callback.have_result()); | |
790 base::ThreadRestrictions::SetIOAllowed(prev); | |
791 } | |
792 | |
793 // Verify that Write() errors are mapped correctly. | |
794 TEST_F(FileStreamTest, WriteError) { | |
795 // Try opening file as read-only and then writing to it using FileStream. | |
796 uint32 flags = base::File::FLAG_OPEN | base::File::FLAG_READ | | |
797 base::File::FLAG_ASYNC; | |
798 | |
799 base::File file(temp_file_path(), flags); | |
800 ASSERT_TRUE(file.IsValid()); | |
801 | |
802 scoped_ptr<FileStream> stream( | |
803 new FileStream(file.Pass(), base::MessageLoopProxy::current())); | |
804 | |
805 scoped_refptr<IOBuffer> buf = new IOBuffer(1); | |
806 buf->data()[0] = 0; | |
807 | |
808 TestCompletionCallback callback; | |
809 int rv = stream->Write(buf.get(), 1, callback.callback()); | |
810 if (rv == ERR_IO_PENDING) | |
811 rv = callback.WaitForResult(); | |
812 EXPECT_LT(rv, 0); | |
813 | |
814 stream.reset(); | |
815 base::RunLoop().RunUntilIdle(); | |
816 } | |
817 | |
818 // Verify that Read() errors are mapped correctly. | |
819 TEST_F(FileStreamTest, ReadError) { | |
820 // Try opening file for write and then reading from it using FileStream. | |
821 uint32 flags = base::File::FLAG_OPEN | base::File::FLAG_WRITE | | |
822 base::File::FLAG_ASYNC; | |
823 | |
824 base::File file(temp_file_path(), flags); | |
825 ASSERT_TRUE(file.IsValid()); | |
826 | |
827 scoped_ptr<FileStream> stream( | |
828 new FileStream(file.Pass(), base::MessageLoopProxy::current())); | |
829 | |
830 scoped_refptr<IOBuffer> buf = new IOBuffer(1); | |
831 TestCompletionCallback callback; | |
832 int rv = stream->Read(buf.get(), 1, callback.callback()); | |
833 if (rv == ERR_IO_PENDING) | |
834 rv = callback.WaitForResult(); | |
835 EXPECT_LT(rv, 0); | |
836 | |
837 stream.reset(); | |
838 base::RunLoop().RunUntilIdle(); | |
839 } | |
840 | |
841 #if defined(OS_ANDROID) | |
842 TEST_F(FileStreamTest, ContentUriRead) { | |
843 base::FilePath test_dir; | |
844 PathService::Get(base::DIR_SOURCE_ROOT, &test_dir); | |
845 test_dir = test_dir.AppendASCII("net"); | |
846 test_dir = test_dir.AppendASCII("data"); | |
847 test_dir = test_dir.AppendASCII("file_stream_unittest"); | |
848 ASSERT_TRUE(base::PathExists(test_dir)); | |
849 base::FilePath image_file = test_dir.Append(FILE_PATH_LITERAL("red.png")); | |
850 | |
851 // Insert the image into MediaStore. MediaStore will do some conversions, and | |
852 // return the content URI. | |
853 base::FilePath path = base::InsertImageIntoMediaStore(image_file); | |
854 EXPECT_TRUE(path.IsContentUri()); | |
855 EXPECT_TRUE(base::PathExists(path)); | |
856 int64 file_size; | |
857 EXPECT_TRUE(base::GetFileSize(path, &file_size)); | |
858 EXPECT_LT(0, file_size); | |
859 | |
860 FileStream stream(base::MessageLoopProxy::current()); | |
861 int flags = base::File::FLAG_OPEN | base::File::FLAG_READ | | |
862 base::File::FLAG_ASYNC; | |
863 TestCompletionCallback callback; | |
864 int rv = stream.Open(path, flags, callback.callback()); | |
865 EXPECT_EQ(ERR_IO_PENDING, rv); | |
866 EXPECT_EQ(OK, callback.WaitForResult()); | |
867 | |
868 int total_bytes_read = 0; | |
869 | |
870 std::string data_read; | |
871 for (;;) { | |
872 scoped_refptr<IOBufferWithSize> buf = new IOBufferWithSize(4); | |
873 rv = stream.Read(buf.get(), buf->size(), callback.callback()); | |
874 if (rv == ERR_IO_PENDING) | |
875 rv = callback.WaitForResult(); | |
876 EXPECT_LE(0, rv); | |
877 if (rv <= 0) | |
878 break; | |
879 total_bytes_read += rv; | |
880 data_read.append(buf->data(), rv); | |
881 } | |
882 EXPECT_EQ(file_size, total_bytes_read); | |
883 } | |
884 #endif | |
885 | |
886 } // namespace | |
887 | |
888 } // namespace net | |
OLD | NEW |