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