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.
5 #include "net/base/file_stream.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"
27 #if defined(OS_ANDROID)
28 #include "base/test/test_file_util.h"
35 const char kTestData
[] = "0123456789";
36 const int kTestDataSize
= arraysize(kTestData
) - 1;
38 // Creates an IOBufferWithSize that contains the kTestDataSize.
39 IOBufferWithSize
* CreateTestDataBuffer() {
40 IOBufferWithSize
* buf
= new IOBufferWithSize(kTestDataSize
);
41 memcpy(buf
->data(), kTestData
, kTestDataSize
);
47 class FileStreamTest
: public PlatformTest
{
49 void SetUp() override
{
50 PlatformTest::SetUp();
52 base::CreateTemporaryFile(&temp_file_path_
);
53 base::WriteFile(temp_file_path_
, kTestData
, kTestDataSize
);
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));
61 PlatformTest::TearDown();
64 const base::FilePath
temp_file_path() const { return temp_file_path_
; }
67 base::FilePath temp_file_path_
;
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());
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()));
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.
108 // Test the use of FileStream with a file handle provided at construction.
109 TEST_F(FileStreamTest
, UseFileHandle
) {
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
);
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
));
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
);
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();
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(),
157 ASSERT_EQ(0, memcmp(kTestData
, read_buffer
->data(), kTestDataSize
));
160 TEST_F(FileStreamTest
, UseClosedStream
) {
162 TestCompletionCallback callback
;
163 TestInt64CompletionCallback callback64
;
165 FileStream
stream(base::MessageLoopProxy::current());
167 EXPECT_FALSE(stream
.IsOpen());
170 rv
= stream
.Seek(base::File::FROM_BEGIN
, 5, callback64
.callback());
171 EXPECT_EQ(ERR_UNEXPECTED
, callback64
.GetResult(rv
));
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
));
179 TEST_F(FileStreamTest
, Read
) {
181 EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size
));
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
));
190 int total_bytes_read
= 0;
192 std::string data_read
;
194 scoped_refptr
<IOBufferWithSize
> buf
= new IOBufferWithSize(4);
195 rv
= stream
.Read(buf
.get(), buf
->size(), callback
.callback());
196 rv
= callback
.GetResult(rv
);
200 total_bytes_read
+= rv
;
201 data_read
.append(buf
->data(), rv
);
203 EXPECT_EQ(file_size
, total_bytes_read
);
204 EXPECT_EQ(kTestData
, data_read
);
207 TEST_F(FileStreamTest
, Read_EarlyDelete
) {
209 EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size
));
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());
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.
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());
229 EXPECT_EQ(std::string(kTestData
, rv
), std::string(buf
->data(), rv
));
233 TEST_F(FileStreamTest
, Read_FromOffset
) {
235 EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size
));
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());
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
);
252 int total_bytes_read
= 0;
254 std::string data_read
;
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();
263 total_bytes_read
+= rv
;
264 data_read
.append(buf
->data(), rv
);
266 EXPECT_EQ(file_size
- kOffset
, total_bytes_read
);
267 EXPECT_EQ(kTestData
+ kOffset
, data_read
);
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());
279 TestInt64CompletionCallback callback64
;
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
);
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
);
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
);
297 const int kTestDataLen
= arraysize(kTestData
) - 1;
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
);
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
));
314 EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size
));
315 EXPECT_EQ(0, file_size
);
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
);
322 EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size
));
323 EXPECT_EQ(kTestDataSize
, file_size
);
325 std::string data_read
;
326 EXPECT_TRUE(base::ReadFileToString(temp_file_path(), &data_read
));
327 EXPECT_EQ(kTestData
, data_read
);
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());
341 EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size
));
342 EXPECT_EQ(0, file_size
);
344 scoped_refptr
<IOBufferWithSize
> buf
= CreateTestDataBuffer();
345 rv
= stream
->Write(buf
.get(), buf
->size(), callback
.callback());
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());
353 EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size
));
354 EXPECT_EQ(file_size
, rv
);
358 TEST_F(FileStreamTest
, Write_FromOffset
) {
360 EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size
));
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());
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
);
377 int total_bytes_written
= 0;
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();
390 drainable
->DidConsume(rv
);
391 total_bytes_written
+= rv
;
393 EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size
));
394 EXPECT_EQ(file_size
, kTestDataSize
* 2);
397 TEST_F(FileStreamTest
, BasicReadWrite
) {
399 EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size
));
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());
410 int64 total_bytes_read
= 0;
412 std::string data_read
;
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();
421 total_bytes_read
+= rv
;
422 data_read
.append(buf
->data(), rv
);
424 EXPECT_EQ(file_size
, total_bytes_read
);
425 EXPECT_TRUE(data_read
== kTestData
);
427 int total_bytes_written
= 0;
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();
440 drainable
->DidConsume(rv
);
441 total_bytes_written
+= rv
;
446 EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size
));
447 EXPECT_EQ(kTestDataSize
* 2, file_size
);
450 TEST_F(FileStreamTest
, BasicWriteRead
) {
452 EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size
));
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());
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
);
469 int total_bytes_written
= 0;
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();
482 drainable
->DidConsume(rv
);
483 total_bytes_written
+= rv
;
486 EXPECT_EQ(kTestDataSize
, total_bytes_written
);
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
);
493 int total_bytes_read
= 0;
495 std::string data_read
;
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();
504 total_bytes_read
+= rv
;
505 data_read
.append(buf
->data(), rv
);
509 EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size
));
510 EXPECT_EQ(kTestDataSize
* 2, file_size
);
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
);
518 class TestWriteReadCompletionCallback
{
520 TestWriteReadCompletionCallback(FileStream
* stream
,
521 int* total_bytes_written
,
522 int* total_bytes_read
,
523 std::string
* data_read
)
526 waiting_for_result_(false),
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
)) {}
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;
543 have_result_
= false; // auto-reset for next callback
547 const CompletionCallback
& callback() const { return callback_
; }
549 void ValidateWrittenData() {
550 TestCompletionCallback callback
;
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();
563 *total_bytes_read_
+= rv
;
564 data_read_
->append(buf
->data(), rv
);
569 void OnComplete(int result
) {
570 DCHECK_LT(0, result
);
571 *total_bytes_written_
+= result
;
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
);
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()));
595 base::MessageLoop::ScopedNestableTaskAllower
allow(
596 base::MessageLoop::current());
597 EXPECT_LE(0, callback64
.WaitForResult());
601 result_
= *total_bytes_written_
;
603 if (waiting_for_result_
)
604 base::MessageLoop::current()->Quit();
609 bool waiting_for_result_
;
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_
;
618 DISALLOW_COPY_AND_ASSIGN(TestWriteReadCompletionCallback
);
621 TEST_F(FileStreamTest
, WriteRead
) {
623 EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size
));
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());
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());
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
);
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();
650 EXPECT_EQ(kTestDataSize
, total_bytes_written
);
652 callback
.ValidateWrittenData();
656 EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size
));
657 EXPECT_EQ(kTestDataSize
* 2, file_size
);
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
);
665 class TestWriteCloseCompletionCallback
{
667 TestWriteCloseCompletionCallback(FileStream
* stream
, int* total_bytes_written
)
670 waiting_for_result_(false),
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
)) {}
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;
685 have_result_
= false; // auto-reset for next callback
689 const CompletionCallback
& callback() const { return callback_
; }
692 void OnComplete(int result
) {
693 DCHECK_LT(0, result
);
694 *total_bytes_written_
+= result
;
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
);
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
;
710 result_
= *total_bytes_written_
;
712 if (waiting_for_result_
)
713 base::MessageLoop::current()->Quit();
718 bool waiting_for_result_
;
720 int* total_bytes_written_
;
721 const CompletionCallback callback_
;
722 scoped_refptr
<IOBufferWithSize
> test_data_
;
723 scoped_refptr
<DrainableIOBuffer
> drainable_
;
725 DISALLOW_COPY_AND_ASSIGN(TestWriteCloseCompletionCallback
);
728 TEST_F(FileStreamTest
, WriteClose
) {
730 EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size
));
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());
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());
746 int total_bytes_written
= 0;
747 TestWriteCloseCompletionCallback
callback(stream
.get(), &total_bytes_written
);
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
);
758 EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size
));
759 EXPECT_EQ(kTestDataSize
* 2, file_size
);
762 TEST_F(FileStreamTest
, OpenAndDelete
) {
763 scoped_refptr
<base::SequencedWorkerPool
> pool(
764 new base::SequencedWorkerPool(1, "StreamTest"));
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
);
774 // Delete the stream without waiting for the open operation to be
775 // complete. Should be safe.
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
));
787 // open_callback won't be called.
788 base::RunLoop().RunUntilIdle();
789 EXPECT_FALSE(open_callback
.have_result());
790 base::ThreadRestrictions::SetIOAllowed(prev
);
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
;
799 base::File
file(temp_file_path(), flags
);
800 ASSERT_TRUE(file
.IsValid());
802 scoped_ptr
<FileStream
> stream(
803 new FileStream(file
.Pass(), base::MessageLoopProxy::current()));
805 scoped_refptr
<IOBuffer
> buf
= new IOBuffer(1);
808 TestCompletionCallback callback
;
809 int rv
= stream
->Write(buf
.get(), 1, callback
.callback());
810 if (rv
== ERR_IO_PENDING
)
811 rv
= callback
.WaitForResult();
815 base::RunLoop().RunUntilIdle();
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
;
824 base::File
file(temp_file_path(), flags
);
825 ASSERT_TRUE(file
.IsValid());
827 scoped_ptr
<FileStream
> stream(
828 new FileStream(file
.Pass(), base::MessageLoopProxy::current()));
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();
838 base::RunLoop().RunUntilIdle();
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"));
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
));
857 EXPECT_TRUE(base::GetFileSize(path
, &file_size
));
858 EXPECT_LT(0, file_size
);
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());
868 int total_bytes_read
= 0;
870 std::string data_read
;
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();
879 total_bytes_read
+= rv
;
880 data_read
.append(buf
->data(), rv
);
882 EXPECT_EQ(file_size
, total_bytes_read
);