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