drive_file_stream_reader_unittest.cc revision 46d4c2bc3267f3f028f39e7e311b0f89aba2e4fd
1// Copyright 2013 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 "chrome/browser/chromeos/drive/drive_file_stream_reader.h" 6 7#include <string> 8 9#include "base/bind.h" 10#include "base/files/file_path.h" 11#include "base/files/scoped_temp_dir.h" 12#include "base/run_loop.h" 13#include "base/threading/thread.h" 14#include "chrome/browser/chromeos/drive/fake_file_system.h" 15#include "chrome/browser/chromeos/drive/file_system_util.h" 16#include "chrome/browser/chromeos/drive/local_file_reader.h" 17#include "chrome/browser/chromeos/drive/test_util.h" 18#include "chrome/browser/drive/fake_drive_service.h" 19#include "chrome/browser/drive/test_util.h" 20#include "content/public/test/test_browser_thread_bundle.h" 21#include "google_apis/drive/drive_api_parser.h" 22#include "google_apis/drive/test_util.h" 23#include "net/base/io_buffer.h" 24#include "net/base/net_errors.h" 25#include "net/base/test_completion_callback.h" 26#include "net/http/http_byte_range.h" 27#include "testing/gtest/include/gtest/gtest.h" 28 29namespace drive { 30namespace internal { 31namespace { 32 33// Increments the |num_called|, when this method is invoked. 34void IncrementCallback(int* num_called) { 35 DCHECK(num_called); 36 ++*num_called; 37} 38 39} // namespace 40 41class LocalReaderProxyTest : public ::testing::Test { 42 protected: 43 LocalReaderProxyTest() 44 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) { 45 } 46 47 virtual void SetUp() OVERRIDE { 48 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 49 ASSERT_TRUE(google_apis::test_util::CreateFileOfSpecifiedSize( 50 temp_dir_.path(), 1024, &file_path_, &file_content_)); 51 52 worker_thread_.reset(new base::Thread("ReaderProxyTest")); 53 ASSERT_TRUE(worker_thread_->Start()); 54 } 55 56 content::TestBrowserThreadBundle thread_bundle_; 57 58 base::ScopedTempDir temp_dir_; 59 base::FilePath file_path_; 60 std::string file_content_; 61 62 scoped_ptr<base::Thread> worker_thread_; 63}; 64 65TEST_F(LocalReaderProxyTest, Read) { 66 // Open the file first. 67 scoped_ptr<util::LocalFileReader> file_reader( 68 new util::LocalFileReader(worker_thread_->message_loop_proxy().get())); 69 net::TestCompletionCallback callback; 70 file_reader->Open(file_path_, 0, callback.callback()); 71 ASSERT_EQ(net::OK, callback.WaitForResult()); 72 73 // Test instance. 74 LocalReaderProxy proxy(file_reader.Pass(), file_content_.size()); 75 76 // Make sure the read content is as same as the file. 77 std::string content; 78 ASSERT_EQ(net::OK, test_util::ReadAllData(&proxy, &content)); 79 EXPECT_EQ(file_content_, content); 80} 81 82TEST_F(LocalReaderProxyTest, ReadWithLimit) { 83 // This test case, we only read first half of the file. 84 const std::string expected_content = 85 file_content_.substr(0, file_content_.size() / 2); 86 87 // Open the file first. 88 scoped_ptr<util::LocalFileReader> file_reader( 89 new util::LocalFileReader(worker_thread_->message_loop_proxy().get())); 90 net::TestCompletionCallback callback; 91 file_reader->Open(file_path_, 0, callback.callback()); 92 ASSERT_EQ(net::OK, callback.WaitForResult()); 93 94 // Test instance. 95 LocalReaderProxy proxy(file_reader.Pass(), expected_content.size()); 96 97 // Make sure the read content is as same as the file. 98 std::string content; 99 ASSERT_EQ(net::OK, test_util::ReadAllData(&proxy, &content)); 100 EXPECT_EQ(expected_content, content); 101} 102 103class NetworkReaderProxyTest : public ::testing::Test { 104 protected: 105 NetworkReaderProxyTest() 106 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) { 107 } 108 109 content::TestBrowserThreadBundle thread_bundle_; 110}; 111 112TEST_F(NetworkReaderProxyTest, EmptyFile) { 113 NetworkReaderProxy proxy(0, 0, 0, base::Bind(&base::DoNothing)); 114 115 net::TestCompletionCallback callback; 116 const int kBufferSize = 10; 117 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize)); 118 int result = proxy.Read(buffer.get(), kBufferSize, callback.callback()); 119 120 // For empty file, Read() should return 0 immediately. 121 EXPECT_EQ(0, result); 122} 123 124TEST_F(NetworkReaderProxyTest, Read) { 125 int cancel_called = 0; 126 { 127 NetworkReaderProxy proxy(0, 10, 10, 128 base::Bind(&IncrementCallback, &cancel_called)); 129 130 net::TestCompletionCallback callback; 131 const int kBufferSize = 3; 132 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize)); 133 134 // If no data is available yet, ERR_IO_PENDING should be returned. 135 int result = proxy.Read(buffer.get(), kBufferSize, callback.callback()); 136 EXPECT_EQ(net::ERR_IO_PENDING, result); 137 138 // And when the data is supplied, the callback will be called. 139 scoped_ptr<std::string> data(new std::string("abcde")); 140 proxy.OnGetContent(data.Pass()); 141 142 // The returned data should be fit to the buffer size. 143 result = callback.GetResult(result); 144 EXPECT_EQ(3, result); 145 EXPECT_EQ("abc", std::string(buffer->data(), result)); 146 147 // The next Read should return immediately because there is pending data 148 result = proxy.Read(buffer.get(), kBufferSize, callback.callback()); 149 EXPECT_EQ(2, result); 150 EXPECT_EQ("de", std::string(buffer->data(), result)); 151 152 // Supply the data before calling Read operation. 153 data.reset(new std::string("fg")); 154 proxy.OnGetContent(data.Pass()); 155 data.reset(new std::string("hij")); 156 proxy.OnGetContent(data.Pass()); // Now 10 bytes are supplied. 157 158 // The data should be concatenated if possible. 159 result = proxy.Read(buffer.get(), kBufferSize, callback.callback()); 160 EXPECT_EQ(3, result); 161 EXPECT_EQ("fgh", std::string(buffer->data(), result)); 162 163 result = proxy.Read(buffer.get(), kBufferSize, callback.callback()); 164 EXPECT_EQ(2, result); 165 EXPECT_EQ("ij", std::string(buffer->data(), result)); 166 167 // The whole data is read, so Read() should return 0 immediately by then. 168 result = proxy.Read(buffer.get(), kBufferSize, callback.callback()); 169 EXPECT_EQ(0, result); 170 } 171 172 // Proxy is deleted without any called to OnCompleted(). Even in the case, 173 // cancel callback should not be invoked. 174 EXPECT_EQ(0, cancel_called); 175} 176 177TEST_F(NetworkReaderProxyTest, ReadWithLimit) { 178 NetworkReaderProxy proxy(10, 10, 10, base::Bind(&base::DoNothing)); 179 180 net::TestCompletionCallback callback; 181 const int kBufferSize = 3; 182 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize)); 183 184 // If no data is available yet, ERR_IO_PENDING should be returned. 185 int result = proxy.Read(buffer.get(), kBufferSize, callback.callback()); 186 EXPECT_EQ(net::ERR_IO_PENDING, result); 187 188 // And when the data is supplied, the callback will be called. 189 scoped_ptr<std::string> data(new std::string("abcde")); 190 proxy.OnGetContent(data.Pass()); 191 data.reset(new std::string("fgh")); 192 proxy.OnGetContent(data.Pass()); 193 data.reset(new std::string("ijklmno")); 194 proxy.OnGetContent(data.Pass()); 195 196 // The returned data should be fit to the buffer size. 197 result = callback.GetResult(result); 198 EXPECT_EQ(3, result); 199 EXPECT_EQ("klm", std::string(buffer->data(), result)); 200 201 // The next Read should return immediately because there is pending data 202 result = proxy.Read(buffer.get(), kBufferSize, callback.callback()); 203 EXPECT_EQ(2, result); 204 EXPECT_EQ("no", std::string(buffer->data(), result)); 205 206 // Supply the data before calling Read operation. 207 data.reset(new std::string("pqrs")); 208 proxy.OnGetContent(data.Pass()); 209 data.reset(new std::string("tuvwxyz")); 210 proxy.OnGetContent(data.Pass()); // 't' is the 20-th byte. 211 212 // The data should be concatenated if possible. 213 result = proxy.Read(buffer.get(), kBufferSize, callback.callback()); 214 EXPECT_EQ(3, result); 215 EXPECT_EQ("pqr", std::string(buffer->data(), result)); 216 217 result = proxy.Read(buffer.get(), kBufferSize, callback.callback()); 218 EXPECT_EQ(2, result); 219 EXPECT_EQ("st", std::string(buffer->data(), result)); 220 221 // The whole data is read, so Read() should return 0 immediately by then. 222 result = proxy.Read(buffer.get(), kBufferSize, callback.callback()); 223 EXPECT_EQ(0, result); 224} 225 226TEST_F(NetworkReaderProxyTest, ErrorWithPendingCallback) { 227 NetworkReaderProxy proxy(0, 10, 10, base::Bind(&base::DoNothing)); 228 229 net::TestCompletionCallback callback; 230 const int kBufferSize = 3; 231 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize)); 232 233 // Set pending callback. 234 int result = proxy.Read(buffer.get(), kBufferSize, callback.callback()); 235 EXPECT_EQ(net::ERR_IO_PENDING, result); 236 237 // Emulate that an error is found. The callback should be called internally. 238 proxy.OnCompleted(FILE_ERROR_FAILED); 239 result = callback.GetResult(result); 240 EXPECT_EQ(net::ERR_FAILED, result); 241 242 // The next Read call should also return the same error code. 243 EXPECT_EQ(net::ERR_FAILED, 244 proxy.Read(buffer.get(), kBufferSize, callback.callback())); 245} 246 247TEST_F(NetworkReaderProxyTest, ErrorWithPendingData) { 248 NetworkReaderProxy proxy(0, 10, 10, base::Bind(&base::DoNothing)); 249 250 net::TestCompletionCallback callback; 251 const int kBufferSize = 3; 252 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize)); 253 254 // Supply the data before an error. 255 scoped_ptr<std::string> data(new std::string("abcde")); 256 proxy.OnGetContent(data.Pass()); 257 258 // Emulate that an error is found. 259 proxy.OnCompleted(FILE_ERROR_FAILED); 260 261 // The next Read call should return the error code, even if there is 262 // pending data (the pending data should be released in OnCompleted. 263 EXPECT_EQ(net::ERR_FAILED, 264 proxy.Read(buffer.get(), kBufferSize, callback.callback())); 265} 266 267TEST_F(NetworkReaderProxyTest, CancelJob) { 268 int num_called = 0; 269 { 270 NetworkReaderProxy proxy( 271 0, 0, 0, base::Bind(&IncrementCallback, &num_called)); 272 proxy.OnCompleted(FILE_ERROR_OK); 273 // Destroy the instance after the network operation is completed. 274 // The cancelling callback shouldn't be called. 275 } 276 EXPECT_EQ(0, num_called); 277 278 num_called = 0; 279 { 280 NetworkReaderProxy proxy( 281 0, 0, 0, base::Bind(&IncrementCallback, &num_called)); 282 // Destroy the instance before the network operation is completed. 283 // The cancelling callback should be called. 284 } 285 EXPECT_EQ(1, num_called); 286} 287 288} // namespace internal 289 290class DriveFileStreamReaderTest : public ::testing::Test { 291 protected: 292 DriveFileStreamReaderTest() 293 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) { 294 } 295 296 virtual void SetUp() OVERRIDE { 297 worker_thread_.reset(new base::Thread("DriveFileStreamReaderTest")); 298 ASSERT_TRUE(worker_thread_->Start()); 299 300 // Initialize FakeDriveService. 301 fake_drive_service_.reset(new FakeDriveService); 302 ASSERT_TRUE(test_util::SetUpTestEntries(fake_drive_service_.get())); 303 304 // Create a testee instance. 305 fake_file_system_.reset( 306 new test_util::FakeFileSystem(fake_drive_service_.get())); 307 } 308 309 FileSystemInterface* GetFileSystem() { 310 return fake_file_system_.get(); 311 } 312 313 DriveFileStreamReader::FileSystemGetter GetFileSystemGetter() { 314 return base::Bind(&DriveFileStreamReaderTest::GetFileSystem, 315 base::Unretained(this)); 316 } 317 318 content::TestBrowserThreadBundle thread_bundle_; 319 320 scoped_ptr<base::Thread> worker_thread_; 321 322 scoped_ptr<FakeDriveService> fake_drive_service_; 323 scoped_ptr<test_util::FakeFileSystem> fake_file_system_; 324}; 325 326TEST_F(DriveFileStreamReaderTest, Read) { 327 const base::FilePath kDriveFile = 328 util::GetDriveMyDriveRootPath().AppendASCII("File 1.txt"); 329 // Create the reader, and initialize it. 330 // In this case, the file is not yet locally cached. 331 scoped_ptr<DriveFileStreamReader> reader(new DriveFileStreamReader( 332 GetFileSystemGetter(), worker_thread_->message_loop_proxy().get())); 333 EXPECT_FALSE(reader->IsInitialized()); 334 335 int error = net::ERR_FAILED; 336 scoped_ptr<ResourceEntry> entry; 337 { 338 base::RunLoop run_loop; 339 reader->Initialize( 340 kDriveFile, 341 net::HttpByteRange(), 342 google_apis::test_util::CreateQuitCallback( 343 &run_loop, 344 google_apis::test_util::CreateCopyResultCallback(&error, &entry))); 345 run_loop.Run(); 346 } 347 EXPECT_EQ(net::OK, error); 348 ASSERT_TRUE(entry); 349 EXPECT_TRUE(reader->IsInitialized()); 350 size_t content_size = entry->file_info().size(); 351 352 // Read data from the reader. 353 std::string first_content; 354 ASSERT_EQ(net::OK, test_util::ReadAllData(reader.get(), &first_content)); 355 EXPECT_EQ(content_size, first_content.size()); 356 357 // Create second instance and initialize it. 358 // In this case, the file should be cached one. 359 reader.reset(new DriveFileStreamReader( 360 GetFileSystemGetter(), worker_thread_->message_loop_proxy().get())); 361 EXPECT_FALSE(reader->IsInitialized()); 362 363 error = net::ERR_FAILED; 364 entry.reset(); 365 { 366 base::RunLoop run_loop; 367 reader->Initialize( 368 kDriveFile, 369 net::HttpByteRange(), 370 google_apis::test_util::CreateQuitCallback( 371 &run_loop, 372 google_apis::test_util::CreateCopyResultCallback(&error, &entry))); 373 run_loop.Run(); 374 } 375 EXPECT_EQ(net::OK, error); 376 ASSERT_TRUE(entry); 377 EXPECT_TRUE(reader->IsInitialized()); 378 379 // The size should be same. 380 EXPECT_EQ(content_size, static_cast<size_t>(entry->file_info().size())); 381 382 // Read data from the reader, again. 383 std::string second_content; 384 ASSERT_EQ(net::OK, test_util::ReadAllData(reader.get(), &second_content)); 385 386 // The same content is expected. 387 EXPECT_EQ(first_content, second_content); 388} 389 390TEST_F(DriveFileStreamReaderTest, ReadRange) { 391 // In this test case, we just confirm that the part of file is read. 392 const int64 kRangeOffset = 3; 393 const int64 kRangeLength = 4; 394 395 const base::FilePath kDriveFile = 396 util::GetDriveMyDriveRootPath().AppendASCII("File 1.txt"); 397 // Create the reader, and initialize it. 398 // In this case, the file is not yet locally cached. 399 scoped_ptr<DriveFileStreamReader> reader(new DriveFileStreamReader( 400 GetFileSystemGetter(), worker_thread_->message_loop_proxy().get())); 401 EXPECT_FALSE(reader->IsInitialized()); 402 403 int error = net::ERR_FAILED; 404 scoped_ptr<ResourceEntry> entry; 405 net::HttpByteRange byte_range; 406 byte_range.set_first_byte_position(kRangeOffset); 407 // Last byte position is inclusive. 408 byte_range.set_last_byte_position(kRangeOffset + kRangeLength - 1); 409 { 410 base::RunLoop run_loop; 411 reader->Initialize( 412 kDriveFile, 413 byte_range, 414 google_apis::test_util::CreateQuitCallback( 415 &run_loop, 416 google_apis::test_util::CreateCopyResultCallback(&error, &entry))); 417 run_loop.Run(); 418 } 419 EXPECT_EQ(net::OK, error); 420 ASSERT_TRUE(entry); 421 EXPECT_TRUE(reader->IsInitialized()); 422 423 // Read data from the reader. 424 std::string first_content; 425 ASSERT_EQ(net::OK, test_util::ReadAllData(reader.get(), &first_content)); 426 427 // The length should be equal to range length. 428 EXPECT_EQ(kRangeLength, static_cast<int64>(first_content.size())); 429 430 // Create second instance and initialize it. 431 // In this case, the file should be cached one. 432 reader.reset(new DriveFileStreamReader( 433 GetFileSystemGetter(), worker_thread_->message_loop_proxy().get())); 434 EXPECT_FALSE(reader->IsInitialized()); 435 436 error = net::ERR_FAILED; 437 entry.reset(); 438 { 439 base::RunLoop run_loop; 440 reader->Initialize( 441 kDriveFile, 442 byte_range, 443 google_apis::test_util::CreateQuitCallback( 444 &run_loop, 445 google_apis::test_util::CreateCopyResultCallback(&error, &entry))); 446 run_loop.Run(); 447 } 448 EXPECT_EQ(net::OK, error); 449 ASSERT_TRUE(entry); 450 EXPECT_TRUE(reader->IsInitialized()); 451 452 // Read data from the reader, again. 453 std::string second_content; 454 ASSERT_EQ(net::OK, test_util::ReadAllData(reader.get(), &second_content)); 455 456 // The same content is expected. 457 EXPECT_EQ(first_content, second_content); 458} 459 460TEST_F(DriveFileStreamReaderTest, OutOfRangeError) { 461 const int64 kRangeOffset = 1000000; // Out of range. 462 const int64 kRangeLength = 4; 463 464 const base::FilePath kDriveFile = 465 util::GetDriveMyDriveRootPath().AppendASCII("File 1.txt"); 466 // Create the reader, and initialize it. 467 // In this case, the file is not yet locally cached. 468 scoped_ptr<DriveFileStreamReader> reader(new DriveFileStreamReader( 469 GetFileSystemGetter(), worker_thread_->message_loop_proxy().get())); 470 EXPECT_FALSE(reader->IsInitialized()); 471 472 int error = net::ERR_FAILED; 473 scoped_ptr<ResourceEntry> entry; 474 net::HttpByteRange byte_range; 475 byte_range.set_first_byte_position(kRangeOffset); 476 // Last byte position is inclusive. 477 byte_range.set_last_byte_position(kRangeOffset + kRangeLength - 1); 478 { 479 base::RunLoop run_loop; 480 reader->Initialize( 481 kDriveFile, 482 byte_range, 483 google_apis::test_util::CreateQuitCallback( 484 &run_loop, 485 google_apis::test_util::CreateCopyResultCallback(&error, &entry))); 486 run_loop.Run(); 487 } 488 EXPECT_EQ(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE, error); 489 EXPECT_FALSE(entry); 490} 491 492TEST_F(DriveFileStreamReaderTest, ZeroByteFileRead) { 493 // Prepare an empty file 494 { 495 google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR; 496 scoped_ptr<google_apis::FileResource> entry; 497 fake_drive_service_->AddNewFile( 498 "text/plain", 499 "", // empty 500 fake_drive_service_->GetRootResourceId(), 501 "EmptyFile.txt", 502 false, // shared_with_me 503 google_apis::test_util::CreateCopyResultCallback(&error, &entry)); 504 drive::test_util::RunBlockingPoolTask(); 505 ASSERT_EQ(google_apis::HTTP_CREATED, error); 506 ASSERT_TRUE(entry); 507 ASSERT_EQ(0, entry->file_size()); 508 } 509 510 const base::FilePath kDriveFile = 511 util::GetDriveMyDriveRootPath().AppendASCII("EmptyFile.txt"); 512 // Create the reader, and initialize it. 513 // In this case, the file is not yet locally cached. 514 scoped_ptr<DriveFileStreamReader> reader(new DriveFileStreamReader( 515 GetFileSystemGetter(), worker_thread_->message_loop_proxy().get())); 516 EXPECT_FALSE(reader->IsInitialized()); 517 518 int error = net::ERR_FAILED; 519 scoped_ptr<ResourceEntry> entry; 520 { 521 base::RunLoop run_loop; 522 reader->Initialize( 523 kDriveFile, 524 net::HttpByteRange(), 525 google_apis::test_util::CreateQuitCallback( 526 &run_loop, 527 google_apis::test_util::CreateCopyResultCallback(&error, &entry))); 528 run_loop.Run(); 529 } 530 EXPECT_EQ(net::OK, error); 531 ASSERT_TRUE(entry); 532 ASSERT_EQ(0u, entry->file_info().size()); // It's a zero-byte file. 533 EXPECT_TRUE(reader->IsInitialized()); 534 535 // Read data from the reader. Check that it successfuly reads empty data. 536 std::string first_content; 537 ASSERT_EQ(net::OK, test_util::ReadAllData(reader.get(), &first_content)); 538 EXPECT_EQ(0u, first_content.size()); 539 540 // Create second instance and initialize it. 541 // In this case, the file should be cached one. 542 reader.reset(new DriveFileStreamReader( 543 GetFileSystemGetter(), worker_thread_->message_loop_proxy().get())); 544 EXPECT_FALSE(reader->IsInitialized()); 545 546 error = net::ERR_FAILED; 547 entry.reset(); 548 { 549 base::RunLoop run_loop; 550 reader->Initialize( 551 kDriveFile, 552 net::HttpByteRange(), 553 google_apis::test_util::CreateQuitCallback( 554 &run_loop, 555 google_apis::test_util::CreateCopyResultCallback(&error, &entry))); 556 run_loop.Run(); 557 } 558 EXPECT_EQ(net::OK, error); 559 ASSERT_TRUE(entry); 560 EXPECT_TRUE(reader->IsInitialized()); 561 562 // Read data from the reader, again. 563 std::string second_content; 564 ASSERT_EQ(net::OK, test_util::ReadAllData(reader.get(), &second_content)); 565 EXPECT_EQ(0u, second_content.size()); 566} 567 568} // namespace drive 569