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