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