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