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