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