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 "chrome/browser/chromeos/drive/job_scheduler.h" 6 7 #include <set> 8 9 #include "base/bind.h" 10 #include "base/file_util.h" 11 #include "base/files/scoped_temp_dir.h" 12 #include "base/prefs/testing_pref_service.h" 13 #include "base/run_loop.h" 14 #include "base/stl_util.h" 15 #include "base/strings/stringprintf.h" 16 #include "chrome/browser/chromeos/drive/test_util.h" 17 #include "chrome/browser/drive/fake_drive_service.h" 18 #include "chrome/common/pref_names.h" 19 #include "content/public/test/test_browser_thread_bundle.h" 20 #include "google_apis/drive/drive_api_parser.h" 21 #include "google_apis/drive/gdata_wapi_parser.h" 22 #include "google_apis/drive/test_util.h" 23 #include "testing/gtest/include/gtest/gtest.h" 24 25 namespace drive { 26 27 namespace { 28 29 // Dummy value passed for the |expected_file_size| parameter of DownloadFile(). 30 const int64 kDummyDownloadFileSize = 0; 31 32 void CopyTitleFromGetResourceEntryCallback( 33 std::vector<std::string>* title_list_out, 34 google_apis::GDataErrorCode error_in, 35 scoped_ptr<google_apis::ResourceEntry> resource_entry_in) { 36 title_list_out->push_back(resource_entry_in->title()); 37 } 38 39 class JobListLogger : public JobListObserver { 40 public: 41 enum EventType { 42 ADDED, 43 UPDATED, 44 DONE, 45 }; 46 47 struct EventLog { 48 EventType type; 49 JobInfo info; 50 51 EventLog(EventType type, const JobInfo& info) : type(type), info(info) { 52 } 53 }; 54 55 // Checks whether the specified type of event has occurred. 56 bool Has(EventType type, JobType job_type) { 57 for (size_t i = 0; i < events.size(); ++i) { 58 if (events[i].type == type && events[i].info.job_type == job_type) 59 return true; 60 } 61 return false; 62 } 63 64 // Gets the progress event information of the specified type. 65 void GetProgressInfo(JobType job_type, std::vector<int64>* progress) { 66 for (size_t i = 0; i < events.size(); ++i) { 67 if (events[i].type == UPDATED && events[i].info.job_type == job_type) 68 progress->push_back(events[i].info.num_completed_bytes); 69 } 70 } 71 72 // JobListObserver overrides. 73 virtual void OnJobAdded(const JobInfo& info) OVERRIDE { 74 events.push_back(EventLog(ADDED, info)); 75 } 76 77 virtual void OnJobUpdated(const JobInfo& info) OVERRIDE { 78 events.push_back(EventLog(UPDATED, info)); 79 } 80 81 virtual void OnJobDone(const JobInfo& info, FileError error) OVERRIDE { 82 events.push_back(EventLog(DONE, info)); 83 } 84 85 private: 86 std::vector<EventLog> events; 87 }; 88 89 // Fake drive service extended for testing cancellation. 90 // When upload_new_file_cancelable is set, this Drive service starts 91 // returning a closure to cancel from InitiateUploadNewFile(). The task will 92 // finish only when the cancel closure is called. 93 class CancelTestableFakeDriveService : public FakeDriveService { 94 public: 95 CancelTestableFakeDriveService() 96 : upload_new_file_cancelable_(false) { 97 } 98 99 void set_upload_new_file_cancelable(bool cancelable) { 100 upload_new_file_cancelable_ = cancelable; 101 } 102 103 virtual google_apis::CancelCallback InitiateUploadNewFile( 104 const std::string& content_type, 105 int64 content_length, 106 const std::string& parent_resource_id, 107 const std::string& title, 108 const google_apis::InitiateUploadCallback& callback) OVERRIDE { 109 if (upload_new_file_cancelable_) 110 return base::Bind(callback, google_apis::GDATA_CANCELLED, GURL()); 111 112 return FakeDriveService::InitiateUploadNewFile(content_type, 113 content_length, 114 parent_resource_id, 115 title, 116 callback); 117 } 118 119 private: 120 bool upload_new_file_cancelable_; 121 }; 122 123 } // namespace 124 125 class JobSchedulerTest : public testing::Test { 126 public: 127 JobSchedulerTest() 128 : pref_service_(new TestingPrefServiceSimple) { 129 test_util::RegisterDrivePrefs(pref_service_->registry()); 130 } 131 132 virtual void SetUp() OVERRIDE { 133 fake_network_change_notifier_.reset( 134 new test_util::FakeNetworkChangeNotifier); 135 136 fake_drive_service_.reset(new CancelTestableFakeDriveService); 137 fake_drive_service_->LoadResourceListForWapi( 138 "gdata/root_feed.json"); 139 fake_drive_service_->LoadAccountMetadataForWapi( 140 "gdata/account_metadata.json"); 141 fake_drive_service_->LoadAppListForDriveApi( 142 "drive/applist.json"); 143 144 scheduler_.reset(new JobScheduler(pref_service_.get(), 145 fake_drive_service_.get(), 146 base::MessageLoopProxy::current().get())); 147 scheduler_->SetDisableThrottling(true); 148 } 149 150 protected: 151 // Sets up FakeNetworkChangeNotifier as if it's connected to a network with 152 // the specified connection type. 153 void ChangeConnectionType(net::NetworkChangeNotifier::ConnectionType type) { 154 fake_network_change_notifier_->SetConnectionType(type); 155 } 156 157 // Sets up FakeNetworkChangeNotifier as if it's connected to wifi network. 158 void ConnectToWifi() { 159 ChangeConnectionType(net::NetworkChangeNotifier::CONNECTION_WIFI); 160 } 161 162 // Sets up FakeNetworkChangeNotifier as if it's connected to cellular network. 163 void ConnectToCellular() { 164 ChangeConnectionType(net::NetworkChangeNotifier::CONNECTION_2G); 165 } 166 167 // Sets up FakeNetworkChangeNotifier as if it's connected to wimax network. 168 void ConnectToWimax() { 169 ChangeConnectionType(net::NetworkChangeNotifier::CONNECTION_4G); 170 } 171 172 // Sets up FakeNetworkChangeNotifier as if it's disconnected. 173 void ConnectToNone() { 174 ChangeConnectionType(net::NetworkChangeNotifier::CONNECTION_NONE); 175 } 176 177 static int GetMetadataQueueMaxJobCount() { 178 return JobScheduler::kMaxJobCount[JobScheduler::METADATA_QUEUE]; 179 } 180 181 content::TestBrowserThreadBundle thread_bundle_; 182 scoped_ptr<TestingPrefServiceSimple> pref_service_; 183 scoped_ptr<test_util::FakeNetworkChangeNotifier> 184 fake_network_change_notifier_; 185 scoped_ptr<CancelTestableFakeDriveService> fake_drive_service_; 186 scoped_ptr<JobScheduler> scheduler_; 187 }; 188 189 TEST_F(JobSchedulerTest, GetAboutResource) { 190 ConnectToWifi(); 191 192 google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR; 193 scoped_ptr<google_apis::AboutResource> about_resource; 194 scheduler_->GetAboutResource( 195 google_apis::test_util::CreateCopyResultCallback( 196 &error, &about_resource)); 197 base::RunLoop().RunUntilIdle(); 198 ASSERT_EQ(google_apis::HTTP_SUCCESS, error); 199 ASSERT_TRUE(about_resource); 200 } 201 202 TEST_F(JobSchedulerTest, GetAppList) { 203 ConnectToWifi(); 204 205 google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR; 206 scoped_ptr<google_apis::AppList> app_list; 207 208 scheduler_->GetAppList( 209 google_apis::test_util::CreateCopyResultCallback(&error, &app_list)); 210 base::RunLoop().RunUntilIdle(); 211 212 ASSERT_EQ(google_apis::HTTP_SUCCESS, error); 213 ASSERT_TRUE(app_list); 214 } 215 216 TEST_F(JobSchedulerTest, GetAllResourceList) { 217 ConnectToWifi(); 218 219 google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR; 220 scoped_ptr<google_apis::ResourceList> resource_list; 221 222 scheduler_->GetAllResourceList( 223 google_apis::test_util::CreateCopyResultCallback( 224 &error, &resource_list)); 225 base::RunLoop().RunUntilIdle(); 226 227 ASSERT_EQ(google_apis::HTTP_SUCCESS, error); 228 ASSERT_TRUE(resource_list); 229 } 230 231 TEST_F(JobSchedulerTest, GetResourceListInDirectory) { 232 ConnectToWifi(); 233 234 google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR; 235 scoped_ptr<google_apis::ResourceList> resource_list; 236 237 scheduler_->GetResourceListInDirectory( 238 fake_drive_service_->GetRootResourceId(), 239 google_apis::test_util::CreateCopyResultCallback( 240 &error, &resource_list)); 241 base::RunLoop().RunUntilIdle(); 242 243 ASSERT_EQ(google_apis::HTTP_SUCCESS, error); 244 ASSERT_TRUE(resource_list); 245 } 246 247 TEST_F(JobSchedulerTest, Search) { 248 ConnectToWifi(); 249 250 google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR; 251 scoped_ptr<google_apis::ResourceList> resource_list; 252 253 scheduler_->Search( 254 "File", // search query 255 google_apis::test_util::CreateCopyResultCallback( 256 &error, &resource_list)); 257 base::RunLoop().RunUntilIdle(); 258 259 ASSERT_EQ(google_apis::HTTP_SUCCESS, error); 260 ASSERT_TRUE(resource_list); 261 } 262 263 TEST_F(JobSchedulerTest, GetChangeList) { 264 ConnectToWifi(); 265 266 google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR; 267 268 // Create a new directory. 269 // The loaded (initial) changestamp is 654321. Thus, by this operation, 270 // it should become 654322. 271 { 272 scoped_ptr<google_apis::ResourceEntry> resource_entry; 273 fake_drive_service_->AddNewDirectory( 274 fake_drive_service_->GetRootResourceId(), 275 "new directory", 276 google_apis::test_util::CreateCopyResultCallback( 277 &error, &resource_entry)); 278 base::RunLoop().RunUntilIdle(); 279 ASSERT_EQ(google_apis::HTTP_CREATED, error); 280 } 281 282 error = google_apis::GDATA_OTHER_ERROR; 283 scoped_ptr<google_apis::ResourceList> resource_list; 284 scheduler_->GetChangeList( 285 654321 + 1, // start_changestamp 286 google_apis::test_util::CreateCopyResultCallback( 287 &error, &resource_list)); 288 base::RunLoop().RunUntilIdle(); 289 290 ASSERT_EQ(google_apis::HTTP_SUCCESS, error); 291 ASSERT_TRUE(resource_list); 292 } 293 294 TEST_F(JobSchedulerTest, GetRemainingChangeList) { 295 ConnectToWifi(); 296 fake_drive_service_->set_default_max_results(2); 297 298 google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR; 299 scoped_ptr<google_apis::ResourceList> resource_list; 300 301 scheduler_->GetAllResourceList( 302 google_apis::test_util::CreateCopyResultCallback( 303 &error, &resource_list)); 304 base::RunLoop().RunUntilIdle(); 305 306 ASSERT_EQ(google_apis::HTTP_SUCCESS, error); 307 ASSERT_TRUE(resource_list); 308 309 const google_apis::Link* next_link = 310 resource_list->GetLinkByType(google_apis::Link::LINK_NEXT); 311 ASSERT_TRUE(next_link); 312 // Keep the next url before releasing the |resource_list|. 313 GURL next_url(next_link->href()); 314 315 error = google_apis::GDATA_OTHER_ERROR; 316 resource_list.reset(); 317 318 scheduler_->GetRemainingChangeList( 319 next_url, 320 google_apis::test_util::CreateCopyResultCallback( 321 &error, &resource_list)); 322 base::RunLoop().RunUntilIdle(); 323 324 ASSERT_EQ(google_apis::HTTP_SUCCESS, error); 325 ASSERT_TRUE(resource_list); 326 } 327 328 TEST_F(JobSchedulerTest, GetRemainingFileList) { 329 ConnectToWifi(); 330 fake_drive_service_->set_default_max_results(2); 331 332 google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR; 333 scoped_ptr<google_apis::ResourceList> resource_list; 334 335 scheduler_->GetResourceListInDirectory( 336 fake_drive_service_->GetRootResourceId(), 337 google_apis::test_util::CreateCopyResultCallback( 338 &error, &resource_list)); 339 base::RunLoop().RunUntilIdle(); 340 341 ASSERT_EQ(google_apis::HTTP_SUCCESS, error); 342 ASSERT_TRUE(resource_list); 343 344 const google_apis::Link* next_link = 345 resource_list->GetLinkByType(google_apis::Link::LINK_NEXT); 346 ASSERT_TRUE(next_link); 347 // Keep the next url before releasing the |resource_list|. 348 GURL next_url(next_link->href()); 349 350 error = google_apis::GDATA_OTHER_ERROR; 351 resource_list.reset(); 352 353 scheduler_->GetRemainingFileList( 354 next_url, 355 google_apis::test_util::CreateCopyResultCallback( 356 &error, &resource_list)); 357 base::RunLoop().RunUntilIdle(); 358 359 ASSERT_EQ(google_apis::HTTP_SUCCESS, error); 360 ASSERT_TRUE(resource_list); 361 } 362 363 TEST_F(JobSchedulerTest, GetResourceEntry) { 364 ConnectToWifi(); 365 366 google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR; 367 scoped_ptr<google_apis::ResourceEntry> entry; 368 369 scheduler_->GetResourceEntry( 370 "file:2_file_resource_id", // resource ID 371 ClientContext(USER_INITIATED), 372 google_apis::test_util::CreateCopyResultCallback(&error, &entry)); 373 base::RunLoop().RunUntilIdle(); 374 375 ASSERT_EQ(google_apis::HTTP_SUCCESS, error); 376 ASSERT_TRUE(entry); 377 } 378 379 TEST_F(JobSchedulerTest, GetShareUrl) { 380 ConnectToWifi(); 381 382 google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR; 383 GURL share_url; 384 385 scheduler_->GetShareUrl( 386 "file:2_file_resource_id", // resource ID 387 GURL("chrome-extension://test-id/"), // embed origin 388 ClientContext(USER_INITIATED), 389 google_apis::test_util::CreateCopyResultCallback(&error, &share_url)); 390 base::RunLoop().RunUntilIdle(); 391 392 ASSERT_EQ(google_apis::HTTP_SUCCESS, error); 393 ASSERT_FALSE(share_url.is_empty()); 394 } 395 396 TEST_F(JobSchedulerTest, TrashResource) { 397 ConnectToWifi(); 398 399 google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR; 400 401 scheduler_->TrashResource( 402 "file:2_file_resource_id", 403 ClientContext(USER_INITIATED), 404 google_apis::test_util::CreateCopyResultCallback(&error)); 405 base::RunLoop().RunUntilIdle(); 406 407 ASSERT_EQ(google_apis::HTTP_SUCCESS, error); 408 } 409 410 TEST_F(JobSchedulerTest, CopyResource) { 411 ConnectToWifi(); 412 413 google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR; 414 scoped_ptr<google_apis::ResourceEntry> entry; 415 416 scheduler_->CopyResource( 417 "file:2_file_resource_id", // resource ID 418 "folder:1_folder_resource_id", // parent resource ID 419 "New Document", // new title 420 base::Time(), 421 google_apis::test_util::CreateCopyResultCallback(&error, &entry)); 422 base::RunLoop().RunUntilIdle(); 423 424 ASSERT_EQ(google_apis::HTTP_SUCCESS, error); 425 ASSERT_TRUE(entry); 426 } 427 428 TEST_F(JobSchedulerTest, UpdateResource) { 429 ConnectToWifi(); 430 431 google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR; 432 scoped_ptr<google_apis::ResourceEntry> entry; 433 434 scheduler_->UpdateResource( 435 "file:2_file_resource_id", // resource ID 436 "folder:1_folder_resource_id", // parent resource ID 437 "New Document", // new title 438 base::Time(), 439 base::Time(), 440 ClientContext(USER_INITIATED), 441 google_apis::test_util::CreateCopyResultCallback(&error, &entry)); 442 base::RunLoop().RunUntilIdle(); 443 444 ASSERT_EQ(google_apis::HTTP_SUCCESS, error); 445 ASSERT_TRUE(entry); 446 } 447 448 TEST_F(JobSchedulerTest, RenameResource) { 449 ConnectToWifi(); 450 451 google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR; 452 453 scheduler_->RenameResource( 454 "file:2_file_resource_id", 455 "New Title", 456 google_apis::test_util::CreateCopyResultCallback(&error)); 457 base::RunLoop().RunUntilIdle(); 458 459 ASSERT_EQ(google_apis::HTTP_SUCCESS, error); 460 } 461 462 TEST_F(JobSchedulerTest, AddResourceToDirectory) { 463 ConnectToWifi(); 464 465 google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR; 466 467 scheduler_->AddResourceToDirectory( 468 "folder:1_folder_resource_id", 469 "file:2_file_resource_id", 470 google_apis::test_util::CreateCopyResultCallback(&error)); 471 base::RunLoop().RunUntilIdle(); 472 473 ASSERT_EQ(google_apis::HTTP_SUCCESS, error); 474 } 475 476 TEST_F(JobSchedulerTest, RemoveResourceFromDirectory) { 477 ConnectToWifi(); 478 479 google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR; 480 481 scheduler_->RemoveResourceFromDirectory( 482 "folder:1_folder_resource_id", 483 "file:subdirectory_file_1_id", // resource ID 484 ClientContext(USER_INITIATED), 485 google_apis::test_util::CreateCopyResultCallback(&error)); 486 base::RunLoop().RunUntilIdle(); 487 488 ASSERT_EQ(google_apis::HTTP_NO_CONTENT, error); 489 } 490 491 TEST_F(JobSchedulerTest, AddNewDirectory) { 492 ConnectToWifi(); 493 494 google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR; 495 scoped_ptr<google_apis::ResourceEntry> entry; 496 497 scheduler_->AddNewDirectory( 498 fake_drive_service_->GetRootResourceId(), // Root directory. 499 "New Directory", 500 google_apis::test_util::CreateCopyResultCallback(&error, &entry)); 501 base::RunLoop().RunUntilIdle(); 502 503 ASSERT_EQ(google_apis::HTTP_CREATED, error); 504 ASSERT_TRUE(entry); 505 } 506 507 TEST_F(JobSchedulerTest, PriorityHandling) { 508 const base::FilePath kDummyFilePath(FILE_PATH_LITERAL("dummy")); 509 510 // Saturate the metadata job queue with uninteresting jobs to prevent 511 // following jobs from starting. 512 google_apis::GDataErrorCode error_dontcare = google_apis::GDATA_OTHER_ERROR; 513 scoped_ptr<google_apis::ResourceEntry> entry_dontcare; 514 for (int i = 0; i < GetMetadataQueueMaxJobCount(); ++i) { 515 scheduler_->CreateFile( 516 fake_drive_service_->GetRootResourceId(), 517 kDummyFilePath, 518 base::StringPrintf("uninteresting file %d", i), 519 "text/plain", 520 ClientContext(USER_INITIATED), 521 google_apis::test_util::CreateCopyResultCallback(&error_dontcare, 522 &entry_dontcare)); 523 } 524 525 // Start jobs with different priorities. 526 std::string title_1("new file 1"); 527 std::string title_2("new file 2"); 528 std::string title_3("new file 3"); 529 std::string title_4("new file 4"); 530 std::vector<std::string> titles; 531 532 scheduler_->CreateFile( 533 fake_drive_service_->GetRootResourceId(), 534 kDummyFilePath, 535 title_1, 536 "text/plain", 537 ClientContext(USER_INITIATED), 538 base::Bind(&CopyTitleFromGetResourceEntryCallback, &titles)); 539 scheduler_->CreateFile( 540 fake_drive_service_->GetRootResourceId(), 541 kDummyFilePath, 542 title_2, 543 "text/plain", 544 ClientContext(BACKGROUND), 545 base::Bind(&CopyTitleFromGetResourceEntryCallback, &titles)); 546 scheduler_->CreateFile( 547 fake_drive_service_->GetRootResourceId(), 548 kDummyFilePath, 549 title_3, 550 "text/plain", 551 ClientContext(BACKGROUND), 552 base::Bind(&CopyTitleFromGetResourceEntryCallback, &titles)); 553 scheduler_->CreateFile( 554 fake_drive_service_->GetRootResourceId(), 555 kDummyFilePath, 556 title_4, 557 "text/plain", 558 ClientContext(USER_INITIATED), 559 base::Bind(&CopyTitleFromGetResourceEntryCallback, &titles)); 560 561 base::RunLoop().RunUntilIdle(); 562 563 ASSERT_EQ(4ul, titles.size()); 564 EXPECT_EQ(title_1, titles[0]); 565 EXPECT_EQ(title_4, titles[1]); 566 EXPECT_EQ(title_2, titles[2]); 567 EXPECT_EQ(title_3, titles[3]); 568 } 569 570 TEST_F(JobSchedulerTest, NoConnectionUserInitiated) { 571 ConnectToNone(); 572 573 google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR; 574 scoped_ptr<google_apis::ResourceEntry> entry; 575 scheduler_->CreateFile( 576 fake_drive_service_->GetRootResourceId(), 577 base::FilePath(FILE_PATH_LITERAL("dummy")), 578 "title", 579 "text/plain", 580 ClientContext(USER_INITIATED), 581 google_apis::test_util::CreateCopyResultCallback(&error, &entry)); 582 base::RunLoop().RunUntilIdle(); 583 584 EXPECT_EQ(google_apis::GDATA_NO_CONNECTION, error); 585 } 586 587 TEST_F(JobSchedulerTest, NoConnectionBackground) { 588 ConnectToNone(); 589 590 std::string resource_id("file:2_file_resource_id"); 591 592 google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR; 593 scoped_ptr<google_apis::ResourceEntry> entry; 594 scheduler_->CreateFile( 595 fake_drive_service_->GetRootResourceId(), 596 base::FilePath(FILE_PATH_LITERAL("dummy")), 597 "title", 598 "text/plain", 599 ClientContext(BACKGROUND), 600 google_apis::test_util::CreateCopyResultCallback(&error, &entry)); 601 base::RunLoop().RunUntilIdle(); 602 603 EXPECT_FALSE(entry); 604 605 // Reconnect to the net. 606 ConnectToWifi(); 607 608 base::RunLoop().RunUntilIdle(); 609 610 EXPECT_EQ(google_apis::HTTP_SUCCESS, error); 611 ASSERT_TRUE(entry); 612 EXPECT_EQ("title", entry->title()); 613 } 614 615 TEST_F(JobSchedulerTest, DownloadFileCellularDisabled) { 616 ConnectToCellular(); 617 618 // Disable fetching over cellular network. 619 pref_service_->SetBoolean(prefs::kDisableDriveOverCellular, true); 620 621 // Try to get a file in the background 622 base::ScopedTempDir temp_dir; 623 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 624 625 const base::FilePath kOutputFilePath = 626 temp_dir.path().AppendASCII("whatever.txt"); 627 google_apis::GDataErrorCode download_error = google_apis::GDATA_OTHER_ERROR; 628 base::FilePath output_file_path; 629 scheduler_->DownloadFile( 630 base::FilePath::FromUTF8Unsafe("drive/whatever.txt"), // virtual path 631 kDummyDownloadFileSize, 632 kOutputFilePath, 633 "file:2_file_resource_id", 634 ClientContext(BACKGROUND), 635 google_apis::test_util::CreateCopyResultCallback( 636 &download_error, &output_file_path), 637 google_apis::GetContentCallback()); 638 // Metadata should still work 639 google_apis::GDataErrorCode metadata_error = google_apis::GDATA_OTHER_ERROR; 640 scoped_ptr<google_apis::AboutResource> about_resource; 641 642 // Try to get the metadata 643 scheduler_->GetAboutResource( 644 google_apis::test_util::CreateCopyResultCallback( 645 &metadata_error, &about_resource)); 646 base::RunLoop().RunUntilIdle(); 647 648 // Check the metadata 649 ASSERT_EQ(google_apis::HTTP_SUCCESS, metadata_error); 650 ASSERT_TRUE(about_resource); 651 652 // Check the download 653 EXPECT_EQ(google_apis::GDATA_OTHER_ERROR, download_error); 654 655 // Switch to a Wifi connection 656 ConnectToWifi(); 657 658 base::RunLoop().RunUntilIdle(); 659 660 // Check the download again 661 EXPECT_EQ(google_apis::HTTP_SUCCESS, download_error); 662 std::string content; 663 EXPECT_EQ(output_file_path, kOutputFilePath); 664 ASSERT_TRUE(base::ReadFileToString(output_file_path, &content)); 665 EXPECT_EQ("This is some test content.", content); 666 } 667 668 TEST_F(JobSchedulerTest, DownloadFileWimaxDisabled) { 669 ConnectToWimax(); 670 671 // Disable fetching over cellular network. 672 pref_service_->SetBoolean(prefs::kDisableDriveOverCellular, true); 673 674 // Try to get a file in the background 675 base::ScopedTempDir temp_dir; 676 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 677 678 const base::FilePath kOutputFilePath = 679 temp_dir.path().AppendASCII("whatever.txt"); 680 google_apis::GDataErrorCode download_error = google_apis::GDATA_OTHER_ERROR; 681 base::FilePath output_file_path; 682 scheduler_->DownloadFile( 683 base::FilePath::FromUTF8Unsafe("drive/whatever.txt"), // virtual path 684 kDummyDownloadFileSize, 685 kOutputFilePath, 686 "file:2_file_resource_id", 687 ClientContext(BACKGROUND), 688 google_apis::test_util::CreateCopyResultCallback( 689 &download_error, &output_file_path), 690 google_apis::GetContentCallback()); 691 // Metadata should still work 692 google_apis::GDataErrorCode metadata_error = google_apis::GDATA_OTHER_ERROR; 693 scoped_ptr<google_apis::AboutResource> about_resource; 694 695 // Try to get the metadata 696 scheduler_->GetAboutResource( 697 google_apis::test_util::CreateCopyResultCallback( 698 &metadata_error, &about_resource)); 699 base::RunLoop().RunUntilIdle(); 700 701 // Check the metadata 702 ASSERT_EQ(google_apis::HTTP_SUCCESS, metadata_error); 703 ASSERT_TRUE(about_resource); 704 705 // Check the download 706 EXPECT_EQ(google_apis::GDATA_OTHER_ERROR, download_error); 707 708 // Switch to a Wifi connection 709 ConnectToWifi(); 710 711 base::RunLoop().RunUntilIdle(); 712 713 // Check the download again 714 EXPECT_EQ(google_apis::HTTP_SUCCESS, download_error); 715 std::string content; 716 EXPECT_EQ(output_file_path, kOutputFilePath); 717 ASSERT_TRUE(base::ReadFileToString(output_file_path, &content)); 718 EXPECT_EQ("This is some test content.", content); 719 } 720 721 TEST_F(JobSchedulerTest, DownloadFileCellularEnabled) { 722 ConnectToCellular(); 723 724 // Enable fetching over cellular network. 725 pref_service_->SetBoolean(prefs::kDisableDriveOverCellular, false); 726 727 // Try to get a file in the background 728 base::ScopedTempDir temp_dir; 729 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 730 731 const base::FilePath kOutputFilePath = 732 temp_dir.path().AppendASCII("whatever.txt"); 733 google_apis::GDataErrorCode download_error = google_apis::GDATA_OTHER_ERROR; 734 base::FilePath output_file_path; 735 scheduler_->DownloadFile( 736 base::FilePath::FromUTF8Unsafe("drive/whatever.txt"), // virtual path 737 kDummyDownloadFileSize, 738 kOutputFilePath, 739 "file:2_file_resource_id", 740 ClientContext(BACKGROUND), 741 google_apis::test_util::CreateCopyResultCallback( 742 &download_error, &output_file_path), 743 google_apis::GetContentCallback()); 744 // Metadata should still work 745 google_apis::GDataErrorCode metadata_error = google_apis::GDATA_OTHER_ERROR; 746 scoped_ptr<google_apis::AboutResource> about_resource; 747 748 // Try to get the metadata 749 scheduler_->GetAboutResource( 750 google_apis::test_util::CreateCopyResultCallback( 751 &metadata_error, &about_resource)); 752 base::RunLoop().RunUntilIdle(); 753 754 // Check the metadata 755 ASSERT_EQ(google_apis::HTTP_SUCCESS, metadata_error); 756 ASSERT_TRUE(about_resource); 757 758 // Check the download 759 EXPECT_EQ(google_apis::HTTP_SUCCESS, download_error); 760 std::string content; 761 EXPECT_EQ(output_file_path, kOutputFilePath); 762 ASSERT_TRUE(base::ReadFileToString(output_file_path, &content)); 763 EXPECT_EQ("This is some test content.", content); 764 } 765 766 TEST_F(JobSchedulerTest, DownloadFileWimaxEnabled) { 767 ConnectToWimax(); 768 769 // Enable fetching over cellular network. 770 pref_service_->SetBoolean(prefs::kDisableDriveOverCellular, false); 771 772 // Try to get a file in the background 773 base::ScopedTempDir temp_dir; 774 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 775 776 const base::FilePath kOutputFilePath = 777 temp_dir.path().AppendASCII("whatever.txt"); 778 google_apis::GDataErrorCode download_error = google_apis::GDATA_OTHER_ERROR; 779 base::FilePath output_file_path; 780 scheduler_->DownloadFile( 781 base::FilePath::FromUTF8Unsafe("drive/whatever.txt"), // virtual path 782 kDummyDownloadFileSize, 783 kOutputFilePath, 784 "file:2_file_resource_id", 785 ClientContext(BACKGROUND), 786 google_apis::test_util::CreateCopyResultCallback( 787 &download_error, &output_file_path), 788 google_apis::GetContentCallback()); 789 // Metadata should still work 790 google_apis::GDataErrorCode metadata_error = google_apis::GDATA_OTHER_ERROR; 791 scoped_ptr<google_apis::AboutResource> about_resource; 792 793 // Try to get the metadata 794 scheduler_->GetAboutResource( 795 google_apis::test_util::CreateCopyResultCallback( 796 &metadata_error, &about_resource)); 797 base::RunLoop().RunUntilIdle(); 798 799 // Check the metadata 800 ASSERT_EQ(google_apis::HTTP_SUCCESS, metadata_error); 801 ASSERT_TRUE(about_resource); 802 803 // Check the download 804 EXPECT_EQ(google_apis::HTTP_SUCCESS, download_error); 805 std::string content; 806 EXPECT_EQ(output_file_path, kOutputFilePath); 807 ASSERT_TRUE(base::ReadFileToString(output_file_path, &content)); 808 EXPECT_EQ("This is some test content.", content); 809 } 810 811 TEST_F(JobSchedulerTest, JobInfo) { 812 JobListLogger logger; 813 scheduler_->AddObserver(&logger); 814 815 // Disable background upload/download. 816 ConnectToWimax(); 817 pref_service_->SetBoolean(prefs::kDisableDriveOverCellular, true); 818 819 base::ScopedTempDir temp_dir; 820 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 821 822 google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR; 823 scoped_ptr<google_apis::ResourceEntry> entry; 824 scoped_ptr<google_apis::AboutResource> about_resource; 825 base::FilePath path; 826 827 std::set<JobType> expected_types; 828 829 // Add many jobs. 830 expected_types.insert(TYPE_ADD_NEW_DIRECTORY); 831 scheduler_->AddNewDirectory( 832 fake_drive_service_->GetRootResourceId(), 833 "New Directory", 834 google_apis::test_util::CreateCopyResultCallback(&error, &entry)); 835 expected_types.insert(TYPE_GET_ABOUT_RESOURCE); 836 scheduler_->GetAboutResource( 837 google_apis::test_util::CreateCopyResultCallback( 838 &error, &about_resource)); 839 expected_types.insert(TYPE_RENAME_RESOURCE); 840 scheduler_->RenameResource( 841 "file:2_file_resource_id", 842 "New Title", 843 google_apis::test_util::CreateCopyResultCallback(&error)); 844 expected_types.insert(TYPE_DOWNLOAD_FILE); 845 scheduler_->DownloadFile( 846 base::FilePath::FromUTF8Unsafe("drive/whatever.txt"), // virtual path 847 kDummyDownloadFileSize, 848 temp_dir.path().AppendASCII("whatever.txt"), 849 "file:2_file_resource_id", 850 ClientContext(BACKGROUND), 851 google_apis::test_util::CreateCopyResultCallback(&error, &path), 852 google_apis::GetContentCallback()); 853 854 // The number of jobs queued so far. 855 EXPECT_EQ(4U, scheduler_->GetJobInfoList().size()); 856 EXPECT_TRUE(logger.Has(JobListLogger::ADDED, TYPE_ADD_NEW_DIRECTORY)); 857 EXPECT_TRUE(logger.Has(JobListLogger::ADDED, TYPE_GET_ABOUT_RESOURCE)); 858 EXPECT_TRUE(logger.Has(JobListLogger::ADDED, TYPE_RENAME_RESOURCE)); 859 EXPECT_TRUE(logger.Has(JobListLogger::ADDED, TYPE_DOWNLOAD_FILE)); 860 EXPECT_FALSE(logger.Has(JobListLogger::DONE, TYPE_ADD_NEW_DIRECTORY)); 861 EXPECT_FALSE(logger.Has(JobListLogger::DONE, TYPE_GET_ABOUT_RESOURCE)); 862 EXPECT_FALSE(logger.Has(JobListLogger::DONE, TYPE_RENAME_RESOURCE)); 863 EXPECT_FALSE(logger.Has(JobListLogger::DONE, TYPE_DOWNLOAD_FILE)); 864 865 // Add more jobs. 866 expected_types.insert(TYPE_ADD_RESOURCE_TO_DIRECTORY); 867 scheduler_->AddResourceToDirectory( 868 "folder:1_folder_resource_id", 869 "file:2_file_resource_id", 870 google_apis::test_util::CreateCopyResultCallback(&error)); 871 expected_types.insert(TYPE_COPY_RESOURCE); 872 scheduler_->CopyResource( 873 "document:5_document_resource_id", 874 fake_drive_service_->GetRootResourceId(), 875 "New Document", 876 base::Time(), // last_modified 877 google_apis::test_util::CreateCopyResultCallback(&error, &entry)); 878 879 // 6 jobs in total were queued. 880 std::vector<JobInfo> jobs = scheduler_->GetJobInfoList(); 881 EXPECT_EQ(6U, jobs.size()); 882 std::set<JobType> actual_types; 883 std::set<JobID> job_ids; 884 for (size_t i = 0; i < jobs.size(); ++i) { 885 actual_types.insert(jobs[i].job_type); 886 job_ids.insert(jobs[i].job_id); 887 } 888 EXPECT_EQ(expected_types, actual_types); 889 EXPECT_EQ(6U, job_ids.size()) << "All job IDs must be unique"; 890 EXPECT_TRUE(logger.Has(JobListLogger::ADDED, TYPE_ADD_RESOURCE_TO_DIRECTORY)); 891 EXPECT_TRUE(logger.Has(JobListLogger::ADDED, TYPE_COPY_RESOURCE)); 892 EXPECT_FALSE(logger.Has(JobListLogger::DONE, TYPE_ADD_RESOURCE_TO_DIRECTORY)); 893 EXPECT_FALSE(logger.Has(JobListLogger::DONE, TYPE_COPY_RESOURCE)); 894 895 // Run the jobs. 896 base::RunLoop().RunUntilIdle(); 897 898 // All jobs except the BACKGROUND job should have started running (UPDATED) 899 // and then finished (DONE). 900 jobs = scheduler_->GetJobInfoList(); 901 ASSERT_EQ(1U, jobs.size()); 902 EXPECT_EQ(TYPE_DOWNLOAD_FILE, jobs[0].job_type); 903 904 EXPECT_TRUE(logger.Has(JobListLogger::UPDATED, TYPE_ADD_NEW_DIRECTORY)); 905 EXPECT_TRUE(logger.Has(JobListLogger::UPDATED, TYPE_GET_ABOUT_RESOURCE)); 906 EXPECT_TRUE(logger.Has(JobListLogger::UPDATED, TYPE_RENAME_RESOURCE)); 907 EXPECT_TRUE(logger.Has(JobListLogger::UPDATED, 908 TYPE_ADD_RESOURCE_TO_DIRECTORY)); 909 EXPECT_TRUE(logger.Has(JobListLogger::UPDATED, TYPE_COPY_RESOURCE)); 910 EXPECT_FALSE(logger.Has(JobListLogger::UPDATED, TYPE_DOWNLOAD_FILE)); 911 912 EXPECT_TRUE(logger.Has(JobListLogger::DONE, TYPE_ADD_NEW_DIRECTORY)); 913 EXPECT_TRUE(logger.Has(JobListLogger::DONE, TYPE_GET_ABOUT_RESOURCE)); 914 EXPECT_TRUE(logger.Has(JobListLogger::DONE, TYPE_RENAME_RESOURCE)); 915 EXPECT_TRUE(logger.Has(JobListLogger::DONE, TYPE_ADD_RESOURCE_TO_DIRECTORY)); 916 EXPECT_TRUE(logger.Has(JobListLogger::DONE, TYPE_COPY_RESOURCE)); 917 EXPECT_FALSE(logger.Has(JobListLogger::DONE, TYPE_DOWNLOAD_FILE)); 918 919 // Run the background downloading job as well. 920 ConnectToWifi(); 921 base::RunLoop().RunUntilIdle(); 922 923 // All jobs should have finished. 924 EXPECT_EQ(0U, scheduler_->GetJobInfoList().size()); 925 EXPECT_TRUE(logger.Has(JobListLogger::UPDATED, TYPE_DOWNLOAD_FILE)); 926 EXPECT_TRUE(logger.Has(JobListLogger::DONE, TYPE_DOWNLOAD_FILE)); 927 } 928 929 TEST_F(JobSchedulerTest, JobInfoProgress) { 930 JobListLogger logger; 931 scheduler_->AddObserver(&logger); 932 933 ConnectToWifi(); 934 935 base::ScopedTempDir temp_dir; 936 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 937 938 google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR; 939 base::FilePath path; 940 941 // Download job. 942 scheduler_->DownloadFile( 943 base::FilePath::FromUTF8Unsafe("drive/whatever.txt"), // virtual path 944 kDummyDownloadFileSize, 945 temp_dir.path().AppendASCII("whatever.txt"), 946 "file:2_file_resource_id", 947 ClientContext(BACKGROUND), 948 google_apis::test_util::CreateCopyResultCallback(&error, &path), 949 google_apis::GetContentCallback()); 950 base::RunLoop().RunUntilIdle(); 951 952 std::vector<int64> download_progress; 953 logger.GetProgressInfo(TYPE_DOWNLOAD_FILE, &download_progress); 954 ASSERT_TRUE(!download_progress.empty()); 955 EXPECT_TRUE(base::STLIsSorted(download_progress)); 956 EXPECT_GE(download_progress.front(), 0); 957 EXPECT_LE(download_progress.back(), 26); 958 959 // Upload job. 960 path = temp_dir.path().AppendASCII("new_file.txt"); 961 ASSERT_TRUE(google_apis::test_util::WriteStringToFile(path, "Hello")); 962 google_apis::GDataErrorCode upload_error = 963 google_apis::GDATA_OTHER_ERROR; 964 scoped_ptr<google_apis::ResourceEntry> entry; 965 966 scheduler_->UploadNewFile( 967 fake_drive_service_->GetRootResourceId(), 968 base::FilePath::FromUTF8Unsafe("drive/new_file.txt"), 969 path, 970 "dummy title", 971 "plain/plain", 972 ClientContext(BACKGROUND), 973 google_apis::test_util::CreateCopyResultCallback(&upload_error, &entry)); 974 base::RunLoop().RunUntilIdle(); 975 976 std::vector<int64> upload_progress; 977 logger.GetProgressInfo(TYPE_UPLOAD_NEW_FILE, &upload_progress); 978 ASSERT_TRUE(!upload_progress.empty()); 979 EXPECT_TRUE(base::STLIsSorted(upload_progress)); 980 EXPECT_GE(upload_progress.front(), 0); 981 EXPECT_LE(upload_progress.back(), 13); 982 } 983 984 TEST_F(JobSchedulerTest, CancelPendingJob) { 985 base::ScopedTempDir temp_dir; 986 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 987 base::FilePath upload_path = temp_dir.path().AppendASCII("new_file.txt"); 988 ASSERT_TRUE(google_apis::test_util::WriteStringToFile(upload_path, "Hello")); 989 990 // To create a pending job for testing, set the mode to cellular connection 991 // and issue BACKGROUND jobs. 992 ConnectToCellular(); 993 pref_service_->SetBoolean(prefs::kDisableDriveOverCellular, true); 994 995 // Start the first job and record its job ID. 996 google_apis::GDataErrorCode error1 = google_apis::GDATA_OTHER_ERROR; 997 scoped_ptr<google_apis::ResourceEntry> entry; 998 scheduler_->UploadNewFile( 999 fake_drive_service_->GetRootResourceId(), 1000 base::FilePath::FromUTF8Unsafe("dummy/path"), 1001 upload_path, 1002 "dummy title 1", 1003 "text/plain", 1004 ClientContext(BACKGROUND), 1005 google_apis::test_util::CreateCopyResultCallback(&error1, &entry)); 1006 1007 const std::vector<JobInfo>& jobs = scheduler_->GetJobInfoList(); 1008 ASSERT_EQ(1u, jobs.size()); 1009 ASSERT_EQ(STATE_NONE, jobs[0].state); // Not started yet. 1010 JobID first_job_id = jobs[0].job_id; 1011 1012 // Start the second job. 1013 google_apis::GDataErrorCode error2 = google_apis::GDATA_OTHER_ERROR; 1014 scheduler_->UploadNewFile( 1015 fake_drive_service_->GetRootResourceId(), 1016 base::FilePath::FromUTF8Unsafe("dummy/path"), 1017 upload_path, 1018 "dummy title 2", 1019 "text/plain", 1020 ClientContext(BACKGROUND), 1021 google_apis::test_util::CreateCopyResultCallback(&error2, &entry)); 1022 1023 // Cancel the first one. 1024 scheduler_->CancelJob(first_job_id); 1025 1026 // Only the first job should be cancelled. 1027 ConnectToWifi(); 1028 base::RunLoop().RunUntilIdle(); 1029 EXPECT_EQ(google_apis::GDATA_CANCELLED, error1); 1030 EXPECT_EQ(google_apis::HTTP_SUCCESS, error2); 1031 EXPECT_TRUE(scheduler_->GetJobInfoList().empty()); 1032 } 1033 1034 TEST_F(JobSchedulerTest, CancelRunningJob) { 1035 ConnectToWifi(); 1036 1037 base::ScopedTempDir temp_dir; 1038 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 1039 base::FilePath upload_path = temp_dir.path().AppendASCII("new_file.txt"); 1040 ASSERT_TRUE(google_apis::test_util::WriteStringToFile(upload_path, "Hello")); 1041 1042 // Run as a cancelable task. 1043 fake_drive_service_->set_upload_new_file_cancelable(true); 1044 google_apis::GDataErrorCode error1 = google_apis::GDATA_OTHER_ERROR; 1045 scoped_ptr<google_apis::ResourceEntry> entry; 1046 scheduler_->UploadNewFile( 1047 fake_drive_service_->GetRootResourceId(), 1048 base::FilePath::FromUTF8Unsafe("dummy/path"), 1049 upload_path, 1050 "dummy title 1", 1051 "text/plain", 1052 ClientContext(USER_INITIATED), 1053 google_apis::test_util::CreateCopyResultCallback(&error1, &entry)); 1054 1055 const std::vector<JobInfo>& jobs = scheduler_->GetJobInfoList(); 1056 ASSERT_EQ(1u, jobs.size()); 1057 ASSERT_EQ(STATE_RUNNING, jobs[0].state); // It's running. 1058 JobID first_job_id = jobs[0].job_id; 1059 1060 // Start the second job normally. 1061 fake_drive_service_->set_upload_new_file_cancelable(false); 1062 google_apis::GDataErrorCode error2 = google_apis::GDATA_OTHER_ERROR; 1063 scheduler_->UploadNewFile( 1064 fake_drive_service_->GetRootResourceId(), 1065 base::FilePath::FromUTF8Unsafe("dummy/path"), 1066 upload_path, 1067 "dummy title 2", 1068 "text/plain", 1069 ClientContext(USER_INITIATED), 1070 google_apis::test_util::CreateCopyResultCallback(&error2, &entry)); 1071 1072 // Cancel the first one. 1073 scheduler_->CancelJob(first_job_id); 1074 1075 // Only the first job should be cancelled. 1076 base::RunLoop().RunUntilIdle(); 1077 EXPECT_EQ(google_apis::GDATA_CANCELLED, error1); 1078 EXPECT_EQ(google_apis::HTTP_SUCCESS, error2); 1079 EXPECT_TRUE(scheduler_->GetJobInfoList().empty()); 1080 } 1081 1082 } // namespace drive 1083