8f573b5261d1221cfbb34279d8b7c34e1499803f
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / drive / file_system_unittest.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/chromeos/drive/file_system.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "base/bind.h"
11 #include "base/file_util.h"
12 #include "base/files/file_path.h"
13 #include "base/files/scoped_temp_dir.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/message_loop/message_loop_proxy.h"
16 #include "base/prefs/testing_pref_service.h"
17 #include "base/run_loop.h"
18 #include "chrome/browser/chromeos/drive/change_list_loader.h"
19 #include "chrome/browser/chromeos/drive/drive.pb.h"
20 #include "chrome/browser/chromeos/drive/fake_free_disk_space_getter.h"
21 #include "chrome/browser/chromeos/drive/file_system_observer.h"
22 #include "chrome/browser/chromeos/drive/file_system_util.h"
23 #include "chrome/browser/chromeos/drive/job_scheduler.h"
24 #include "chrome/browser/chromeos/drive/sync_client.h"
25 #include "chrome/browser/chromeos/drive/test_util.h"
26 #include "chrome/browser/drive/drive_api_util.h"
27 #include "chrome/browser/drive/event_logger.h"
28 #include "chrome/browser/drive/fake_drive_service.h"
29 #include "content/public/test/test_browser_thread_bundle.h"
30 #include "google_apis/drive/drive_api_parser.h"
31 #include "google_apis/drive/test_util.h"
32 #include "testing/gtest/include/gtest/gtest.h"
33
34 namespace drive {
35 namespace {
36
37 // Counts the number of invocation, and if it increased up to |expected_counter|
38 // quits the current message loop by calling |quit|.
39 void AsyncInitializationCallback(
40     int* counter, int expected_counter, const base::Closure& quit,
41     FileError error, scoped_ptr<ResourceEntry> entry) {
42   if (error != FILE_ERROR_OK || !entry) {
43     // If we hit an error case, quit the message loop immediately.
44     // Then the expectation in the test case can find it because the actual
45     // value of |counter| is different from the expected one.
46     quit.Run();
47     return;
48   }
49
50   (*counter)++;
51   if (*counter >= expected_counter)
52     quit.Run();
53 }
54
55 // This class is used to record directory changes and examine them later.
56 class MockDirectoryChangeObserver : public FileSystemObserver {
57  public:
58   MockDirectoryChangeObserver() {}
59   virtual ~MockDirectoryChangeObserver() {}
60
61   // FileSystemObserver overrides.
62   virtual void OnDirectoryChanged(
63       const base::FilePath& directory_path) OVERRIDE {
64     changed_directories_.push_back(directory_path);
65   }
66
67   const std::vector<base::FilePath>& changed_directories() const {
68     return changed_directories_;
69   }
70
71  private:
72   std::vector<base::FilePath> changed_directories_;
73   DISALLOW_COPY_AND_ASSIGN(MockDirectoryChangeObserver);
74 };
75
76 }  // namespace
77
78 class FileSystemTest : public testing::Test {
79  protected:
80   virtual void SetUp() OVERRIDE {
81     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
82     pref_service_.reset(new TestingPrefServiceSimple);
83     test_util::RegisterDrivePrefs(pref_service_->registry());
84
85     logger_.reset(new EventLogger);
86     fake_drive_service_.reset(new FakeDriveService);
87     fake_drive_service_->LoadResourceListForWapi(
88         "gdata/root_feed.json");
89     fake_drive_service_->LoadAccountMetadataForWapi(
90         "gdata/account_metadata.json");
91
92     fake_free_disk_space_getter_.reset(new FakeFreeDiskSpaceGetter);
93
94     scheduler_.reset(new JobScheduler(pref_service_.get(),
95                                       logger_.get(),
96                                       fake_drive_service_.get(),
97                                       base::MessageLoopProxy::current().get()));
98
99     mock_directory_observer_.reset(new MockDirectoryChangeObserver);
100
101     SetUpResourceMetadataAndFileSystem();
102   }
103
104   void SetUpResourceMetadataAndFileSystem() {
105     const base::FilePath metadata_dir = temp_dir_.path().AppendASCII("meta");
106     ASSERT_TRUE(base::CreateDirectory(metadata_dir));
107     metadata_storage_.reset(new internal::ResourceMetadataStorage(
108         metadata_dir, base::MessageLoopProxy::current().get()));
109     ASSERT_TRUE(metadata_storage_->Initialize());
110
111     const base::FilePath cache_dir = temp_dir_.path().AppendASCII("files");
112     ASSERT_TRUE(base::CreateDirectory(cache_dir));
113     cache_.reset(new internal::FileCache(
114         metadata_storage_.get(),
115         cache_dir,
116         base::MessageLoopProxy::current().get(),
117         fake_free_disk_space_getter_.get()));
118     ASSERT_TRUE(cache_->Initialize());
119
120     resource_metadata_.reset(new internal::ResourceMetadata(
121         metadata_storage_.get(), base::MessageLoopProxy::current()));
122     ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->Initialize());
123
124     const base::FilePath temp_file_dir = temp_dir_.path().AppendASCII("tmp");
125     ASSERT_TRUE(base::CreateDirectory(temp_file_dir));
126     file_system_.reset(new FileSystem(
127         pref_service_.get(),
128         logger_.get(),
129         cache_.get(),
130         fake_drive_service_.get(),
131         scheduler_.get(),
132         resource_metadata_.get(),
133         base::MessageLoopProxy::current().get(),
134         temp_file_dir));
135     file_system_->AddObserver(mock_directory_observer_.get());
136
137     // Disable delaying so that the sync starts immediately.
138     file_system_->sync_client_for_testing()->set_delay_for_testing(
139         base::TimeDelta::FromSeconds(0));
140   }
141
142   // Loads the full resource list via FakeDriveService.
143   bool LoadFullResourceList() {
144     FileError error = FILE_ERROR_FAILED;
145     file_system_->change_list_loader_for_testing()->LoadIfNeeded(
146         google_apis::test_util::CreateCopyResultCallback(&error));
147     test_util::RunBlockingPoolTask();
148     return error == FILE_ERROR_OK;
149   }
150
151   // Gets resource entry by path synchronously.
152   scoped_ptr<ResourceEntry> GetResourceEntrySync(
153       const base::FilePath& file_path) {
154     FileError error = FILE_ERROR_FAILED;
155     scoped_ptr<ResourceEntry> entry;
156     file_system_->GetResourceEntry(
157         file_path,
158         google_apis::test_util::CreateCopyResultCallback(&error, &entry));
159     test_util::RunBlockingPoolTask();
160
161     return entry.Pass();
162   }
163
164   // Gets directory info by path synchronously.
165   scoped_ptr<ResourceEntryVector> ReadDirectorySync(
166       const base::FilePath& file_path) {
167     FileError error = FILE_ERROR_FAILED;
168     scoped_ptr<ResourceEntryVector> entries(new ResourceEntryVector);
169     bool last_has_more = true;
170     file_system_->ReadDirectory(
171         file_path,
172         base::Bind(&AccumulateReadDirectoryResult,
173                    &error, entries.get(), &last_has_more));
174     test_util::RunBlockingPoolTask();
175     if (error != FILE_ERROR_OK)
176       entries.reset();
177     return entries.Pass();
178   }
179
180   // Used to implement ReadDirectorySync().
181   static void AccumulateReadDirectoryResult(
182       FileError* out_error,
183       ResourceEntryVector* out_entries,
184       bool* last_has_more,
185       FileError error,
186       scoped_ptr<ResourceEntryVector> entries,
187       bool has_more) {
188     EXPECT_TRUE(*last_has_more);
189     *out_error = error;
190     *last_has_more = has_more;
191     if (error == FILE_ERROR_OK) {
192       ASSERT_TRUE(entries);
193       out_entries->insert(out_entries->end(), entries->begin(), entries->end());
194     } else {
195       EXPECT_FALSE(has_more);
196     }
197   }
198
199   // Returns true if an entry exists at |file_path|.
200   bool EntryExists(const base::FilePath& file_path) {
201     return GetResourceEntrySync(file_path);
202   }
203
204   // Flag for specifying the timestamp of the test filesystem cache.
205   enum SetUpTestFileSystemParam {
206     USE_OLD_TIMESTAMP,
207     USE_SERVER_TIMESTAMP,
208   };
209
210   // Sets up a filesystem with directories: drive/root, drive/root/Dir1,
211   // drive/root/Dir1/SubDir2 and files drive/root/File1, drive/root/Dir1/File2,
212   // drive/root/Dir1/SubDir2/File3. If |use_up_to_date_timestamp| is true, sets
213   // the changestamp to 654321, equal to that of "account_metadata.json" test
214   // data, indicating the cache is holding the latest file system info.
215   void SetUpTestFileSystem(SetUpTestFileSystemParam param) {
216     // Destroy the existing resource metadata to close DB.
217     resource_metadata_.reset();
218
219     const base::FilePath metadata_dir = temp_dir_.path().AppendASCII("meta");
220     ASSERT_TRUE(base::CreateDirectory(metadata_dir));
221     scoped_ptr<internal::ResourceMetadataStorage,
222                test_util::DestroyHelperForTests> metadata_storage(
223         new internal::ResourceMetadataStorage(
224             metadata_dir, base::MessageLoopProxy::current().get()));
225
226     scoped_ptr<internal::ResourceMetadata, test_util::DestroyHelperForTests>
227         resource_metadata(new internal::ResourceMetadata(
228             metadata_storage_.get(), base::MessageLoopProxy::current()));
229
230     ASSERT_EQ(FILE_ERROR_OK, resource_metadata->Initialize());
231
232     const int64 changestamp = param == USE_SERVER_TIMESTAMP ? 654321 : 1;
233     ASSERT_EQ(FILE_ERROR_OK,
234               resource_metadata->SetLargestChangestamp(changestamp));
235
236     // drive/root
237     ResourceEntry root;
238     ASSERT_EQ(FILE_ERROR_OK, resource_metadata->GetResourceEntryByPath(
239         util::GetDriveMyDriveRootPath(), &root));
240     root.set_resource_id(fake_drive_service_->GetRootResourceId());
241     ASSERT_EQ(FILE_ERROR_OK, resource_metadata->RefreshEntry(root));
242
243     std::string local_id;
244
245     // drive/root/File1
246     ResourceEntry file1;
247     file1.set_title("File1");
248     file1.set_resource_id("resource_id:File1");
249     file1.set_parent_local_id(root.local_id());
250     file1.mutable_file_specific_info()->set_md5("md5");
251     file1.mutable_file_info()->set_is_directory(false);
252     file1.mutable_file_info()->set_size(1048576);
253     ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(file1, &local_id));
254
255     // drive/root/Dir1
256     ResourceEntry dir1;
257     dir1.set_title("Dir1");
258     dir1.set_resource_id("resource_id:Dir1");
259     dir1.set_parent_local_id(root.local_id());
260     dir1.mutable_file_info()->set_is_directory(true);
261     ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(dir1, &local_id));
262     const std::string dir1_local_id = local_id;
263
264     // drive/root/Dir1/File2
265     ResourceEntry file2;
266     file2.set_title("File2");
267     file2.set_resource_id("resource_id:File2");
268     file2.set_parent_local_id(dir1_local_id);
269     file2.mutable_file_specific_info()->set_md5("md5");
270     file2.mutable_file_info()->set_is_directory(false);
271     file2.mutable_file_info()->set_size(555);
272     ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(file2, &local_id));
273
274     // drive/root/Dir1/SubDir2
275     ResourceEntry dir2;
276     dir2.set_title("SubDir2");
277     dir2.set_resource_id("resource_id:SubDir2");
278     dir2.set_parent_local_id(dir1_local_id);
279     dir2.mutable_file_info()->set_is_directory(true);
280     ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(dir2, &local_id));
281     const std::string dir2_local_id = local_id;
282
283     // drive/root/Dir1/SubDir2/File3
284     ResourceEntry file3;
285     file3.set_title("File3");
286     file3.set_resource_id("resource_id:File3");
287     file3.set_parent_local_id(dir2_local_id);
288     file3.mutable_file_specific_info()->set_md5("md5");
289     file3.mutable_file_info()->set_is_directory(false);
290     file3.mutable_file_info()->set_size(12345);
291     ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(file3, &local_id));
292
293     // Recreate resource metadata.
294     SetUpResourceMetadataAndFileSystem();
295   }
296
297   content::TestBrowserThreadBundle thread_bundle_;
298   base::ScopedTempDir temp_dir_;
299   // We don't use TestingProfile::GetPrefs() in favor of having less
300   // dependencies to Profile in general.
301   scoped_ptr<TestingPrefServiceSimple> pref_service_;
302
303   scoped_ptr<EventLogger> logger_;
304   scoped_ptr<FakeDriveService> fake_drive_service_;
305   scoped_ptr<FakeFreeDiskSpaceGetter> fake_free_disk_space_getter_;
306   scoped_ptr<JobScheduler> scheduler_;
307   scoped_ptr<MockDirectoryChangeObserver> mock_directory_observer_;
308
309   scoped_ptr<internal::ResourceMetadataStorage,
310              test_util::DestroyHelperForTests> metadata_storage_;
311   scoped_ptr<internal::FileCache, test_util::DestroyHelperForTests> cache_;
312   scoped_ptr<internal::ResourceMetadata, test_util::DestroyHelperForTests>
313       resource_metadata_;
314   scoped_ptr<FileSystem> file_system_;
315 };
316
317 TEST_F(FileSystemTest, Copy) {
318   base::FilePath src_file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
319   base::FilePath dest_file_path(FILE_PATH_LITERAL("drive/root/Copied.txt"));
320   EXPECT_TRUE(GetResourceEntrySync(src_file_path));
321   EXPECT_FALSE(GetResourceEntrySync(dest_file_path));
322
323   FileError error = FILE_ERROR_FAILED;
324   file_system_->Copy(src_file_path,
325                      dest_file_path,
326                      false,  // preserve_last_modified,
327                      google_apis::test_util::CreateCopyResultCallback(&error));
328   test_util::RunBlockingPoolTask();
329   EXPECT_EQ(FILE_ERROR_OK, error);
330
331   // Entry is added on the server.
332   scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(dest_file_path);
333   ASSERT_TRUE(entry);
334
335   google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR;
336   scoped_ptr<google_apis::ResourceEntry> resource_entry;
337   fake_drive_service_->GetResourceEntry(
338       entry->resource_id(),
339       google_apis::test_util::CreateCopyResultCallback(&status,
340                                                        &resource_entry));
341   test_util::RunBlockingPoolTask();
342   EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
343   ASSERT_TRUE(resource_entry);
344   EXPECT_EQ(entry->title(), resource_entry->title());
345   EXPECT_TRUE(resource_entry->is_file());
346 }
347
348 TEST_F(FileSystemTest, Move) {
349   base::FilePath src_file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
350   base::FilePath dest_file_path(
351       FILE_PATH_LITERAL("drive/root/Directory 1/Moved.txt"));
352   EXPECT_TRUE(GetResourceEntrySync(src_file_path));
353   EXPECT_FALSE(GetResourceEntrySync(dest_file_path));
354   scoped_ptr<ResourceEntry> parent =
355       GetResourceEntrySync(dest_file_path.DirName());
356   ASSERT_TRUE(parent);
357
358   FileError error = FILE_ERROR_FAILED;
359   file_system_->Move(src_file_path,
360                      dest_file_path,
361                      google_apis::test_util::CreateCopyResultCallback(&error));
362   test_util::RunBlockingPoolTask();
363   EXPECT_EQ(FILE_ERROR_OK, error);
364
365   // Entry is moved on the server.
366   scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(dest_file_path);
367   ASSERT_TRUE(entry);
368
369   google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR;
370   scoped_ptr<google_apis::ResourceEntry> resource_entry;
371   fake_drive_service_->GetResourceEntry(
372       entry->resource_id(),
373       google_apis::test_util::CreateCopyResultCallback(&status,
374                                                        &resource_entry));
375   test_util::RunBlockingPoolTask();
376   EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
377   ASSERT_TRUE(resource_entry);
378   EXPECT_EQ(entry->title(), resource_entry->title());
379
380   const google_apis::Link* parent_link =
381       resource_entry->GetLinkByType(google_apis::Link::LINK_PARENT);
382   ASSERT_TRUE(parent_link);
383   EXPECT_EQ(parent->resource_id(),
384             util::ExtractResourceIdFromUrl(parent_link->href()));
385 }
386
387 TEST_F(FileSystemTest, Remove) {
388   base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
389   scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(file_path);
390   ASSERT_TRUE(entry);
391
392   FileError error = FILE_ERROR_FAILED;
393   file_system_->Remove(
394       file_path,
395       false,  // is_resursive
396       google_apis::test_util::CreateCopyResultCallback(&error));
397   test_util::RunBlockingPoolTask();
398   EXPECT_EQ(FILE_ERROR_OK, error);
399
400   // Entry is removed on the server.
401   google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR;
402   scoped_ptr<google_apis::ResourceEntry> resource_entry;
403   fake_drive_service_->GetResourceEntry(
404       entry->resource_id(),
405       google_apis::test_util::CreateCopyResultCallback(&status,
406                                                        &resource_entry));
407   test_util::RunBlockingPoolTask();
408   EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
409   ASSERT_TRUE(resource_entry);
410   EXPECT_TRUE(resource_entry->deleted());
411 }
412
413 TEST_F(FileSystemTest, CreateDirectory) {
414   base::FilePath directory_path(FILE_PATH_LITERAL("drive/root/New Directory"));
415   EXPECT_FALSE(GetResourceEntrySync(directory_path));
416
417   FileError error = FILE_ERROR_FAILED;
418   file_system_->CreateDirectory(
419       directory_path,
420       true,  // is_exclusive
421       false,  // is_recursive
422       google_apis::test_util::CreateCopyResultCallback(&error));
423   test_util::RunBlockingPoolTask();
424   EXPECT_EQ(FILE_ERROR_OK, error);
425
426   // Directory is created on the server.
427   scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(directory_path);
428   ASSERT_TRUE(entry);
429
430   google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR;
431   scoped_ptr<google_apis::ResourceEntry> resource_entry;
432   fake_drive_service_->GetResourceEntry(
433       entry->resource_id(),
434       google_apis::test_util::CreateCopyResultCallback(&status,
435                                                        &resource_entry));
436   test_util::RunBlockingPoolTask();
437   EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
438   ASSERT_TRUE(resource_entry);
439   EXPECT_EQ(entry->title(), resource_entry->title());
440   EXPECT_TRUE(resource_entry->is_folder());
441 }
442
443 TEST_F(FileSystemTest, CreateFile) {
444   base::FilePath file_path(FILE_PATH_LITERAL("drive/root/New File.txt"));
445   EXPECT_FALSE(GetResourceEntrySync(file_path));
446
447   FileError error = FILE_ERROR_FAILED;
448   file_system_->CreateFile(
449       file_path,
450       true,  // is_exclusive
451       "text/plain",
452       google_apis::test_util::CreateCopyResultCallback(&error));
453   test_util::RunBlockingPoolTask();
454   EXPECT_EQ(FILE_ERROR_OK, error);
455
456   // File is created on the server.
457   scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(file_path);
458   ASSERT_TRUE(entry);
459
460   google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR;
461   scoped_ptr<google_apis::ResourceEntry> resource_entry;
462   fake_drive_service_->GetResourceEntry(
463       entry->resource_id(),
464       google_apis::test_util::CreateCopyResultCallback(&status,
465                                                        &resource_entry));
466   test_util::RunBlockingPoolTask();
467   EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
468   ASSERT_TRUE(resource_entry);
469   EXPECT_EQ(entry->title(), resource_entry->title());
470   EXPECT_TRUE(resource_entry->is_file());
471 }
472
473 TEST_F(FileSystemTest, TouchFile) {
474   base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
475   scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(file_path);
476   ASSERT_TRUE(entry);
477
478   base::Time last_accessed =
479       base::Time::FromInternalValue(entry->file_info().last_accessed()) +
480       base::TimeDelta::FromSeconds(1);
481   base::Time last_modified =
482       base::Time::FromInternalValue(entry->file_info().last_modified()) +
483       base::TimeDelta::FromSeconds(1);
484
485   FileError error = FILE_ERROR_FAILED;
486   file_system_->TouchFile(
487       file_path,
488       last_accessed,
489       last_modified,
490       google_apis::test_util::CreateCopyResultCallback(&error));
491   test_util::RunBlockingPoolTask();
492   EXPECT_EQ(FILE_ERROR_OK, error);
493
494   // File is touched on the server.
495   google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR;
496   scoped_ptr<google_apis::ResourceEntry> resource_entry;
497   fake_drive_service_->GetResourceEntry(
498       entry->resource_id(),
499       google_apis::test_util::CreateCopyResultCallback(&status,
500                                                        &resource_entry));
501   test_util::RunBlockingPoolTask();
502   EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
503   ASSERT_TRUE(resource_entry);
504   EXPECT_EQ(last_accessed, resource_entry->last_viewed_time());
505   EXPECT_EQ(last_modified, resource_entry->updated_time());
506 }
507
508 TEST_F(FileSystemTest, TruncateFile) {
509   base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
510   scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(file_path);
511   ASSERT_TRUE(entry);
512
513   const int64 kLength = entry->file_info().size() + 100;
514
515   FileError error = FILE_ERROR_FAILED;
516   file_system_->TruncateFile(
517       file_path,
518       kLength,
519       google_apis::test_util::CreateCopyResultCallback(&error));
520   test_util::RunBlockingPoolTask();
521   EXPECT_EQ(FILE_ERROR_OK, error);
522
523   // File is touched on the server.
524   google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR;
525   scoped_ptr<google_apis::ResourceEntry> resource_entry;
526   fake_drive_service_->GetResourceEntry(
527       entry->resource_id(),
528       google_apis::test_util::CreateCopyResultCallback(&status,
529                                                        &resource_entry));
530   test_util::RunBlockingPoolTask();
531   EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
532   ASSERT_TRUE(resource_entry);
533   EXPECT_EQ(kLength, resource_entry->file_size());
534 }
535
536 TEST_F(FileSystemTest, DuplicatedAsyncInitialization) {
537   base::RunLoop loop;
538
539   int counter = 0;
540   const GetResourceEntryCallback& callback = base::Bind(
541       &AsyncInitializationCallback, &counter, 2, loop.QuitClosure());
542
543   file_system_->GetResourceEntry(
544       base::FilePath(FILE_PATH_LITERAL("drive/root")), callback);
545   file_system_->GetResourceEntry(
546       base::FilePath(FILE_PATH_LITERAL("drive/root")), callback);
547   loop.Run();  // Wait to get our result
548   EXPECT_EQ(2, counter);
549
550   EXPECT_EQ(1, fake_drive_service_->resource_list_load_count());
551 }
552
553 TEST_F(FileSystemTest, GetGrandRootEntry) {
554   const base::FilePath kFilePath(FILE_PATH_LITERAL("drive"));
555   scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
556   ASSERT_TRUE(entry);
557   EXPECT_EQ(util::kDriveGrandRootLocalId, entry->local_id());
558 }
559
560 TEST_F(FileSystemTest, GetOtherDirEntry) {
561   const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/other"));
562   scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
563   ASSERT_TRUE(entry);
564   EXPECT_EQ(util::kDriveOtherDirLocalId, entry->local_id());
565 }
566
567 TEST_F(FileSystemTest, GetMyDriveRoot) {
568   const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root"));
569   scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
570   ASSERT_TRUE(entry);
571   EXPECT_EQ(fake_drive_service_->GetRootResourceId(), entry->resource_id());
572
573   // After "fast fetch" is done, full resource list is fetched.
574   EXPECT_EQ(1, fake_drive_service_->resource_list_load_count());
575 }
576
577 TEST_F(FileSystemTest, GetExistingFile) {
578   // Simulate the situation that full feed fetching takes very long time,
579   // to test the recursive "fast fetch" feature is properly working.
580   fake_drive_service_->set_never_return_all_resource_list(true);
581
582   const base::FilePath kFilePath(
583       FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt"));
584   scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
585   ASSERT_TRUE(entry);
586   EXPECT_EQ("file:subdirectory_file_1_id", entry->resource_id());
587
588   EXPECT_EQ(1, fake_drive_service_->about_resource_load_count());
589   EXPECT_EQ(2, fake_drive_service_->directory_load_count());
590   EXPECT_EQ(1, fake_drive_service_->blocked_resource_list_load_count());
591 }
592
593 TEST_F(FileSystemTest, GetExistingDocument) {
594   const base::FilePath kFilePath(
595       FILE_PATH_LITERAL("drive/root/Document 1 excludeDir-test.gdoc"));
596   scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
597   ASSERT_TRUE(entry);
598   EXPECT_EQ("document:5_document_resource_id", entry->resource_id());
599 }
600
601 TEST_F(FileSystemTest, GetNonExistingFile) {
602   const base::FilePath kFilePath(
603       FILE_PATH_LITERAL("drive/root/nonexisting.file"));
604   scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
605   EXPECT_FALSE(entry);
606 }
607
608 TEST_F(FileSystemTest, GetInSubSubdir) {
609   const base::FilePath kFilePath(
610       FILE_PATH_LITERAL("drive/root/Directory 1/Sub Directory Folder/"
611                         "Sub Sub Directory Folder"));
612   scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
613   ASSERT_TRUE(entry);
614   ASSERT_EQ("folder:sub_sub_directory_folder_id", entry->resource_id());
615 }
616
617 TEST_F(FileSystemTest, GetOrphanFile) {
618   ASSERT_TRUE(LoadFullResourceList());
619
620   // Entry without parents are placed under "drive/other".
621   const base::FilePath kFilePath(
622       FILE_PATH_LITERAL("drive/other/Orphan File 1.txt"));
623   scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
624   ASSERT_TRUE(entry);
625   EXPECT_EQ("file:1_orphanfile_resource_id", entry->resource_id());
626 }
627
628 TEST_F(FileSystemTest, ReadDirectory_Root) {
629   // ReadDirectory() should kick off the resource list loading.
630   scoped_ptr<ResourceEntryVector> entries(
631       ReadDirectorySync(base::FilePath::FromUTF8Unsafe("drive")));
632   // The root directory should be read correctly.
633   ASSERT_TRUE(entries);
634   ASSERT_EQ(3U, entries->size());
635
636   // The found three directories should be /drive/root, /drive/other and
637   // /drive/trash.
638   std::set<base::FilePath> found;
639   for (size_t i = 0; i < entries->size(); ++i)
640     found.insert(base::FilePath::FromUTF8Unsafe((*entries)[i].title()));
641   EXPECT_EQ(3U, found.size());
642   EXPECT_EQ(1U, found.count(base::FilePath(util::kDriveMyDriveRootDirName)));
643   EXPECT_EQ(1U, found.count(base::FilePath(util::kDriveOtherDirName)));
644   EXPECT_EQ(1U, found.count(base::FilePath(util::kDriveTrashDirName)));
645 }
646
647 TEST_F(FileSystemTest, ReadDirectory_NonRootDirectory) {
648   // ReadDirectory() should kick off the resource list loading.
649   scoped_ptr<ResourceEntryVector> entries(
650       ReadDirectorySync(
651           base::FilePath::FromUTF8Unsafe("drive/root/Directory 1")));
652   // The non root directory should also be read correctly.
653   // There was a bug (crbug.com/181487), which broke this behavior.
654   // Make sure this is fixed.
655   ASSERT_TRUE(entries);
656   EXPECT_EQ(3U, entries->size());
657 }
658
659 TEST_F(FileSystemTest, LoadFileSystemFromUpToDateCache) {
660   ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_SERVER_TIMESTAMP));
661
662   // Kicks loading of cached file system and query for server update.
663   EXPECT_TRUE(ReadDirectorySync(util::GetDriveMyDriveRootPath()));
664
665   // SetUpTestFileSystem and "account_metadata.json" have the same
666   // changestamp (i.e. the local metadata is up-to-date), so no request for
667   // new resource list (i.e., call to GetResourceList) should happen.
668   EXPECT_EQ(0, fake_drive_service_->resource_list_load_count());
669
670   // Since the file system has verified that it holds the latest snapshot,
671   // it should change its state to "loaded", which admits periodic refresh.
672   // To test it, call CheckForUpdates and verify it does try to check updates.
673   const int about_resource_load_count_before =
674       fake_drive_service_->about_resource_load_count();
675   file_system_->CheckForUpdates();
676   test_util::RunBlockingPoolTask();
677   EXPECT_LT(about_resource_load_count_before,
678             fake_drive_service_->about_resource_load_count());
679 }
680
681 TEST_F(FileSystemTest, LoadFileSystemFromCacheWhileOffline) {
682   ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_OLD_TIMESTAMP));
683
684   // Make GetResourceList fail for simulating offline situation. This will
685   // leave the file system "loaded from cache, but not synced with server"
686   // state.
687   fake_drive_service_->set_offline(true);
688
689   // Load the root.
690   EXPECT_TRUE(ReadDirectorySync(util::GetDriveGrandRootPath()));
691   // Loading of about resource should not happen as it's offline.
692   EXPECT_EQ(0, fake_drive_service_->about_resource_load_count());
693
694   // Load "My Drive".
695   EXPECT_TRUE(ReadDirectorySync(util::GetDriveMyDriveRootPath()));
696   EXPECT_EQ(0, fake_drive_service_->about_resource_load_count());
697
698   // Tests that cached data can be loaded even if the server is not reachable.
699   EXPECT_TRUE(EntryExists(base::FilePath(
700       FILE_PATH_LITERAL("drive/root/File1"))));
701   EXPECT_TRUE(EntryExists(base::FilePath(
702       FILE_PATH_LITERAL("drive/root/Dir1"))));
703   EXPECT_TRUE(EntryExists(base::FilePath(
704       FILE_PATH_LITERAL("drive/root/Dir1/File2"))));
705   EXPECT_TRUE(EntryExists(base::FilePath(
706       FILE_PATH_LITERAL("drive/root/Dir1/SubDir2"))));
707   EXPECT_TRUE(EntryExists(base::FilePath(
708       FILE_PATH_LITERAL("drive/root/Dir1/SubDir2/File3"))));
709
710   // Since the file system has at least succeeded to load cached snapshot,
711   // the file system should be able to start periodic refresh.
712   // To test it, call CheckForUpdates and verify it does try to check
713   // updates, which will cause directory changes.
714   fake_drive_service_->set_offline(false);
715
716   file_system_->CheckForUpdates();
717
718   test_util::RunBlockingPoolTask();
719   EXPECT_EQ(1, fake_drive_service_->about_resource_load_count());
720   EXPECT_EQ(1, fake_drive_service_->change_list_load_count());
721
722   ASSERT_LE(1u, mock_directory_observer_->changed_directories().size());
723 }
724
725 TEST_F(FileSystemTest, ReadDirectoryWhileRefreshing) {
726   // Use old timestamp so the fast fetch will be performed.
727   ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_OLD_TIMESTAMP));
728
729   // The list of resources in "drive/root/Dir1" should be fetched.
730   EXPECT_TRUE(ReadDirectorySync(base::FilePath(
731       FILE_PATH_LITERAL("drive/root/Dir1"))));
732   EXPECT_EQ(1, fake_drive_service_->directory_load_count());
733
734   ASSERT_LE(1u, mock_directory_observer_->changed_directories().size());
735 }
736
737 TEST_F(FileSystemTest, GetResourceEntryNonExistentWhileRefreshing) {
738   // Use old timestamp so the fast fetch will be performed.
739   ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_OLD_TIMESTAMP));
740
741   // If an entry is not found, parent directory's resource list is fetched.
742   EXPECT_FALSE(GetResourceEntrySync(base::FilePath(
743       FILE_PATH_LITERAL("drive/root/Dir1/NonExistentFile"))));
744   EXPECT_EQ(1, fake_drive_service_->directory_load_count());
745
746   ASSERT_LE(1u, mock_directory_observer_->changed_directories().size());
747 }
748
749 TEST_F(FileSystemTest, CreateDirectoryByImplicitLoad) {
750   // Intentionally *not* calling LoadFullResourceList(), for testing that
751   // CreateDirectory ensures the resource list is loaded before it runs.
752
753   base::FilePath existing_directory(
754       FILE_PATH_LITERAL("drive/root/Directory 1"));
755   FileError error = FILE_ERROR_FAILED;
756   file_system_->CreateDirectory(
757       existing_directory,
758       true,  // is_exclusive
759       false,  // is_recursive
760       google_apis::test_util::CreateCopyResultCallback(&error));
761   test_util::RunBlockingPoolTask();
762
763   // It should fail because is_exclusive is set to true.
764   EXPECT_EQ(FILE_ERROR_EXISTS, error);
765 }
766
767 TEST_F(FileSystemTest, CreateDirectoryRecursively) {
768   // Intentionally *not* calling LoadFullResourceList(), for testing that
769   // CreateDirectory ensures the resource list is loaded before it runs.
770
771   base::FilePath new_directory(
772       FILE_PATH_LITERAL("drive/root/Directory 1/a/b/c/d"));
773   FileError error = FILE_ERROR_FAILED;
774   file_system_->CreateDirectory(
775       new_directory,
776       true,  // is_exclusive
777       true,  // is_recursive
778       google_apis::test_util::CreateCopyResultCallback(&error));
779   test_util::RunBlockingPoolTask();
780
781   EXPECT_EQ(FILE_ERROR_OK, error);
782
783   scoped_ptr<ResourceEntry> entry(GetResourceEntrySync(new_directory));
784   ASSERT_TRUE(entry);
785   EXPECT_TRUE(entry->file_info().is_directory());
786 }
787
788 TEST_F(FileSystemTest, PinAndUnpin) {
789   ASSERT_TRUE(LoadFullResourceList());
790
791   base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
792
793   // Get the file info.
794   scoped_ptr<ResourceEntry> entry(GetResourceEntrySync(file_path));
795   ASSERT_TRUE(entry);
796
797   // Pin the file.
798   FileError error = FILE_ERROR_FAILED;
799   file_system_->Pin(file_path,
800                     google_apis::test_util::CreateCopyResultCallback(&error));
801   test_util::RunBlockingPoolTask();
802   EXPECT_EQ(FILE_ERROR_OK, error);
803
804   FileCacheEntry cache_entry;
805   EXPECT_TRUE(cache_->GetCacheEntry(entry->local_id(), &cache_entry));
806   EXPECT_TRUE(cache_entry.is_pinned());
807   EXPECT_TRUE(cache_entry.is_present());
808
809   // Unpin the file.
810   error = FILE_ERROR_FAILED;
811   file_system_->Unpin(file_path,
812                       google_apis::test_util::CreateCopyResultCallback(&error));
813   test_util::RunBlockingPoolTask();
814   EXPECT_EQ(FILE_ERROR_OK, error);
815
816   EXPECT_TRUE(cache_->GetCacheEntry(entry->local_id(), &cache_entry));
817   EXPECT_FALSE(cache_entry.is_pinned());
818
819   // Pinned file gets synced and it results in entry state changes.
820   ASSERT_EQ(1u, mock_directory_observer_->changed_directories().size());
821   EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("drive/root")),
822             mock_directory_observer_->changed_directories()[0]);
823 }
824
825 TEST_F(FileSystemTest, PinAndUnpin_NotSynced) {
826   ASSERT_TRUE(LoadFullResourceList());
827
828   base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
829
830   // Get the file info.
831   scoped_ptr<ResourceEntry> entry(GetResourceEntrySync(file_path));
832   ASSERT_TRUE(entry);
833
834   // Unpin the file just after pinning. File fetch should be cancelled.
835   FileError error_pin = FILE_ERROR_FAILED;
836   file_system_->Pin(
837       file_path,
838       google_apis::test_util::CreateCopyResultCallback(&error_pin));
839
840   FileError error_unpin = FILE_ERROR_FAILED;
841   file_system_->Unpin(
842       file_path,
843       google_apis::test_util::CreateCopyResultCallback(&error_unpin));
844
845   test_util::RunBlockingPoolTask();
846   EXPECT_EQ(FILE_ERROR_OK, error_pin);
847   EXPECT_EQ(FILE_ERROR_OK, error_unpin);
848
849   // No cache file available because the sync was cancelled by Unpin().
850   FileCacheEntry cache_entry;
851   EXPECT_FALSE(cache_->GetCacheEntry(entry->local_id(), &cache_entry));
852 }
853
854 TEST_F(FileSystemTest, GetAvailableSpace) {
855   FileError error = FILE_ERROR_OK;
856   int64 bytes_total;
857   int64 bytes_used;
858   file_system_->GetAvailableSpace(
859       google_apis::test_util::CreateCopyResultCallback(
860           &error, &bytes_total, &bytes_used));
861   test_util::RunBlockingPoolTask();
862   EXPECT_EQ(GG_LONGLONG(6789012345), bytes_used);
863   EXPECT_EQ(GG_LONGLONG(9876543210), bytes_total);
864 }
865
866 TEST_F(FileSystemTest, MarkCacheFileAsMountedAndUnmounted) {
867   ASSERT_TRUE(LoadFullResourceList());
868
869   base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
870   scoped_ptr<ResourceEntry> entry(GetResourceEntrySync(file_in_root));
871   ASSERT_TRUE(entry);
872
873   // Write to cache.
874   ASSERT_EQ(FILE_ERROR_OK, cache_->Store(
875       entry->local_id(),
876       entry->file_specific_info().md5(),
877       google_apis::test_util::GetTestFilePath("gdata/root_feed.json"),
878       internal::FileCache::FILE_OPERATION_COPY));
879
880   // Test for mounting.
881   FileError error = FILE_ERROR_FAILED;
882   base::FilePath file_path;
883   file_system_->MarkCacheFileAsMounted(
884       file_in_root,
885       google_apis::test_util::CreateCopyResultCallback(&error, &file_path));
886   test_util::RunBlockingPoolTask();
887   EXPECT_EQ(FILE_ERROR_OK, error);
888
889   // Cannot remove a cache entry while it's being mounted.
890   EXPECT_EQ(FILE_ERROR_IN_USE, cache_->Remove(entry->local_id()));
891
892   // Test for unmounting.
893   error = FILE_ERROR_FAILED;
894   file_system_->MarkCacheFileAsUnmounted(
895       file_path,
896       google_apis::test_util::CreateCopyResultCallback(&error));
897   test_util::RunBlockingPoolTask();
898   EXPECT_EQ(FILE_ERROR_OK, error);
899
900   // Now able to remove the cache entry.
901   EXPECT_EQ(FILE_ERROR_OK, cache_->Remove(entry->local_id()));
902 }
903
904 TEST_F(FileSystemTest, GetShareUrl) {
905   ASSERT_TRUE(LoadFullResourceList());
906
907   const base::FilePath kFileInRoot(FILE_PATH_LITERAL("drive/root/File 1.txt"));
908   const GURL kEmbedOrigin("chrome-extension://test-id");
909
910   // Try to fetch the URL for the sharing dialog.
911   FileError error = FILE_ERROR_FAILED;
912   GURL share_url;
913   file_system_->GetShareUrl(
914       kFileInRoot,
915       kEmbedOrigin,
916       google_apis::test_util::CreateCopyResultCallback(&error, &share_url));
917   test_util::RunBlockingPoolTask();
918
919   // Verify the share url to the sharing dialog.
920   EXPECT_EQ(FILE_ERROR_OK, error);
921   EXPECT_EQ(GURL("https://file_link_share/"), share_url);
922 }
923
924 TEST_F(FileSystemTest, GetShareUrlNotAvailable) {
925   ASSERT_TRUE(LoadFullResourceList());
926
927   const base::FilePath kFileInRoot(
928       FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt"));
929   const GURL kEmbedOrigin("chrome-extension://test-id");
930
931   // Try to fetch the URL for the sharing dialog.
932   FileError error = FILE_ERROR_FAILED;
933   GURL share_url;
934
935   file_system_->GetShareUrl(
936       kFileInRoot,
937       kEmbedOrigin,
938       google_apis::test_util::CreateCopyResultCallback(&error, &share_url));
939   test_util::RunBlockingPoolTask();
940
941   // Verify the error and the share url, which should be empty.
942   EXPECT_EQ(FILE_ERROR_FAILED, error);
943   EXPECT_TRUE(share_url.is_empty());
944 }
945
946 }   // namespace drive