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