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