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
CopyTitleFromGetResourceEntryCallback(std::vector<std::string> * title_list_out,google_apis::GDataErrorCode error_in,scoped_ptr<google_apis::ResourceEntry> resource_entry_in)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
EventLogdrive::__anon847efbd90111::JobListLogger::EventLog51 EventLog(EventType type, const JobInfo& info) : type(type), info(info) {
52 }
53 };
54
55 // Checks whether the specified type of event has occurred.
Has(EventType type,JobType job_type)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.
GetProgressInfo(JobType job_type,std::vector<int64> * progress)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.
OnJobAdded(const JobInfo & info)73 virtual void OnJobAdded(const JobInfo& info) OVERRIDE {
74 events.push_back(EventLog(ADDED, info));
75 }
76
OnJobUpdated(const JobInfo & info)77 virtual void OnJobUpdated(const JobInfo& info) OVERRIDE {
78 events.push_back(EventLog(UPDATED, info));
79 }
80
OnJobDone(const JobInfo & info,FileError error)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:
CancelTestableFakeDriveService()95 CancelTestableFakeDriveService()
96 : upload_new_file_cancelable_(false) {
97 }
98
set_upload_new_file_cancelable(bool cancelable)99 void set_upload_new_file_cancelable(bool cancelable) {
100 upload_new_file_cancelable_ = cancelable;
101 }
102
InitiateUploadNewFile(const std::string & content_type,int64 content_length,const std::string & parent_resource_id,const std::string & title,const google_apis::InitiateUploadCallback & callback)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:
JobSchedulerTest()127 JobSchedulerTest()
128 : pref_service_(new TestingPrefServiceSimple) {
129 test_util::RegisterDrivePrefs(pref_service_->registry());
130 }
131
SetUp()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.
ChangeConnectionType(net::NetworkChangeNotifier::ConnectionType 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.
ConnectToWifi()158 void ConnectToWifi() {
159 ChangeConnectionType(net::NetworkChangeNotifier::CONNECTION_WIFI);
160 }
161
162 // Sets up FakeNetworkChangeNotifier as if it's connected to cellular network.
ConnectToCellular()163 void ConnectToCellular() {
164 ChangeConnectionType(net::NetworkChangeNotifier::CONNECTION_2G);
165 }
166
167 // Sets up FakeNetworkChangeNotifier as if it's connected to wimax network.
ConnectToWimax()168 void ConnectToWimax() {
169 ChangeConnectionType(net::NetworkChangeNotifier::CONNECTION_4G);
170 }
171
172 // Sets up FakeNetworkChangeNotifier as if it's disconnected.
ConnectToNone()173 void ConnectToNone() {
174 ChangeConnectionType(net::NetworkChangeNotifier::CONNECTION_NONE);
175 }
176
GetMetadataQueueMaxJobCount()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
TEST_F(JobSchedulerTest,GetAboutResource)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
TEST_F(JobSchedulerTest,GetAppList)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
TEST_F(JobSchedulerTest,GetAllResourceList)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
TEST_F(JobSchedulerTest,GetResourceListInDirectory)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
TEST_F(JobSchedulerTest,Search)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
TEST_F(JobSchedulerTest,GetChangeList)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
TEST_F(JobSchedulerTest,GetRemainingChangeList)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
TEST_F(JobSchedulerTest,GetRemainingFileList)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
TEST_F(JobSchedulerTest,GetResourceEntry)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
TEST_F(JobSchedulerTest,GetShareUrl)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
TEST_F(JobSchedulerTest,TrashResource)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
TEST_F(JobSchedulerTest,CopyResource)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
TEST_F(JobSchedulerTest,UpdateResource)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
TEST_F(JobSchedulerTest,RenameResource)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
TEST_F(JobSchedulerTest,AddResourceToDirectory)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
TEST_F(JobSchedulerTest,RemoveResourceFromDirectory)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
TEST_F(JobSchedulerTest,AddNewDirectory)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
TEST_F(JobSchedulerTest,PriorityHandling)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
TEST_F(JobSchedulerTest,NoConnectionUserInitiated)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
TEST_F(JobSchedulerTest,NoConnectionBackground)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
TEST_F(JobSchedulerTest,DownloadFileCellularDisabled)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
TEST_F(JobSchedulerTest,DownloadFileWimaxDisabled)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
TEST_F(JobSchedulerTest,DownloadFileCellularEnabled)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
TEST_F(JobSchedulerTest,DownloadFileWimaxEnabled)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
TEST_F(JobSchedulerTest,JobInfo)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
TEST_F(JobSchedulerTest,JobInfoProgress)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
TEST_F(JobSchedulerTest,CancelPendingJob)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
TEST_F(JobSchedulerTest,CancelRunningJob)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