Home | History | Annotate | Download | only in drive
      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/change_list_processor.h"
     20 #include "chrome/browser/chromeos/drive/drive.pb.h"
     21 #include "chrome/browser/chromeos/drive/fake_free_disk_space_getter.h"
     22 #include "chrome/browser/chromeos/drive/file_system_observer.h"
     23 #include "chrome/browser/chromeos/drive/file_system_util.h"
     24 #include "chrome/browser/chromeos/drive/job_scheduler.h"
     25 #include "chrome/browser/chromeos/drive/sync_client.h"
     26 #include "chrome/browser/chromeos/drive/test_util.h"
     27 #include "chrome/browser/drive/fake_drive_service.h"
     28 #include "content/public/test/test_browser_thread_bundle.h"
     29 #include "google_apis/drive/drive_api_parser.h"
     30 #include "google_apis/drive/test_util.h"
     31 #include "testing/gtest/include/gtest/gtest.h"
     32 
     33 namespace drive {
     34 namespace {
     35 
     36 // Counts the number of invocation, and if it increased up to |expected_counter|
     37 // quits the current message loop by calling |quit|.
     38 void AsyncInitializationCallback(
     39     int* counter, int expected_counter, const base::Closure& quit,
     40     FileError error, scoped_ptr<ResourceEntry> entry) {
     41   if (error != FILE_ERROR_OK || !entry) {
     42     // If we hit an error case, quit the message loop immediately.
     43     // Then the expectation in the test case can find it because the actual
     44     // value of |counter| is different from the expected one.
     45     quit.Run();
     46     return;
     47   }
     48 
     49   (*counter)++;
     50   if (*counter >= expected_counter)
     51     quit.Run();
     52 }
     53 
     54 // This class is used to record directory changes and examine them later.
     55 class MockDirectoryChangeObserver : public FileSystemObserver {
     56  public:
     57   MockDirectoryChangeObserver() {}
     58   virtual ~MockDirectoryChangeObserver() {}
     59 
     60   // FileSystemObserver overrides.
     61   virtual void OnDirectoryChanged(
     62       const base::FilePath& directory_path) OVERRIDE {
     63     changed_directories_.push_back(directory_path);
     64   }
     65 
     66   const std::vector<base::FilePath>& changed_directories() const {
     67     return changed_directories_;
     68   }
     69 
     70  private:
     71   std::vector<base::FilePath> changed_directories_;
     72   DISALLOW_COPY_AND_ASSIGN(MockDirectoryChangeObserver);
     73 };
     74 
     75 }  // namespace
     76 
     77 class FileSystemTest : public testing::Test {
     78  protected:
     79   virtual void SetUp() OVERRIDE {
     80     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     81     pref_service_.reset(new TestingPrefServiceSimple);
     82     test_util::RegisterDrivePrefs(pref_service_->registry());
     83 
     84     fake_drive_service_.reset(new FakeDriveService);
     85     fake_drive_service_->LoadResourceListForWapi(
     86         "gdata/root_feed.json");
     87     fake_drive_service_->LoadAccountMetadataForWapi(
     88         "gdata/account_metadata.json");
     89 
     90     fake_free_disk_space_getter_.reset(new FakeFreeDiskSpaceGetter);
     91 
     92     scheduler_.reset(new JobScheduler(pref_service_.get(),
     93                                       fake_drive_service_.get(),
     94                                       base::MessageLoopProxy::current().get()));
     95 
     96     mock_directory_observer_.reset(new MockDirectoryChangeObserver);
     97 
     98     SetUpResourceMetadataAndFileSystem();
     99   }
    100 
    101   void SetUpResourceMetadataAndFileSystem() {
    102     const base::FilePath metadata_dir = temp_dir_.path().AppendASCII("meta");
    103     ASSERT_TRUE(base::CreateDirectory(metadata_dir));
    104     metadata_storage_.reset(new internal::ResourceMetadataStorage(
    105         metadata_dir, base::MessageLoopProxy::current().get()));
    106     ASSERT_TRUE(metadata_storage_->Initialize());
    107 
    108     const base::FilePath cache_dir = temp_dir_.path().AppendASCII("files");
    109     ASSERT_TRUE(base::CreateDirectory(cache_dir));
    110     cache_.reset(new internal::FileCache(
    111         metadata_storage_.get(),
    112         cache_dir,
    113         base::MessageLoopProxy::current().get(),
    114         fake_free_disk_space_getter_.get()));
    115     ASSERT_TRUE(cache_->Initialize());
    116 
    117     resource_metadata_.reset(new internal::ResourceMetadata(
    118         metadata_storage_.get(), base::MessageLoopProxy::current()));
    119     ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->Initialize());
    120 
    121     const base::FilePath temp_file_dir = temp_dir_.path().AppendASCII("tmp");
    122     ASSERT_TRUE(base::CreateDirectory(temp_file_dir));
    123     file_system_.reset(new FileSystem(
    124         pref_service_.get(),
    125         cache_.get(),
    126         fake_drive_service_.get(),
    127         scheduler_.get(),
    128         resource_metadata_.get(),
    129         base::MessageLoopProxy::current().get(),
    130         temp_file_dir));
    131     file_system_->AddObserver(mock_directory_observer_.get());
    132 
    133     // Disable delaying so that the sync starts immediately.
    134     file_system_->sync_client_for_testing()->set_delay_for_testing(
    135         base::TimeDelta::FromSeconds(0));
    136   }
    137 
    138   // Loads the full resource list via FakeDriveService.
    139   bool LoadFullResourceList() {
    140     FileError error = FILE_ERROR_FAILED;
    141     file_system_->change_list_loader_for_testing()->LoadIfNeeded(
    142         internal::DirectoryFetchInfo(),
    143         google_apis::test_util::CreateCopyResultCallback(&error));
    144     test_util::RunBlockingPoolTask();
    145     return error == FILE_ERROR_OK;
    146   }
    147 
    148   // Gets resource entry by path synchronously.
    149   scoped_ptr<ResourceEntry> GetResourceEntrySync(
    150       const base::FilePath& file_path) {
    151     FileError error = FILE_ERROR_FAILED;
    152     scoped_ptr<ResourceEntry> entry;
    153     file_system_->GetResourceEntry(
    154         file_path,
    155         google_apis::test_util::CreateCopyResultCallback(&error, &entry));
    156     test_util::RunBlockingPoolTask();
    157 
    158     return entry.Pass();
    159   }
    160 
    161   // Gets directory info by path synchronously.
    162   scoped_ptr<ResourceEntryVector> ReadDirectorySync(
    163       const base::FilePath& file_path) {
    164     FileError error = FILE_ERROR_FAILED;
    165     scoped_ptr<ResourceEntryVector> entries;
    166     file_system_->ReadDirectory(
    167         file_path,
    168         google_apis::test_util::CreateCopyResultCallback(&error, &entries));
    169     test_util::RunBlockingPoolTask();
    170 
    171     return entries.Pass();
    172   }
    173 
    174   // Returns true if an entry exists at |file_path|.
    175   bool EntryExists(const base::FilePath& file_path) {
    176     return GetResourceEntrySync(file_path);
    177   }
    178 
    179   // Flag for specifying the timestamp of the test filesystem cache.
    180   enum SetUpTestFileSystemParam {
    181     USE_OLD_TIMESTAMP,
    182     USE_SERVER_TIMESTAMP,
    183   };
    184 
    185   // Sets up a filesystem with directories: drive/root, drive/root/Dir1,
    186   // drive/root/Dir1/SubDir2 and files drive/root/File1, drive/root/Dir1/File2,
    187   // drive/root/Dir1/SubDir2/File3. If |use_up_to_date_timestamp| is true, sets
    188   // the changestamp to 654321, equal to that of "account_metadata.json" test
    189   // data, indicating the cache is holding the latest file system info.
    190   void SetUpTestFileSystem(SetUpTestFileSystemParam param) {
    191     // Destroy the existing resource metadata to close DB.
    192     resource_metadata_.reset();
    193 
    194     const base::FilePath metadata_dir = temp_dir_.path().AppendASCII("meta");
    195     ASSERT_TRUE(base::CreateDirectory(metadata_dir));
    196     scoped_ptr<internal::ResourceMetadataStorage,
    197                test_util::DestroyHelperForTests> metadata_storage(
    198         new internal::ResourceMetadataStorage(
    199             metadata_dir, base::MessageLoopProxy::current().get()));
    200 
    201     scoped_ptr<internal::ResourceMetadata, test_util::DestroyHelperForTests>
    202         resource_metadata(new internal::ResourceMetadata(
    203             metadata_storage_.get(), base::MessageLoopProxy::current()));
    204 
    205     ASSERT_EQ(FILE_ERROR_OK, resource_metadata->Initialize());
    206 
    207     const int64 changestamp = param == USE_SERVER_TIMESTAMP ? 654321 : 1;
    208     ASSERT_EQ(FILE_ERROR_OK,
    209               resource_metadata->SetLargestChangestamp(changestamp));
    210 
    211     // drive/root
    212     const std::string root_resource_id =
    213         fake_drive_service_->GetRootResourceId();
    214     std::string local_id;
    215     ASSERT_EQ(FILE_ERROR_OK,
    216               resource_metadata->AddEntry(util::CreateMyDriveRootEntry(
    217                   root_resource_id), &local_id));
    218     const std::string root_local_id = local_id;
    219 
    220     // drive/root/File1
    221     ResourceEntry file1;
    222     file1.set_title("File1");
    223     file1.set_resource_id("resource_id:File1");
    224     file1.set_parent_local_id(root_local_id);
    225     file1.mutable_file_specific_info()->set_md5("md5");
    226     file1.mutable_file_info()->set_is_directory(false);
    227     file1.mutable_file_info()->set_size(1048576);
    228     ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(file1, &local_id));
    229 
    230     // drive/root/Dir1
    231     ResourceEntry dir1;
    232     dir1.set_title("Dir1");
    233     dir1.set_resource_id("resource_id:Dir1");
    234     dir1.set_parent_local_id(root_local_id);
    235     dir1.mutable_file_info()->set_is_directory(true);
    236     ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(dir1, &local_id));
    237     const std::string dir1_local_id = local_id;
    238 
    239     // drive/root/Dir1/File2
    240     ResourceEntry file2;
    241     file2.set_title("File2");
    242     file2.set_resource_id("resource_id:File2");
    243     file2.set_parent_local_id(dir1_local_id);
    244     file2.mutable_file_specific_info()->set_md5("md5");
    245     file2.mutable_file_info()->set_is_directory(false);
    246     file2.mutable_file_info()->set_size(555);
    247     ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(file2, &local_id));
    248 
    249     // drive/root/Dir1/SubDir2
    250     ResourceEntry dir2;
    251     dir2.set_title("SubDir2");
    252     dir2.set_resource_id("resource_id:SubDir2");
    253     dir2.set_parent_local_id(dir1_local_id);
    254     dir2.mutable_file_info()->set_is_directory(true);
    255     ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(dir2, &local_id));
    256     const std::string dir2_local_id = local_id;
    257 
    258     // drive/root/Dir1/SubDir2/File3
    259     ResourceEntry file3;
    260     file3.set_title("File3");
    261     file3.set_resource_id("resource_id:File3");
    262     file3.set_parent_local_id(dir2_local_id);
    263     file3.mutable_file_specific_info()->set_md5("md5");
    264     file3.mutable_file_info()->set_is_directory(false);
    265     file3.mutable_file_info()->set_size(12345);
    266     ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(file3, &local_id));
    267 
    268     // Recreate resource metadata.
    269     SetUpResourceMetadataAndFileSystem();
    270   }
    271 
    272   content::TestBrowserThreadBundle thread_bundle_;
    273   base::ScopedTempDir temp_dir_;
    274   // We don't use TestingProfile::GetPrefs() in favor of having less
    275   // dependencies to Profile in general.
    276   scoped_ptr<TestingPrefServiceSimple> pref_service_;
    277 
    278   scoped_ptr<FakeDriveService> fake_drive_service_;
    279   scoped_ptr<FakeFreeDiskSpaceGetter> fake_free_disk_space_getter_;
    280   scoped_ptr<JobScheduler> scheduler_;
    281   scoped_ptr<MockDirectoryChangeObserver> mock_directory_observer_;
    282 
    283   scoped_ptr<internal::ResourceMetadataStorage,
    284              test_util::DestroyHelperForTests> metadata_storage_;
    285   scoped_ptr<internal::FileCache, test_util::DestroyHelperForTests> cache_;
    286   scoped_ptr<internal::ResourceMetadata, test_util::DestroyHelperForTests>
    287       resource_metadata_;
    288   scoped_ptr<FileSystem> file_system_;
    289 };
    290 
    291 TEST_F(FileSystemTest, DuplicatedAsyncInitialization) {
    292   base::RunLoop loop;
    293 
    294   int counter = 0;
    295   const GetResourceEntryCallback& callback = base::Bind(
    296       &AsyncInitializationCallback, &counter, 2, loop.QuitClosure());
    297 
    298   file_system_->GetResourceEntry(
    299       base::FilePath(FILE_PATH_LITERAL("drive/root")), callback);
    300   file_system_->GetResourceEntry(
    301       base::FilePath(FILE_PATH_LITERAL("drive/root")), callback);
    302   loop.Run();  // Wait to get our result
    303   EXPECT_EQ(2, counter);
    304 
    305   EXPECT_EQ(1, fake_drive_service_->resource_list_load_count());
    306 
    307   // "Fast fetch" will fire an OnirectoryChanged event.
    308   ASSERT_EQ(1u, mock_directory_observer_->changed_directories().size());
    309   EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("drive")),
    310             mock_directory_observer_->changed_directories()[0]);
    311 }
    312 
    313 TEST_F(FileSystemTest, GetGrandRootEntry) {
    314   const base::FilePath kFilePath(FILE_PATH_LITERAL("drive"));
    315   scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
    316   ASSERT_TRUE(entry);
    317   EXPECT_EQ(util::kDriveGrandRootLocalId, entry->resource_id());
    318 
    319   // Getting the grand root entry should not cause the resource load to happen.
    320   EXPECT_EQ(0, fake_drive_service_->about_resource_load_count());
    321   EXPECT_EQ(0, fake_drive_service_->resource_list_load_count());
    322 }
    323 
    324 TEST_F(FileSystemTest, GetOtherDirEntry) {
    325   const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/other"));
    326   scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
    327   ASSERT_TRUE(entry);
    328   EXPECT_EQ(util::kDriveOtherDirLocalId, entry->resource_id());
    329 
    330   // Getting the "other" directory entry should not cause the resource load to
    331   // happen.
    332   EXPECT_EQ(0, fake_drive_service_->about_resource_load_count());
    333   EXPECT_EQ(0, fake_drive_service_->resource_list_load_count());
    334 }
    335 
    336 TEST_F(FileSystemTest, GetMyDriveRoot) {
    337   const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root"));
    338   scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
    339   ASSERT_TRUE(entry);
    340   EXPECT_EQ(fake_drive_service_->GetRootResourceId(), entry->resource_id());
    341 
    342   EXPECT_EQ(1, fake_drive_service_->about_resource_load_count());
    343 
    344   // After "fast fetch" is done, full resource list is fetched.
    345   EXPECT_EQ(1, fake_drive_service_->resource_list_load_count());
    346 
    347   // "Fast fetch" will fire an OnirectoryChanged event.
    348   ASSERT_EQ(1u, mock_directory_observer_->changed_directories().size());
    349   EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("drive")),
    350             mock_directory_observer_->changed_directories()[0]);
    351 }
    352 
    353 TEST_F(FileSystemTest, GetExistingFile) {
    354   // Simulate the situation that full feed fetching takes very long time,
    355   // to test the recursive "fast fetch" feature is properly working.
    356   fake_drive_service_->set_never_return_all_resource_list(true);
    357 
    358   const base::FilePath kFilePath(
    359       FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt"));
    360   scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
    361   ASSERT_TRUE(entry);
    362   EXPECT_EQ("file:subdirectory_file_1_id", entry->resource_id());
    363 
    364   EXPECT_EQ(1, fake_drive_service_->about_resource_load_count());
    365   EXPECT_EQ(2, fake_drive_service_->directory_load_count());
    366   EXPECT_EQ(1, fake_drive_service_->blocked_resource_list_load_count());
    367 }
    368 
    369 TEST_F(FileSystemTest, GetExistingDocument) {
    370   const base::FilePath kFilePath(
    371       FILE_PATH_LITERAL("drive/root/Document 1 excludeDir-test.gdoc"));
    372   scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
    373   ASSERT_TRUE(entry);
    374   EXPECT_EQ("document:5_document_resource_id", entry->resource_id());
    375 }
    376 
    377 TEST_F(FileSystemTest, GetNonExistingFile) {
    378   const base::FilePath kFilePath(
    379       FILE_PATH_LITERAL("drive/root/nonexisting.file"));
    380   scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
    381   EXPECT_FALSE(entry);
    382 }
    383 
    384 TEST_F(FileSystemTest, GetExistingDirectory) {
    385   const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/Directory 1"));
    386   scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
    387   ASSERT_TRUE(entry);
    388   ASSERT_EQ("folder:1_folder_resource_id", entry->resource_id());
    389 
    390   // The changestamp should be propagated to the directory.
    391   EXPECT_EQ(fake_drive_service_->largest_changestamp(),
    392             entry->directory_specific_info().changestamp());
    393 }
    394 
    395 TEST_F(FileSystemTest, GetInSubSubdir) {
    396   const base::FilePath kFilePath(
    397       FILE_PATH_LITERAL("drive/root/Directory 1/Sub Directory Folder/"
    398                         "Sub Sub Directory Folder"));
    399   scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
    400   ASSERT_TRUE(entry);
    401   ASSERT_EQ("folder:sub_sub_directory_folder_id", entry->resource_id());
    402 }
    403 
    404 TEST_F(FileSystemTest, GetOrphanFile) {
    405   ASSERT_TRUE(LoadFullResourceList());
    406 
    407   // Entry without parents are placed under "drive/other".
    408   const base::FilePath kFilePath(
    409       FILE_PATH_LITERAL("drive/other/Orphan File 1.txt"));
    410   scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
    411   ASSERT_TRUE(entry);
    412   EXPECT_EQ("file:1_orphanfile_resource_id", entry->resource_id());
    413 }
    414 
    415 TEST_F(FileSystemTest, ReadDirectory_Root) {
    416   // ReadDirectory() should kick off the resource list loading.
    417   scoped_ptr<ResourceEntryVector> entries(
    418       ReadDirectorySync(base::FilePath::FromUTF8Unsafe("drive")));
    419   // The root directory should be read correctly.
    420   ASSERT_TRUE(entries);
    421   ASSERT_EQ(3U, entries->size());
    422 
    423   // The found three directories should be /drive/root, /drive/other and
    424   // /drive/trash.
    425   std::set<base::FilePath> found;
    426   for (size_t i = 0; i < entries->size(); ++i)
    427     found.insert(base::FilePath::FromUTF8Unsafe((*entries)[i].title()));
    428   EXPECT_EQ(3U, found.size());
    429   EXPECT_EQ(1U, found.count(base::FilePath(util::kDriveMyDriveRootDirName)));
    430   EXPECT_EQ(1U, found.count(base::FilePath(util::kDriveOtherDirName)));
    431   EXPECT_EQ(1U, found.count(base::FilePath(util::kDriveTrashDirName)));
    432 
    433   ASSERT_EQ(1u, mock_directory_observer_->changed_directories().size());
    434   EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("drive")),
    435             mock_directory_observer_->changed_directories()[0]);
    436 }
    437 
    438 TEST_F(FileSystemTest, ReadDirectory_NonRootDirectory) {
    439   // ReadDirectory() should kick off the resource list loading.
    440   scoped_ptr<ResourceEntryVector> entries(
    441       ReadDirectorySync(
    442           base::FilePath::FromUTF8Unsafe("drive/root/Directory 1")));
    443   // The non root directory should also be read correctly.
    444   // There was a bug (crbug.com/181487), which broke this behavior.
    445   // Make sure this is fixed.
    446   ASSERT_TRUE(entries);
    447   EXPECT_EQ(3U, entries->size());
    448 }
    449 
    450 TEST_F(FileSystemTest, LoadFileSystemFromUpToDateCache) {
    451   ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_SERVER_TIMESTAMP));
    452 
    453   // Kicks loading of cached file system and query for server update.
    454   EXPECT_TRUE(ReadDirectorySync(util::GetDriveMyDriveRootPath()));
    455 
    456   // SetUpTestFileSystem and "account_metadata.json" have the same
    457   // changestamp (i.e. the local metadata is up-to-date), so no request for
    458   // new resource list (i.e., call to GetResourceList) should happen.
    459   EXPECT_EQ(1, fake_drive_service_->about_resource_load_count());
    460   EXPECT_EQ(0, fake_drive_service_->resource_list_load_count());
    461 
    462   // Since the file system has verified that it holds the latest snapshot,
    463   // it should change its state to "loaded", which admits periodic refresh.
    464   // To test it, call CheckForUpdates and verify it does try to check updates.
    465   file_system_->CheckForUpdates();
    466   test_util::RunBlockingPoolTask();
    467   EXPECT_EQ(2, fake_drive_service_->about_resource_load_count());
    468 }
    469 
    470 TEST_F(FileSystemTest, LoadFileSystemFromCacheWhileOffline) {
    471   ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_OLD_TIMESTAMP));
    472 
    473   // Make GetResourceList fail for simulating offline situation. This will
    474   // leave the file system "loaded from cache, but not synced with server"
    475   // state.
    476   fake_drive_service_->set_offline(true);
    477 
    478   // Load the root.
    479   EXPECT_TRUE(ReadDirectorySync(util::GetDriveGrandRootPath()));
    480   // Loading of about resource should not happen as it's offline.
    481   EXPECT_EQ(0, fake_drive_service_->about_resource_load_count());
    482 
    483   // Load "My Drive".
    484   EXPECT_TRUE(ReadDirectorySync(util::GetDriveMyDriveRootPath()));
    485   EXPECT_EQ(0, fake_drive_service_->about_resource_load_count());
    486 
    487   // Tests that cached data can be loaded even if the server is not reachable.
    488   EXPECT_TRUE(EntryExists(base::FilePath(
    489       FILE_PATH_LITERAL("drive/root/File1"))));
    490   EXPECT_TRUE(EntryExists(base::FilePath(
    491       FILE_PATH_LITERAL("drive/root/Dir1"))));
    492   EXPECT_TRUE(EntryExists(base::FilePath(
    493       FILE_PATH_LITERAL("drive/root/Dir1/File2"))));
    494   EXPECT_TRUE(EntryExists(base::FilePath(
    495       FILE_PATH_LITERAL("drive/root/Dir1/SubDir2"))));
    496   EXPECT_TRUE(EntryExists(base::FilePath(
    497       FILE_PATH_LITERAL("drive/root/Dir1/SubDir2/File3"))));
    498 
    499   // Since the file system has at least succeeded to load cached snapshot,
    500   // the file system should be able to start periodic refresh.
    501   // To test it, call CheckForUpdates and verify it does try to check
    502   // updates, which will cause directory changes.
    503   fake_drive_service_->set_offline(false);
    504 
    505   file_system_->CheckForUpdates();
    506 
    507   test_util::RunBlockingPoolTask();
    508   EXPECT_EQ(1, fake_drive_service_->about_resource_load_count());
    509   EXPECT_EQ(1, fake_drive_service_->change_list_load_count());
    510 
    511   ASSERT_LE(1u, mock_directory_observer_->changed_directories().size());
    512 }
    513 
    514 TEST_F(FileSystemTest, ReadDirectoryWhileRefreshing) {
    515   // Enter the "refreshing" state so the fast fetch will be performed.
    516   ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_OLD_TIMESTAMP));
    517   file_system_->CheckForUpdates();
    518 
    519   // The list of resources in "drive/root/Dir1" should be fetched.
    520   EXPECT_TRUE(ReadDirectorySync(base::FilePath(
    521       FILE_PATH_LITERAL("drive/root/Dir1"))));
    522   EXPECT_EQ(1, fake_drive_service_->directory_load_count());
    523 
    524   ASSERT_LE(1u, mock_directory_observer_->changed_directories().size());
    525 }
    526 
    527 TEST_F(FileSystemTest, GetResourceEntryExistingWhileRefreshing) {
    528   // Enter the "refreshing" state.
    529   ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_OLD_TIMESTAMP));
    530   file_system_->CheckForUpdates();
    531 
    532   // If an entry is already found in local metadata, no directory fetch happens.
    533   EXPECT_TRUE(GetResourceEntrySync(base::FilePath(
    534       FILE_PATH_LITERAL("drive/root/Dir1/File2"))));
    535   EXPECT_EQ(0, fake_drive_service_->directory_load_count());
    536 }
    537 
    538 TEST_F(FileSystemTest, GetResourceEntryNonExistentWhileRefreshing) {
    539   // Enter the "refreshing" state so the fast fetch will be performed.
    540   ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_OLD_TIMESTAMP));
    541   file_system_->CheckForUpdates();
    542 
    543   // If an entry is not found, parent directory's resource list is fetched.
    544   EXPECT_FALSE(GetResourceEntrySync(base::FilePath(
    545       FILE_PATH_LITERAL("drive/root/Dir1/NonExistentFile"))));
    546   EXPECT_EQ(1, fake_drive_service_->directory_load_count());
    547 
    548   ASSERT_LE(1u, mock_directory_observer_->changed_directories().size());
    549 }
    550 
    551 TEST_F(FileSystemTest, CreateDirectoryByImplicitLoad) {
    552   // Intentionally *not* calling LoadFullResourceList(), for testing that
    553   // CreateDirectory ensures the resource list is loaded before it runs.
    554 
    555   base::FilePath existing_directory(
    556       FILE_PATH_LITERAL("drive/root/Directory 1"));
    557   FileError error = FILE_ERROR_FAILED;
    558   file_system_->CreateDirectory(
    559       existing_directory,
    560       true,  // is_exclusive
    561       false,  // is_recursive
    562       google_apis::test_util::CreateCopyResultCallback(&error));
    563   test_util::RunBlockingPoolTask();
    564 
    565   // It should fail because is_exclusive is set to true.
    566   EXPECT_EQ(FILE_ERROR_EXISTS, error);
    567 }
    568 
    569 TEST_F(FileSystemTest, CreateDirectoryRecursively) {
    570   // Intentionally *not* calling LoadFullResourceList(), for testing that
    571   // CreateDirectory ensures the resource list is loaded before it runs.
    572 
    573   base::FilePath new_directory(
    574       FILE_PATH_LITERAL("drive/root/Directory 1/a/b/c/d"));
    575   FileError error = FILE_ERROR_FAILED;
    576   file_system_->CreateDirectory(
    577       new_directory,
    578       true,  // is_exclusive
    579       true,  // is_recursive
    580       google_apis::test_util::CreateCopyResultCallback(&error));
    581   test_util::RunBlockingPoolTask();
    582 
    583   EXPECT_EQ(FILE_ERROR_OK, error);
    584 
    585   scoped_ptr<ResourceEntry> entry(GetResourceEntrySync(new_directory));
    586   ASSERT_TRUE(entry);
    587   EXPECT_TRUE(entry->file_info().is_directory());
    588 }
    589 
    590 TEST_F(FileSystemTest, PinAndUnpin) {
    591   ASSERT_TRUE(LoadFullResourceList());
    592 
    593   base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
    594 
    595   // Get the file info.
    596   scoped_ptr<ResourceEntry> entry(GetResourceEntrySync(file_path));
    597   ASSERT_TRUE(entry);
    598 
    599   // Pin the file.
    600   FileError error = FILE_ERROR_FAILED;
    601   file_system_->Pin(file_path,
    602                     google_apis::test_util::CreateCopyResultCallback(&error));
    603   test_util::RunBlockingPoolTask();
    604   EXPECT_EQ(FILE_ERROR_OK, error);
    605 
    606   FileCacheEntry cache_entry;
    607   EXPECT_TRUE(cache_->GetCacheEntry(entry->local_id(), &cache_entry));
    608   EXPECT_TRUE(cache_entry.is_pinned());
    609   EXPECT_TRUE(cache_entry.is_present());
    610 
    611   // Unpin the file.
    612   error = FILE_ERROR_FAILED;
    613   file_system_->Unpin(file_path,
    614                       google_apis::test_util::CreateCopyResultCallback(&error));
    615   test_util::RunBlockingPoolTask();
    616   EXPECT_EQ(FILE_ERROR_OK, error);
    617 
    618   EXPECT_TRUE(cache_->GetCacheEntry(entry->local_id(), &cache_entry));
    619   EXPECT_FALSE(cache_entry.is_pinned());
    620 
    621   // Pinned file gets synced and it results in entry state changes.
    622   ASSERT_EQ(1u, mock_directory_observer_->changed_directories().size());
    623   EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("drive/root")),
    624             mock_directory_observer_->changed_directories()[0]);
    625 }
    626 
    627 TEST_F(FileSystemTest, PinAndUnpin_NotSynced) {
    628   ASSERT_TRUE(LoadFullResourceList());
    629 
    630   base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
    631 
    632   // Get the file info.
    633   scoped_ptr<ResourceEntry> entry(GetResourceEntrySync(file_path));
    634   ASSERT_TRUE(entry);
    635 
    636   // Unpin the file just after pinning. File fetch should be cancelled.
    637   FileError error_pin = FILE_ERROR_FAILED;
    638   file_system_->Pin(
    639       file_path,
    640       google_apis::test_util::CreateCopyResultCallback(&error_pin));
    641 
    642   FileError error_unpin = FILE_ERROR_FAILED;
    643   file_system_->Unpin(
    644       file_path,
    645       google_apis::test_util::CreateCopyResultCallback(&error_unpin));
    646 
    647   test_util::RunBlockingPoolTask();
    648   EXPECT_EQ(FILE_ERROR_OK, error_pin);
    649   EXPECT_EQ(FILE_ERROR_OK, error_unpin);
    650 
    651   // No cache file available because the sync was cancelled by Unpin().
    652   FileCacheEntry cache_entry;
    653   EXPECT_FALSE(cache_->GetCacheEntry(entry->local_id(), &cache_entry));
    654 }
    655 
    656 TEST_F(FileSystemTest, GetAvailableSpace) {
    657   FileError error = FILE_ERROR_OK;
    658   int64 bytes_total;
    659   int64 bytes_used;
    660   file_system_->GetAvailableSpace(
    661       google_apis::test_util::CreateCopyResultCallback(
    662           &error, &bytes_total, &bytes_used));
    663   test_util::RunBlockingPoolTask();
    664   EXPECT_EQ(GG_LONGLONG(6789012345), bytes_used);
    665   EXPECT_EQ(GG_LONGLONG(9876543210), bytes_total);
    666 }
    667 
    668 TEST_F(FileSystemTest, MarkCacheFileAsMountedAndUnmounted) {
    669   ASSERT_TRUE(LoadFullResourceList());
    670 
    671   base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
    672   scoped_ptr<ResourceEntry> entry(GetResourceEntrySync(file_in_root));
    673   ASSERT_TRUE(entry);
    674 
    675   // Write to cache.
    676   ASSERT_EQ(FILE_ERROR_OK, cache_->Store(
    677       entry->local_id(),
    678       entry->file_specific_info().md5(),
    679       google_apis::test_util::GetTestFilePath("gdata/root_feed.json"),
    680       internal::FileCache::FILE_OPERATION_COPY));
    681 
    682   // Test for mounting.
    683   FileError error = FILE_ERROR_FAILED;
    684   base::FilePath file_path;
    685   file_system_->MarkCacheFileAsMounted(
    686       file_in_root,
    687       google_apis::test_util::CreateCopyResultCallback(&error, &file_path));
    688   test_util::RunBlockingPoolTask();
    689   EXPECT_EQ(FILE_ERROR_OK, error);
    690 
    691   // Cannot remove a cache entry while it's being mounted.
    692   EXPECT_EQ(FILE_ERROR_IN_USE, cache_->Remove(entry->local_id()));
    693 
    694   // Test for unmounting.
    695   error = FILE_ERROR_FAILED;
    696   file_system_->MarkCacheFileAsUnmounted(
    697       file_path,
    698       google_apis::test_util::CreateCopyResultCallback(&error));
    699   test_util::RunBlockingPoolTask();
    700   EXPECT_EQ(FILE_ERROR_OK, error);
    701 
    702   // Now able to remove the cache entry.
    703   EXPECT_EQ(FILE_ERROR_OK, cache_->Remove(entry->local_id()));
    704 }
    705 
    706 TEST_F(FileSystemTest, GetShareUrl) {
    707   ASSERT_TRUE(LoadFullResourceList());
    708 
    709   const base::FilePath kFileInRoot(FILE_PATH_LITERAL("drive/root/File 1.txt"));
    710   const GURL kEmbedOrigin("chrome-extension://test-id");
    711 
    712   // Try to fetch the URL for the sharing dialog.
    713   FileError error = FILE_ERROR_FAILED;
    714   GURL share_url;
    715   file_system_->GetShareUrl(
    716       kFileInRoot,
    717       kEmbedOrigin,
    718       google_apis::test_util::CreateCopyResultCallback(&error, &share_url));
    719   test_util::RunBlockingPoolTask();
    720 
    721   // Verify the share url to the sharing dialog.
    722   EXPECT_EQ(FILE_ERROR_OK, error);
    723   EXPECT_EQ(GURL("https://file_link_share/"), share_url);
    724 }
    725 
    726 TEST_F(FileSystemTest, GetShareUrlNotAvailable) {
    727   ASSERT_TRUE(LoadFullResourceList());
    728 
    729   const base::FilePath kFileInRoot(
    730       FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt"));
    731   const GURL kEmbedOrigin("chrome-extension://test-id");
    732 
    733   // Try to fetch the URL for the sharing dialog.
    734   FileError error = FILE_ERROR_FAILED;
    735   GURL share_url;
    736 
    737   file_system_->GetShareUrl(
    738       kFileInRoot,
    739       kEmbedOrigin,
    740       google_apis::test_util::CreateCopyResultCallback(&error, &share_url));
    741   test_util::RunBlockingPoolTask();
    742 
    743   // Verify the error and the share url, which should be empty.
    744   EXPECT_EQ(FILE_ERROR_FAILED, error);
    745   EXPECT_TRUE(share_url.is_empty());
    746 }
    747 
    748 }   // namespace drive
    749