- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / drive / job_scheduler_unittest.cc
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/browser/google_apis/drive_api_parser.h"
19 #include "chrome/browser/google_apis/gdata_wapi_parser.h"
20 #include "chrome/browser/google_apis/test_util.h"
21 #include "chrome/common/pref_names.h"
22 #include "content/public/test/test_browser_thread_bundle.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, GetShareUrl) {
364   ConnectToWifi();
365
366   google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
367   GURL share_url;
368
369   scheduler_->GetShareUrl(
370       "file:2_file_resource_id",  // resource ID
371       GURL("chrome-extension://test-id/"), // embed origin
372       ClientContext(USER_INITIATED),
373       google_apis::test_util::CreateCopyResultCallback(&error, &share_url));
374   base::RunLoop().RunUntilIdle();
375
376   ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
377   ASSERT_FALSE(share_url.is_empty());
378 }
379
380 TEST_F(JobSchedulerTest, DeleteResource) {
381   ConnectToWifi();
382
383   google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
384
385   scheduler_->DeleteResource(
386       "file:2_file_resource_id",
387       google_apis::test_util::CreateCopyResultCallback(&error));
388   base::RunLoop().RunUntilIdle();
389
390   ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
391 }
392
393 TEST_F(JobSchedulerTest, CopyResource) {
394   ConnectToWifi();
395
396   google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
397   scoped_ptr<google_apis::ResourceEntry> entry;
398
399   scheduler_->CopyResource(
400       "file:2_file_resource_id",  // resource ID
401       "folder:1_folder_resource_id",  // parent resource ID
402       "New Document",  // new title
403       base::Time(),
404       google_apis::test_util::CreateCopyResultCallback(&error, &entry));
405   base::RunLoop().RunUntilIdle();
406
407   ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
408   ASSERT_TRUE(entry);
409 }
410
411 TEST_F(JobSchedulerTest, CopyHostedDocument) {
412   ConnectToWifi();
413
414   google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
415   scoped_ptr<google_apis::ResourceEntry> entry;
416
417   scheduler_->CopyHostedDocument(
418       "document:5_document_resource_id",  // resource ID
419       "New Document",  // new title
420       google_apis::test_util::CreateCopyResultCallback(&error, &entry));
421   base::RunLoop().RunUntilIdle();
422
423   ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
424   ASSERT_TRUE(entry);
425 }
426
427 TEST_F(JobSchedulerTest, MoveResource) {
428   ConnectToWifi();
429
430   google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
431   scoped_ptr<google_apis::ResourceEntry> entry;
432
433   scheduler_->MoveResource(
434       "file:2_file_resource_id",  // resource ID
435       "folder:1_folder_resource_id",  // parent resource ID
436       "New Document",  // new title
437       base::Time(),
438       google_apis::test_util::CreateCopyResultCallback(&error, &entry));
439   base::RunLoop().RunUntilIdle();
440
441   ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
442   ASSERT_TRUE(entry);
443 }
444
445 TEST_F(JobSchedulerTest, RenameResource) {
446   ConnectToWifi();
447
448   google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
449
450   scheduler_->RenameResource(
451       "file:2_file_resource_id",
452       "New Title",
453       google_apis::test_util::CreateCopyResultCallback(&error));
454   base::RunLoop().RunUntilIdle();
455
456   ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
457 }
458
459 TEST_F(JobSchedulerTest, AddResourceToDirectory) {
460   ConnectToWifi();
461
462   google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
463
464   scheduler_->AddResourceToDirectory(
465       "folder:1_folder_resource_id",
466       "file:2_file_resource_id",
467       google_apis::test_util::CreateCopyResultCallback(&error));
468   base::RunLoop().RunUntilIdle();
469
470   ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
471 }
472
473 TEST_F(JobSchedulerTest, RemoveResourceFromDirectory) {
474   ConnectToWifi();
475
476   google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
477
478   scheduler_->RemoveResourceFromDirectory(
479       "folder:1_folder_resource_id",
480       "file:subdirectory_file_1_id",  // resource ID
481       google_apis::test_util::CreateCopyResultCallback(&error));
482   base::RunLoop().RunUntilIdle();
483
484   ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
485 }
486
487 TEST_F(JobSchedulerTest, AddNewDirectory) {
488   ConnectToWifi();
489
490   google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
491   scoped_ptr<google_apis::ResourceEntry> entry;
492
493   scheduler_->AddNewDirectory(
494       fake_drive_service_->GetRootResourceId(),  // Root directory.
495       "New Directory",
496       google_apis::test_util::CreateCopyResultCallback(&error, &entry));
497   base::RunLoop().RunUntilIdle();
498
499   ASSERT_EQ(google_apis::HTTP_CREATED, error);
500   ASSERT_TRUE(entry);
501 }
502
503 TEST_F(JobSchedulerTest, PriorityHandling) {
504   const base::FilePath kDummyFilePath(FILE_PATH_LITERAL("dummy"));
505
506   // Saturate the metadata job queue with uninteresting jobs to prevent
507   // following jobs from starting.
508   google_apis::GDataErrorCode error_dontcare = google_apis::GDATA_OTHER_ERROR;
509   scoped_ptr<google_apis::ResourceEntry> entry_dontcare;
510   for (int i = 0; i < GetMetadataQueueMaxJobCount(); ++i) {
511     scheduler_->CreateFile(
512         fake_drive_service_->GetRootResourceId(),
513         kDummyFilePath,
514         base::StringPrintf("uninteresting file %d", i),
515         "text/plain",
516         ClientContext(USER_INITIATED),
517         google_apis::test_util::CreateCopyResultCallback(&error_dontcare,
518                                                          &entry_dontcare));
519   }
520
521   // Start jobs with different priorities.
522   std::string title_1("new file 1");
523   std::string title_2("new file 2");
524   std::string title_3("new file 3");
525   std::string title_4("new file 4");
526   std::vector<std::string> titles;
527
528   scheduler_->CreateFile(
529       fake_drive_service_->GetRootResourceId(),
530       kDummyFilePath,
531       title_1,
532       "text/plain",
533       ClientContext(USER_INITIATED),
534       base::Bind(&CopyTitleFromGetResourceEntryCallback, &titles));
535   scheduler_->CreateFile(
536       fake_drive_service_->GetRootResourceId(),
537       kDummyFilePath,
538       title_2,
539       "text/plain",
540       ClientContext(BACKGROUND),
541       base::Bind(&CopyTitleFromGetResourceEntryCallback, &titles));
542   scheduler_->CreateFile(
543       fake_drive_service_->GetRootResourceId(),
544       kDummyFilePath,
545       title_3,
546       "text/plain",
547       ClientContext(BACKGROUND),
548       base::Bind(&CopyTitleFromGetResourceEntryCallback, &titles));
549   scheduler_->CreateFile(
550       fake_drive_service_->GetRootResourceId(),
551       kDummyFilePath,
552       title_4,
553       "text/plain",
554       ClientContext(USER_INITIATED),
555       base::Bind(&CopyTitleFromGetResourceEntryCallback, &titles));
556
557   base::RunLoop().RunUntilIdle();
558
559   ASSERT_EQ(4ul, titles.size());
560   EXPECT_EQ(title_1, titles[0]);
561   EXPECT_EQ(title_4, titles[1]);
562   EXPECT_EQ(title_2, titles[2]);
563   EXPECT_EQ(title_3, titles[3]);
564 }
565
566 TEST_F(JobSchedulerTest, NoConnectionUserInitiated) {
567   ConnectToNone();
568
569   google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
570   scoped_ptr<google_apis::ResourceEntry> entry;
571   scheduler_->CreateFile(
572       fake_drive_service_->GetRootResourceId(),
573       base::FilePath(FILE_PATH_LITERAL("dummy")),
574       "title",
575       "text/plain",
576       ClientContext(USER_INITIATED),
577       google_apis::test_util::CreateCopyResultCallback(&error, &entry));
578   base::RunLoop().RunUntilIdle();
579
580   EXPECT_EQ(google_apis::GDATA_NO_CONNECTION, error);
581 }
582
583 TEST_F(JobSchedulerTest, NoConnectionBackground) {
584   ConnectToNone();
585
586   std::string resource_id("file:2_file_resource_id");
587
588   google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
589   scoped_ptr<google_apis::ResourceEntry> entry;
590   scheduler_->CreateFile(
591       fake_drive_service_->GetRootResourceId(),
592       base::FilePath(FILE_PATH_LITERAL("dummy")),
593       "title",
594       "text/plain",
595       ClientContext(BACKGROUND),
596       google_apis::test_util::CreateCopyResultCallback(&error, &entry));
597   base::RunLoop().RunUntilIdle();
598
599   EXPECT_FALSE(entry);
600
601   // Reconnect to the net.
602   ConnectToWifi();
603
604   base::RunLoop().RunUntilIdle();
605
606   EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
607   ASSERT_TRUE(entry);
608   EXPECT_EQ("title", entry->title());
609 }
610
611 TEST_F(JobSchedulerTest, DownloadFileCellularDisabled) {
612   ConnectToCellular();
613
614   // Disable fetching over cellular network.
615   pref_service_->SetBoolean(prefs::kDisableDriveOverCellular, true);
616
617   // Try to get a file in the background
618   base::ScopedTempDir temp_dir;
619   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
620
621   const base::FilePath kOutputFilePath =
622       temp_dir.path().AppendASCII("whatever.txt");
623   google_apis::GDataErrorCode download_error = google_apis::GDATA_OTHER_ERROR;
624   base::FilePath output_file_path;
625   scheduler_->DownloadFile(
626       base::FilePath::FromUTF8Unsafe("drive/whatever.txt"),  // virtual path
627       kDummyDownloadFileSize,
628       kOutputFilePath,
629       "file:2_file_resource_id",
630       ClientContext(BACKGROUND),
631       google_apis::test_util::CreateCopyResultCallback(
632           &download_error, &output_file_path),
633       google_apis::GetContentCallback());
634   // Metadata should still work
635   google_apis::GDataErrorCode metadata_error = google_apis::GDATA_OTHER_ERROR;
636   scoped_ptr<google_apis::AboutResource> about_resource;
637
638   // Try to get the metadata
639   scheduler_->GetAboutResource(
640       google_apis::test_util::CreateCopyResultCallback(
641           &metadata_error, &about_resource));
642   base::RunLoop().RunUntilIdle();
643
644   // Check the metadata
645   ASSERT_EQ(google_apis::HTTP_SUCCESS, metadata_error);
646   ASSERT_TRUE(about_resource);
647
648   // Check the download
649   EXPECT_EQ(google_apis::GDATA_OTHER_ERROR, download_error);
650
651   // Switch to a Wifi connection
652   ConnectToWifi();
653
654   base::RunLoop().RunUntilIdle();
655
656   // Check the download again
657   EXPECT_EQ(google_apis::HTTP_SUCCESS, download_error);
658   std::string content;
659   EXPECT_EQ(output_file_path, kOutputFilePath);
660   ASSERT_TRUE(base::ReadFileToString(output_file_path, &content));
661   EXPECT_EQ("This is some test content.", content);
662 }
663
664 TEST_F(JobSchedulerTest, DownloadFileWimaxDisabled) {
665   ConnectToWimax();
666
667   // Disable fetching over cellular network.
668   pref_service_->SetBoolean(prefs::kDisableDriveOverCellular, true);
669
670   // Try to get a file in the background
671   base::ScopedTempDir temp_dir;
672   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
673
674   const base::FilePath kOutputFilePath =
675       temp_dir.path().AppendASCII("whatever.txt");
676   google_apis::GDataErrorCode download_error = google_apis::GDATA_OTHER_ERROR;
677   base::FilePath output_file_path;
678   scheduler_->DownloadFile(
679       base::FilePath::FromUTF8Unsafe("drive/whatever.txt"),  // virtual path
680       kDummyDownloadFileSize,
681       kOutputFilePath,
682       "file:2_file_resource_id",
683       ClientContext(BACKGROUND),
684       google_apis::test_util::CreateCopyResultCallback(
685           &download_error, &output_file_path),
686       google_apis::GetContentCallback());
687   // Metadata should still work
688   google_apis::GDataErrorCode metadata_error = google_apis::GDATA_OTHER_ERROR;
689   scoped_ptr<google_apis::AboutResource> about_resource;
690
691   // Try to get the metadata
692   scheduler_->GetAboutResource(
693       google_apis::test_util::CreateCopyResultCallback(
694           &metadata_error, &about_resource));
695   base::RunLoop().RunUntilIdle();
696
697   // Check the metadata
698   ASSERT_EQ(google_apis::HTTP_SUCCESS, metadata_error);
699   ASSERT_TRUE(about_resource);
700
701   // Check the download
702   EXPECT_EQ(google_apis::GDATA_OTHER_ERROR, download_error);
703
704   // Switch to a Wifi connection
705   ConnectToWifi();
706
707   base::RunLoop().RunUntilIdle();
708
709   // Check the download again
710   EXPECT_EQ(google_apis::HTTP_SUCCESS, download_error);
711   std::string content;
712   EXPECT_EQ(output_file_path, kOutputFilePath);
713   ASSERT_TRUE(base::ReadFileToString(output_file_path, &content));
714   EXPECT_EQ("This is some test content.", content);
715 }
716
717 TEST_F(JobSchedulerTest, DownloadFileCellularEnabled) {
718   ConnectToCellular();
719
720   // Enable fetching over cellular network.
721   pref_service_->SetBoolean(prefs::kDisableDriveOverCellular, false);
722
723   // Try to get a file in the background
724   base::ScopedTempDir temp_dir;
725   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
726
727   const base::FilePath kOutputFilePath =
728       temp_dir.path().AppendASCII("whatever.txt");
729   google_apis::GDataErrorCode download_error = google_apis::GDATA_OTHER_ERROR;
730   base::FilePath output_file_path;
731   scheduler_->DownloadFile(
732       base::FilePath::FromUTF8Unsafe("drive/whatever.txt"),  // virtual path
733       kDummyDownloadFileSize,
734       kOutputFilePath,
735       "file:2_file_resource_id",
736       ClientContext(BACKGROUND),
737       google_apis::test_util::CreateCopyResultCallback(
738           &download_error, &output_file_path),
739       google_apis::GetContentCallback());
740   // Metadata should still work
741   google_apis::GDataErrorCode metadata_error = google_apis::GDATA_OTHER_ERROR;
742   scoped_ptr<google_apis::AboutResource> about_resource;
743
744   // Try to get the metadata
745   scheduler_->GetAboutResource(
746       google_apis::test_util::CreateCopyResultCallback(
747           &metadata_error, &about_resource));
748   base::RunLoop().RunUntilIdle();
749
750   // Check the metadata
751   ASSERT_EQ(google_apis::HTTP_SUCCESS, metadata_error);
752   ASSERT_TRUE(about_resource);
753
754   // Check the download
755   EXPECT_EQ(google_apis::HTTP_SUCCESS, download_error);
756   std::string content;
757   EXPECT_EQ(output_file_path, kOutputFilePath);
758   ASSERT_TRUE(base::ReadFileToString(output_file_path, &content));
759   EXPECT_EQ("This is some test content.", content);
760 }
761
762 TEST_F(JobSchedulerTest, DownloadFileWimaxEnabled) {
763   ConnectToWimax();
764
765   // Enable fetching over cellular network.
766   pref_service_->SetBoolean(prefs::kDisableDriveOverCellular, false);
767
768   // Try to get a file in the background
769   base::ScopedTempDir temp_dir;
770   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
771
772   const base::FilePath kOutputFilePath =
773       temp_dir.path().AppendASCII("whatever.txt");
774   google_apis::GDataErrorCode download_error = google_apis::GDATA_OTHER_ERROR;
775   base::FilePath output_file_path;
776   scheduler_->DownloadFile(
777       base::FilePath::FromUTF8Unsafe("drive/whatever.txt"),  // virtual path
778       kDummyDownloadFileSize,
779       kOutputFilePath,
780       "file:2_file_resource_id",
781       ClientContext(BACKGROUND),
782       google_apis::test_util::CreateCopyResultCallback(
783           &download_error, &output_file_path),
784       google_apis::GetContentCallback());
785   // Metadata should still work
786   google_apis::GDataErrorCode metadata_error = google_apis::GDATA_OTHER_ERROR;
787   scoped_ptr<google_apis::AboutResource> about_resource;
788
789   // Try to get the metadata
790   scheduler_->GetAboutResource(
791       google_apis::test_util::CreateCopyResultCallback(
792           &metadata_error, &about_resource));
793   base::RunLoop().RunUntilIdle();
794
795   // Check the metadata
796   ASSERT_EQ(google_apis::HTTP_SUCCESS, metadata_error);
797   ASSERT_TRUE(about_resource);
798
799   // Check the download
800   EXPECT_EQ(google_apis::HTTP_SUCCESS, download_error);
801   std::string content;
802   EXPECT_EQ(output_file_path, kOutputFilePath);
803   ASSERT_TRUE(base::ReadFileToString(output_file_path, &content));
804   EXPECT_EQ("This is some test content.", content);
805 }
806
807 TEST_F(JobSchedulerTest, JobInfo) {
808   JobListLogger logger;
809   scheduler_->AddObserver(&logger);
810
811   // Disable background upload/download.
812   ConnectToWimax();
813   pref_service_->SetBoolean(prefs::kDisableDriveOverCellular, true);
814
815   base::ScopedTempDir temp_dir;
816   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
817
818   google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
819   scoped_ptr<google_apis::ResourceEntry> entry;
820   scoped_ptr<google_apis::AboutResource> about_resource;
821   base::FilePath path;
822
823   std::set<JobType> expected_types;
824
825   // Add many jobs.
826   expected_types.insert(TYPE_ADD_NEW_DIRECTORY);
827   scheduler_->AddNewDirectory(
828       fake_drive_service_->GetRootResourceId(),
829       "New Directory",
830       google_apis::test_util::CreateCopyResultCallback(&error, &entry));
831   expected_types.insert(TYPE_GET_ABOUT_RESOURCE);
832   scheduler_->GetAboutResource(
833       google_apis::test_util::CreateCopyResultCallback(
834           &error, &about_resource));
835   expected_types.insert(TYPE_RENAME_RESOURCE);
836   scheduler_->RenameResource(
837       "file:2_file_resource_id",
838       "New Title",
839       google_apis::test_util::CreateCopyResultCallback(&error));
840   expected_types.insert(TYPE_DOWNLOAD_FILE);
841   scheduler_->DownloadFile(
842       base::FilePath::FromUTF8Unsafe("drive/whatever.txt"),  // virtual path
843       kDummyDownloadFileSize,
844       temp_dir.path().AppendASCII("whatever.txt"),
845       "file:2_file_resource_id",
846       ClientContext(BACKGROUND),
847       google_apis::test_util::CreateCopyResultCallback(&error, &path),
848       google_apis::GetContentCallback());
849
850   // The number of jobs queued so far.
851   EXPECT_EQ(4U, scheduler_->GetJobInfoList().size());
852   EXPECT_TRUE(logger.Has(JobListLogger::ADDED, TYPE_ADD_NEW_DIRECTORY));
853   EXPECT_TRUE(logger.Has(JobListLogger::ADDED, TYPE_GET_ABOUT_RESOURCE));
854   EXPECT_TRUE(logger.Has(JobListLogger::ADDED, TYPE_RENAME_RESOURCE));
855   EXPECT_TRUE(logger.Has(JobListLogger::ADDED, TYPE_DOWNLOAD_FILE));
856   EXPECT_FALSE(logger.Has(JobListLogger::DONE, TYPE_ADD_NEW_DIRECTORY));
857   EXPECT_FALSE(logger.Has(JobListLogger::DONE, TYPE_GET_ABOUT_RESOURCE));
858   EXPECT_FALSE(logger.Has(JobListLogger::DONE, TYPE_RENAME_RESOURCE));
859   EXPECT_FALSE(logger.Has(JobListLogger::DONE, TYPE_DOWNLOAD_FILE));
860
861   // Add more jobs.
862   expected_types.insert(TYPE_ADD_RESOURCE_TO_DIRECTORY);
863   scheduler_->AddResourceToDirectory(
864       "folder:1_folder_resource_id",
865       "file:2_file_resource_id",
866       google_apis::test_util::CreateCopyResultCallback(&error));
867   expected_types.insert(TYPE_COPY_HOSTED_DOCUMENT);
868   scheduler_->CopyHostedDocument(
869       "document:5_document_resource_id",
870       "New Document",
871       google_apis::test_util::CreateCopyResultCallback(&error, &entry));
872
873   // 6 jobs in total were queued.
874   std::vector<JobInfo> jobs = scheduler_->GetJobInfoList();
875   EXPECT_EQ(6U, jobs.size());
876   std::set<JobType> actual_types;
877   std::set<JobID> job_ids;
878   for (size_t i = 0; i < jobs.size(); ++i) {
879     actual_types.insert(jobs[i].job_type);
880     job_ids.insert(jobs[i].job_id);
881   }
882   EXPECT_EQ(expected_types, actual_types);
883   EXPECT_EQ(6U, job_ids.size()) << "All job IDs must be unique";
884   EXPECT_TRUE(logger.Has(JobListLogger::ADDED, TYPE_ADD_RESOURCE_TO_DIRECTORY));
885   EXPECT_TRUE(logger.Has(JobListLogger::ADDED, TYPE_COPY_HOSTED_DOCUMENT));
886   EXPECT_FALSE(logger.Has(JobListLogger::DONE, TYPE_ADD_RESOURCE_TO_DIRECTORY));
887   EXPECT_FALSE(logger.Has(JobListLogger::DONE, TYPE_COPY_HOSTED_DOCUMENT));
888
889   // Run the jobs.
890   base::RunLoop().RunUntilIdle();
891
892   // All jobs except the BACKGROUND job should have started running (UPDATED)
893   // and then finished (DONE).
894   jobs = scheduler_->GetJobInfoList();
895   ASSERT_EQ(1U, jobs.size());
896   EXPECT_EQ(TYPE_DOWNLOAD_FILE, jobs[0].job_type);
897
898   EXPECT_TRUE(logger.Has(JobListLogger::UPDATED, TYPE_ADD_NEW_DIRECTORY));
899   EXPECT_TRUE(logger.Has(JobListLogger::UPDATED, TYPE_GET_ABOUT_RESOURCE));
900   EXPECT_TRUE(logger.Has(JobListLogger::UPDATED, TYPE_RENAME_RESOURCE));
901   EXPECT_TRUE(logger.Has(JobListLogger::UPDATED,
902                          TYPE_ADD_RESOURCE_TO_DIRECTORY));
903   EXPECT_TRUE(logger.Has(JobListLogger::UPDATED, TYPE_COPY_HOSTED_DOCUMENT));
904   EXPECT_FALSE(logger.Has(JobListLogger::UPDATED, TYPE_DOWNLOAD_FILE));
905
906   EXPECT_TRUE(logger.Has(JobListLogger::DONE, TYPE_ADD_NEW_DIRECTORY));
907   EXPECT_TRUE(logger.Has(JobListLogger::DONE, TYPE_GET_ABOUT_RESOURCE));
908   EXPECT_TRUE(logger.Has(JobListLogger::DONE, TYPE_RENAME_RESOURCE));
909   EXPECT_TRUE(logger.Has(JobListLogger::DONE, TYPE_ADD_RESOURCE_TO_DIRECTORY));
910   EXPECT_TRUE(logger.Has(JobListLogger::DONE, TYPE_COPY_HOSTED_DOCUMENT));
911   EXPECT_FALSE(logger.Has(JobListLogger::DONE, TYPE_DOWNLOAD_FILE));
912
913   // Run the background downloading job as well.
914   ConnectToWifi();
915   base::RunLoop().RunUntilIdle();
916
917   // All jobs should have finished.
918   EXPECT_EQ(0U, scheduler_->GetJobInfoList().size());
919   EXPECT_TRUE(logger.Has(JobListLogger::UPDATED, TYPE_DOWNLOAD_FILE));
920   EXPECT_TRUE(logger.Has(JobListLogger::DONE, TYPE_DOWNLOAD_FILE));
921 }
922
923 TEST_F(JobSchedulerTest, JobInfoProgress) {
924   JobListLogger logger;
925   scheduler_->AddObserver(&logger);
926
927   ConnectToWifi();
928
929   base::ScopedTempDir temp_dir;
930   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
931
932   google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
933   base::FilePath path;
934
935   // Download job.
936   scheduler_->DownloadFile(
937       base::FilePath::FromUTF8Unsafe("drive/whatever.txt"),  // virtual path
938       kDummyDownloadFileSize,
939       temp_dir.path().AppendASCII("whatever.txt"),
940       "file:2_file_resource_id",
941       ClientContext(BACKGROUND),
942       google_apis::test_util::CreateCopyResultCallback(&error, &path),
943       google_apis::GetContentCallback());
944   base::RunLoop().RunUntilIdle();
945
946   std::vector<int64> download_progress;
947   logger.GetProgressInfo(TYPE_DOWNLOAD_FILE, &download_progress);
948   ASSERT_TRUE(!download_progress.empty());
949   EXPECT_TRUE(base::STLIsSorted(download_progress));
950   EXPECT_GE(download_progress.front(), 0);
951   EXPECT_LE(download_progress.back(), 26);
952
953   // Upload job.
954   path = temp_dir.path().AppendASCII("new_file.txt");
955   ASSERT_TRUE(google_apis::test_util::WriteStringToFile(path, "Hello"));
956   google_apis::GDataErrorCode upload_error =
957       google_apis::GDATA_OTHER_ERROR;
958   scoped_ptr<google_apis::ResourceEntry> entry;
959
960   scheduler_->UploadNewFile(
961       fake_drive_service_->GetRootResourceId(),
962       base::FilePath::FromUTF8Unsafe("drive/new_file.txt"),
963       path,
964       "dummy title",
965       "plain/plain",
966       ClientContext(BACKGROUND),
967       google_apis::test_util::CreateCopyResultCallback(&upload_error, &entry));
968   base::RunLoop().RunUntilIdle();
969
970   std::vector<int64> upload_progress;
971   logger.GetProgressInfo(TYPE_UPLOAD_NEW_FILE, &upload_progress);
972   ASSERT_TRUE(!upload_progress.empty());
973   EXPECT_TRUE(base::STLIsSorted(upload_progress));
974   EXPECT_GE(upload_progress.front(), 0);
975   EXPECT_LE(upload_progress.back(), 13);
976 }
977
978 TEST_F(JobSchedulerTest, CancelPendingJob) {
979   base::ScopedTempDir temp_dir;
980   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
981   base::FilePath upload_path = temp_dir.path().AppendASCII("new_file.txt");
982   ASSERT_TRUE(google_apis::test_util::WriteStringToFile(upload_path, "Hello"));
983
984   // To create a pending job for testing, set the mode to cellular connection
985   // and issue BACKGROUND jobs.
986   ConnectToCellular();
987   pref_service_->SetBoolean(prefs::kDisableDriveOverCellular, true);
988
989   // Start the first job and record its job ID.
990   google_apis::GDataErrorCode error1 = google_apis::GDATA_OTHER_ERROR;
991   scoped_ptr<google_apis::ResourceEntry> entry;
992   scheduler_->UploadNewFile(
993       fake_drive_service_->GetRootResourceId(),
994       base::FilePath::FromUTF8Unsafe("dummy/path"),
995       upload_path,
996       "dummy title 1",
997       "text/plain",
998       ClientContext(BACKGROUND),
999       google_apis::test_util::CreateCopyResultCallback(&error1, &entry));
1000
1001   const std::vector<JobInfo>& jobs = scheduler_->GetJobInfoList();
1002   ASSERT_EQ(1u, jobs.size());
1003   ASSERT_EQ(STATE_NONE, jobs[0].state);  // Not started yet.
1004   JobID first_job_id = jobs[0].job_id;
1005
1006   // Start the second job.
1007   google_apis::GDataErrorCode error2 = google_apis::GDATA_OTHER_ERROR;
1008   scheduler_->UploadNewFile(
1009       fake_drive_service_->GetRootResourceId(),
1010       base::FilePath::FromUTF8Unsafe("dummy/path"),
1011       upload_path,
1012       "dummy title 2",
1013       "text/plain",
1014       ClientContext(BACKGROUND),
1015       google_apis::test_util::CreateCopyResultCallback(&error2, &entry));
1016
1017   // Cancel the first one.
1018   scheduler_->CancelJob(first_job_id);
1019
1020   // Only the first job should be cancelled.
1021   ConnectToWifi();
1022   base::RunLoop().RunUntilIdle();
1023   EXPECT_EQ(google_apis::GDATA_CANCELLED, error1);
1024   EXPECT_EQ(google_apis::HTTP_SUCCESS, error2);
1025   EXPECT_TRUE(scheduler_->GetJobInfoList().empty());
1026 }
1027
1028 TEST_F(JobSchedulerTest, CancelRunningJob) {
1029   ConnectToWifi();
1030
1031   base::ScopedTempDir temp_dir;
1032   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
1033   base::FilePath upload_path = temp_dir.path().AppendASCII("new_file.txt");
1034   ASSERT_TRUE(google_apis::test_util::WriteStringToFile(upload_path, "Hello"));
1035
1036   // Run as a cancelable task.
1037   fake_drive_service_->set_upload_new_file_cancelable(true);
1038   google_apis::GDataErrorCode error1 = google_apis::GDATA_OTHER_ERROR;
1039   scoped_ptr<google_apis::ResourceEntry> entry;
1040   scheduler_->UploadNewFile(
1041       fake_drive_service_->GetRootResourceId(),
1042       base::FilePath::FromUTF8Unsafe("dummy/path"),
1043       upload_path,
1044       "dummy title 1",
1045       "text/plain",
1046       ClientContext(USER_INITIATED),
1047       google_apis::test_util::CreateCopyResultCallback(&error1, &entry));
1048
1049   const std::vector<JobInfo>& jobs = scheduler_->GetJobInfoList();
1050   ASSERT_EQ(1u, jobs.size());
1051   ASSERT_EQ(STATE_RUNNING, jobs[0].state);  // It's running.
1052   JobID first_job_id = jobs[0].job_id;
1053
1054   // Start the second job normally.
1055   fake_drive_service_->set_upload_new_file_cancelable(false);
1056   google_apis::GDataErrorCode error2 = google_apis::GDATA_OTHER_ERROR;
1057   scheduler_->UploadNewFile(
1058       fake_drive_service_->GetRootResourceId(),
1059       base::FilePath::FromUTF8Unsafe("dummy/path"),
1060       upload_path,
1061       "dummy title 2",
1062       "text/plain",
1063       ClientContext(USER_INITIATED),
1064       google_apis::test_util::CreateCopyResultCallback(&error2, &entry));
1065
1066   // Cancel the first one.
1067   scheduler_->CancelJob(first_job_id);
1068
1069   // Only the first job should be cancelled.
1070   base::RunLoop().RunUntilIdle();
1071   EXPECT_EQ(google_apis::GDATA_CANCELLED, error1);
1072   EXPECT_EQ(google_apis::HTTP_SUCCESS, error2);
1073   EXPECT_TRUE(scheduler_->GetJobInfoList().empty());
1074 }
1075
1076 }  // namespace drive