Home | History | Annotate | Download | only in drive
      1 // Copyright 2013 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/change_list_processor.h"
      6 
      7 #include "base/files/scoped_temp_dir.h"
      8 #include "base/message_loop/message_loop_proxy.h"
      9 #include "base/values.h"
     10 #include "chrome/browser/chromeos/drive/drive.pb.h"
     11 #include "chrome/browser/chromeos/drive/fake_free_disk_space_getter.h"
     12 #include "chrome/browser/chromeos/drive/file_cache.h"
     13 #include "chrome/browser/chromeos/drive/file_system_util.h"
     14 #include "chrome/browser/chromeos/drive/resource_metadata.h"
     15 #include "chrome/browser/chromeos/drive/test_util.h"
     16 #include "content/public/test/test_browser_thread_bundle.h"
     17 #include "google_apis/drive/drive_api_parser.h"
     18 #include "google_apis/drive/gdata_wapi_parser.h"
     19 #include "google_apis/drive/test_util.h"
     20 #include "testing/gtest/include/gtest/gtest.h"
     21 
     22 namespace drive {
     23 namespace internal {
     24 
     25 namespace {
     26 
     27 const int64 kBaseResourceListChangestamp = 123;
     28 const char kRootId[] = "fake_root";
     29 
     30 enum FileOrDirectory {
     31   FILE,
     32   DIRECTORY,
     33 };
     34 
     35 struct EntryExpectation {
     36   std::string path;
     37   std::string id;
     38   std::string parent_id;
     39   FileOrDirectory type;
     40 };
     41 
     42 // Returns a basic change list which contains some files and directories.
     43 ScopedVector<ChangeList> CreateBaseChangeList() {
     44   ScopedVector<ChangeList> change_lists;
     45   change_lists.push_back(new ChangeList);
     46 
     47   // Add directories to the change list.
     48   ResourceEntry directory;
     49   directory.mutable_file_info()->set_is_directory(true);
     50 
     51   directory.set_title("Directory 1");
     52   directory.set_resource_id("folder:1_folder_resource_id");
     53   change_lists[0]->mutable_entries()->push_back(directory);
     54   change_lists[0]->mutable_parent_resource_ids()->push_back(kRootId);
     55 
     56   directory.set_title("Sub Directory Folder");
     57   directory.set_resource_id("folder:sub_dir_folder_resource_id");
     58   change_lists[0]->mutable_entries()->push_back(directory);
     59   change_lists[0]->mutable_parent_resource_ids()->push_back(
     60       "folder:1_folder_resource_id");
     61 
     62   directory.set_title("Sub Sub Directory Folder");
     63   directory.set_resource_id("folder:sub_sub_directory_folder_id");
     64   change_lists[0]->mutable_entries()->push_back(directory);
     65   change_lists[0]->mutable_parent_resource_ids()->push_back(
     66       "folder:sub_dir_folder_resource_id");
     67 
     68   directory.set_title("Directory 2 excludeDir-test");
     69   directory.set_resource_id("folder:sub_dir_folder_2_self_link");
     70   change_lists[0]->mutable_entries()->push_back(directory);
     71   change_lists[0]->mutable_parent_resource_ids()->push_back(kRootId);
     72 
     73   // Add files to the change list.
     74   ResourceEntry file;
     75 
     76   file.set_title("File 1.txt");
     77   file.set_resource_id("file:2_file_resource_id");
     78   change_lists[0]->mutable_entries()->push_back(file);
     79   change_lists[0]->mutable_parent_resource_ids()->push_back(kRootId);
     80 
     81   file.set_title("SubDirectory File 1.txt");
     82   file.set_resource_id("file:subdirectory_file_1_id");
     83   change_lists[0]->mutable_entries()->push_back(file);
     84   change_lists[0]->mutable_parent_resource_ids()->push_back(
     85       "folder:1_folder_resource_id");
     86 
     87   file.set_title("Orphan File 1.txt");
     88   file.set_resource_id("file:1_orphanfile_resource_id");
     89   change_lists[0]->mutable_entries()->push_back(file);
     90   change_lists[0]->mutable_parent_resource_ids()->push_back("");
     91 
     92   change_lists[0]->set_largest_changestamp(kBaseResourceListChangestamp);
     93   return change_lists.Pass();
     94 }
     95 
     96 class ChangeListProcessorTest : public testing::Test {
     97  protected:
     98   virtual void SetUp() OVERRIDE {
     99     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
    100 
    101     metadata_storage_.reset(new ResourceMetadataStorage(
    102         temp_dir_.path(), base::MessageLoopProxy::current().get()));
    103     ASSERT_TRUE(metadata_storage_->Initialize());
    104 
    105     fake_free_disk_space_getter_.reset(new FakeFreeDiskSpaceGetter);
    106     cache_.reset(new FileCache(metadata_storage_.get(),
    107                                temp_dir_.path(),
    108                                base::MessageLoopProxy::current().get(),
    109                                fake_free_disk_space_getter_.get()));
    110     ASSERT_TRUE(cache_->Initialize());
    111 
    112     metadata_.reset(new internal::ResourceMetadata(
    113         metadata_storage_.get(), cache_.get(),
    114         base::MessageLoopProxy::current()));
    115     ASSERT_EQ(FILE_ERROR_OK, metadata_->Initialize());
    116   }
    117 
    118   // Applies the |changes| to |metadata_| as a full resource list of changestamp
    119   // |kBaseResourceListChangestamp|.
    120   FileError ApplyFullResourceList(ScopedVector<ChangeList> changes) {
    121     scoped_ptr<google_apis::AboutResource> about_resource(
    122         new google_apis::AboutResource);
    123     about_resource->set_largest_change_id(kBaseResourceListChangestamp);
    124     about_resource->set_root_folder_id(kRootId);
    125 
    126     ChangeListProcessor processor(metadata_.get());
    127     return processor.Apply(about_resource.Pass(),
    128                            changes.Pass(),
    129                            false /* is_delta_update */);
    130   }
    131 
    132   // Applies the |changes| to |metadata_| as a delta update. Delta changelists
    133   // should contain their changestamp in themselves.
    134   FileError ApplyChangeList(ScopedVector<ChangeList> changes,
    135                             std::set<base::FilePath>* changed_dirs) {
    136     scoped_ptr<google_apis::AboutResource> about_resource(
    137         new google_apis::AboutResource);
    138     about_resource->set_largest_change_id(kBaseResourceListChangestamp);
    139     about_resource->set_root_folder_id(kRootId);
    140 
    141     ChangeListProcessor processor(metadata_.get());
    142     FileError error = processor.Apply(about_resource.Pass(),
    143                                       changes.Pass(),
    144                                       true /* is_delta_update */);
    145     *changed_dirs = processor.changed_dirs();
    146     return error;
    147   }
    148 
    149   // Gets the resource entry for the path from |metadata_| synchronously.
    150   // Returns null if the entry does not exist.
    151   scoped_ptr<ResourceEntry> GetResourceEntry(const std::string& path) {
    152     scoped_ptr<ResourceEntry> entry(new ResourceEntry);
    153     FileError error = metadata_->GetResourceEntryByPath(
    154         base::FilePath::FromUTF8Unsafe(path), entry.get());
    155     if (error != FILE_ERROR_OK)
    156       entry.reset();
    157     return entry.Pass();
    158   }
    159 
    160   content::TestBrowserThreadBundle thread_bundle_;
    161   base::ScopedTempDir temp_dir_;
    162   scoped_ptr<ResourceMetadataStorage,
    163              test_util::DestroyHelperForTests> metadata_storage_;
    164   scoped_ptr<FakeFreeDiskSpaceGetter> fake_free_disk_space_getter_;
    165   scoped_ptr<FileCache, test_util::DestroyHelperForTests> cache_;
    166   scoped_ptr<ResourceMetadata, test_util::DestroyHelperForTests> metadata_;
    167 };
    168 
    169 }  // namespace
    170 
    171 TEST_F(ChangeListProcessorTest, ApplyFullResourceList) {
    172   EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList()));
    173 
    174   const EntryExpectation kExpected[] = {
    175       // Root files
    176       {"drive/root", kRootId, "", DIRECTORY},
    177       {"drive/root/File 1.txt",
    178           "file:2_file_resource_id", kRootId, FILE},
    179       // Subdirectory files
    180       {"drive/root/Directory 1",
    181           "folder:1_folder_resource_id", kRootId, DIRECTORY},
    182       {"drive/root/Directory 1/SubDirectory File 1.txt",
    183           "file:subdirectory_file_1_id", "folder:1_folder_resource_id", FILE},
    184       {"drive/root/Directory 2 excludeDir-test",
    185           "folder:sub_dir_folder_2_self_link", kRootId, DIRECTORY},
    186       // Deeper
    187       {"drive/root/Directory 1/Sub Directory Folder",
    188           "folder:sub_dir_folder_resource_id",
    189           "folder:1_folder_resource_id", DIRECTORY},
    190       {"drive/root/Directory 1/Sub Directory Folder/Sub Sub Directory Folder",
    191           "folder:sub_sub_directory_folder_id",
    192           "folder:sub_dir_folder_resource_id", DIRECTORY},
    193       // Orphan
    194       {"drive/other/Orphan File 1.txt", "file:1_orphanfile_resource_id",
    195            "", FILE},
    196   };
    197 
    198   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kExpected); ++i) {
    199     scoped_ptr<ResourceEntry> entry = GetResourceEntry(kExpected[i].path);
    200     ASSERT_TRUE(entry) << "for path: " << kExpected[i].path;
    201     EXPECT_EQ(kExpected[i].id, entry->resource_id());
    202 
    203     ResourceEntry parent_entry;
    204     EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryById(
    205         entry->parent_local_id(), &parent_entry));
    206     EXPECT_EQ(kExpected[i].parent_id, parent_entry.resource_id());
    207     EXPECT_EQ(kExpected[i].type,
    208               entry->file_info().is_directory() ? DIRECTORY : FILE);
    209   }
    210 
    211   int64 changestamp = 0;
    212   EXPECT_EQ(FILE_ERROR_OK, metadata_->GetLargestChangestamp(&changestamp));
    213   EXPECT_EQ(kBaseResourceListChangestamp, changestamp);
    214 }
    215 
    216 TEST_F(ChangeListProcessorTest, DeltaFileAddedInNewDirectory) {
    217   ScopedVector<ChangeList> change_lists;
    218   change_lists.push_back(new ChangeList);
    219 
    220   ResourceEntry new_folder;
    221   new_folder.set_resource_id("folder:new_folder_resource_id");
    222   new_folder.set_title("New Directory");
    223   new_folder.mutable_file_info()->set_is_directory(true);
    224   change_lists[0]->mutable_entries()->push_back(new_folder);
    225   change_lists[0]->mutable_parent_resource_ids()->push_back(kRootId);
    226 
    227   ResourceEntry new_file;
    228   new_file.set_resource_id("document:file_added_in_new_dir_id");
    229   new_file.set_title("File in new dir.txt");
    230   change_lists[0]->mutable_entries()->push_back(new_file);
    231   change_lists[0]->mutable_parent_resource_ids()->push_back(
    232       new_folder.resource_id());
    233 
    234   change_lists[0]->set_largest_changestamp(16730);
    235 
    236   // Apply the changelist and check the effect.
    237   EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList()));
    238   std::set<base::FilePath> changed_dirs;
    239   EXPECT_EQ(FILE_ERROR_OK, ApplyChangeList(change_lists.Pass(), &changed_dirs));
    240 
    241   int64 changestamp = 0;
    242   EXPECT_EQ(FILE_ERROR_OK, metadata_->GetLargestChangestamp(&changestamp));
    243   EXPECT_EQ(16730, changestamp);
    244   EXPECT_TRUE(GetResourceEntry("drive/root/New Directory"));
    245   EXPECT_TRUE(GetResourceEntry(
    246       "drive/root/New Directory/File in new dir.txt"));
    247 
    248   EXPECT_EQ(2U, changed_dirs.size());
    249   EXPECT_TRUE(changed_dirs.count(
    250       base::FilePath::FromUTF8Unsafe("drive/root")));
    251   EXPECT_TRUE(changed_dirs.count(
    252       base::FilePath::FromUTF8Unsafe("drive/root/New Directory")));
    253 }
    254 
    255 TEST_F(ChangeListProcessorTest, DeltaDirMovedFromRootToDirectory) {
    256   ScopedVector<ChangeList> change_lists;
    257   change_lists.push_back(new ChangeList);
    258 
    259   ResourceEntry entry;
    260   entry.set_resource_id("folder:1_folder_resource_id");
    261   entry.set_title("Directory 1");
    262   entry.mutable_file_info()->set_is_directory(true);
    263   change_lists[0]->mutable_entries()->push_back(entry);
    264   change_lists[0]->mutable_parent_resource_ids()->push_back(
    265       "folder:sub_dir_folder_2_self_link");
    266 
    267   change_lists[0]->set_largest_changestamp(16809);
    268 
    269   // Apply the changelist and check the effect.
    270   EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList()));
    271   std::set<base::FilePath> changed_dirs;
    272   EXPECT_EQ(FILE_ERROR_OK, ApplyChangeList(change_lists.Pass(), &changed_dirs));
    273 
    274   int64 changestamp = 0;
    275   EXPECT_EQ(FILE_ERROR_OK, metadata_->GetLargestChangestamp(&changestamp));
    276   EXPECT_EQ(16809, changestamp);
    277   EXPECT_FALSE(GetResourceEntry("drive/root/Directory 1"));
    278   EXPECT_TRUE(GetResourceEntry(
    279       "drive/root/Directory 2 excludeDir-test/Directory 1"));
    280 
    281   EXPECT_EQ(4U, changed_dirs.size());
    282   EXPECT_TRUE(changed_dirs.count(
    283       base::FilePath::FromUTF8Unsafe("drive/root")));
    284   EXPECT_TRUE(changed_dirs.count(
    285       base::FilePath::FromUTF8Unsafe("drive/root/Directory 1")));
    286   EXPECT_TRUE(changed_dirs.count(
    287       base::FilePath::FromUTF8Unsafe(
    288           "drive/root/Directory 2 excludeDir-test")));
    289   EXPECT_TRUE(changed_dirs.count(
    290       base::FilePath::FromUTF8Unsafe(
    291           "drive/root/Directory 2 excludeDir-test/Directory 1")));
    292 }
    293 
    294 TEST_F(ChangeListProcessorTest, DeltaFileMovedFromDirectoryToRoot) {
    295   ScopedVector<ChangeList> change_lists;
    296   change_lists.push_back(new ChangeList);
    297 
    298   ResourceEntry entry;
    299   entry.set_resource_id("file:subdirectory_file_1_id");
    300   entry.set_title("SubDirectory File 1.txt");
    301   change_lists[0]->mutable_entries()->push_back(entry);
    302   change_lists[0]->mutable_parent_resource_ids()->push_back(kRootId);
    303 
    304   change_lists[0]->set_largest_changestamp(16815);
    305 
    306   // Apply the changelist and check the effect.
    307   EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList()));
    308   std::set<base::FilePath> changed_dirs;
    309   EXPECT_EQ(FILE_ERROR_OK, ApplyChangeList(change_lists.Pass(), &changed_dirs));
    310 
    311   int64 changestamp = 0;
    312   EXPECT_EQ(FILE_ERROR_OK, metadata_->GetLargestChangestamp(&changestamp));
    313   EXPECT_EQ(16815, changestamp);
    314   EXPECT_FALSE(GetResourceEntry(
    315       "drive/root/Directory 1/SubDirectory File 1.txt"));
    316   EXPECT_TRUE(GetResourceEntry("drive/root/SubDirectory File 1.txt"));
    317 
    318   EXPECT_EQ(2U, changed_dirs.size());
    319   EXPECT_TRUE(changed_dirs.count(
    320       base::FilePath::FromUTF8Unsafe("drive/root")));
    321   EXPECT_TRUE(changed_dirs.count(
    322       base::FilePath::FromUTF8Unsafe("drive/root/Directory 1")));
    323 }
    324 
    325 TEST_F(ChangeListProcessorTest, DeltaFileRenamedInDirectory) {
    326   ScopedVector<ChangeList> change_lists;
    327   change_lists.push_back(new ChangeList);
    328 
    329   ResourceEntry entry;
    330   entry.set_resource_id("file:subdirectory_file_1_id");
    331   entry.set_title("New SubDirectory File 1.txt");
    332   change_lists[0]->mutable_entries()->push_back(entry);
    333   change_lists[0]->mutable_parent_resource_ids()->push_back(
    334       "folder:1_folder_resource_id");
    335 
    336   change_lists[0]->set_largest_changestamp(16767);
    337 
    338   // Apply the changelist and check the effect.
    339   EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList()));
    340   std::set<base::FilePath> changed_dirs;
    341   EXPECT_EQ(FILE_ERROR_OK, ApplyChangeList(change_lists.Pass(), &changed_dirs));
    342 
    343   int64 changestamp = 0;
    344   EXPECT_EQ(FILE_ERROR_OK, metadata_->GetLargestChangestamp(&changestamp));
    345   EXPECT_EQ(16767, changestamp);
    346   EXPECT_FALSE(GetResourceEntry(
    347       "drive/root/Directory 1/SubDirectory File 1.txt"));
    348   EXPECT_TRUE(GetResourceEntry(
    349       "drive/root/Directory 1/New SubDirectory File 1.txt"));
    350 
    351   EXPECT_EQ(1U, changed_dirs.size());
    352   EXPECT_TRUE(changed_dirs.count(
    353       base::FilePath::FromUTF8Unsafe("drive/root/Directory 1")));
    354 }
    355 
    356 TEST_F(ChangeListProcessorTest, DeltaAddAndDeleteFileInRoot) {
    357   // Create ChangeList to add a file.
    358   ScopedVector<ChangeList> change_lists;
    359   change_lists.push_back(new ChangeList);
    360 
    361   ResourceEntry entry;
    362   entry.set_resource_id("document:added_in_root_id");
    363   entry.set_title("Added file.txt");
    364   change_lists[0]->mutable_entries()->push_back(entry);
    365   change_lists[0]->mutable_parent_resource_ids()->push_back(kRootId);
    366 
    367   change_lists[0]->set_largest_changestamp(16683);
    368 
    369   // Apply.
    370   EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList()));
    371   std::set<base::FilePath> changed_dirs;
    372   EXPECT_EQ(FILE_ERROR_OK, ApplyChangeList(change_lists.Pass(), &changed_dirs));
    373   int64 changestamp = 0;
    374   EXPECT_EQ(FILE_ERROR_OK, metadata_->GetLargestChangestamp(&changestamp));
    375   EXPECT_EQ(16683, changestamp);
    376   EXPECT_TRUE(GetResourceEntry("drive/root/Added file.txt"));
    377   EXPECT_EQ(1U, changed_dirs.size());
    378   EXPECT_TRUE(changed_dirs.count(
    379       base::FilePath::FromUTF8Unsafe("drive/root")));
    380 
    381   // Create ChangeList to delete the file.
    382   change_lists.push_back(new ChangeList);
    383 
    384   entry.set_deleted(true);
    385   change_lists[0]->mutable_entries()->push_back(entry);
    386   change_lists[0]->mutable_parent_resource_ids()->push_back(kRootId);
    387 
    388   change_lists[0]->set_largest_changestamp(16687);
    389 
    390   // Apply.
    391   EXPECT_EQ(FILE_ERROR_OK, ApplyChangeList(change_lists.Pass(), &changed_dirs));
    392   EXPECT_EQ(FILE_ERROR_OK, metadata_->GetLargestChangestamp(&changestamp));
    393   EXPECT_EQ(16687, changestamp);
    394   EXPECT_FALSE(GetResourceEntry("drive/root/Added file.txt"));
    395   EXPECT_EQ(1U, changed_dirs.size());
    396   EXPECT_TRUE(changed_dirs.count(
    397       base::FilePath::FromUTF8Unsafe("drive/root")));
    398 }
    399 
    400 
    401 TEST_F(ChangeListProcessorTest, DeltaAddAndDeleteFileFromExistingDirectory) {
    402   // Create ChangeList to add a file.
    403   ScopedVector<ChangeList> change_lists;
    404   change_lists.push_back(new ChangeList);
    405 
    406   ResourceEntry entry;
    407   entry.set_resource_id("document:added_in_root_id");
    408   entry.set_title("Added file.txt");
    409   change_lists[0]->mutable_entries()->push_back(entry);
    410   change_lists[0]->mutable_parent_resource_ids()->push_back(
    411       "folder:1_folder_resource_id");
    412 
    413   change_lists[0]->set_largest_changestamp(16730);
    414 
    415   // Apply.
    416   EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList()));
    417   std::set<base::FilePath> changed_dirs;
    418   EXPECT_EQ(FILE_ERROR_OK, ApplyChangeList(change_lists.Pass(), &changed_dirs));
    419   int64 changestamp = 0;
    420   EXPECT_EQ(FILE_ERROR_OK, metadata_->GetLargestChangestamp(&changestamp));
    421   EXPECT_EQ(16730, changestamp);
    422   EXPECT_TRUE(GetResourceEntry("drive/root/Directory 1/Added file.txt"));
    423 
    424   EXPECT_EQ(1U, changed_dirs.size());
    425   EXPECT_TRUE(changed_dirs.count(
    426       base::FilePath::FromUTF8Unsafe("drive/root/Directory 1")));
    427 
    428   // Create ChangeList to delete the file.
    429   change_lists.push_back(new ChangeList);
    430 
    431   entry.set_deleted(true);
    432   change_lists[0]->mutable_entries()->push_back(entry);
    433   change_lists[0]->mutable_parent_resource_ids()->push_back(
    434       "folder:1_folder_resource_id");
    435 
    436   change_lists[0]->set_largest_changestamp(16770);
    437 
    438   // Apply.
    439   EXPECT_EQ(FILE_ERROR_OK, ApplyChangeList(change_lists.Pass(), &changed_dirs));
    440   EXPECT_EQ(FILE_ERROR_OK, metadata_->GetLargestChangestamp(&changestamp));
    441   EXPECT_EQ(16770, changestamp);
    442   EXPECT_FALSE(GetResourceEntry("drive/root/Directory 1/Added file.txt"));
    443 
    444   EXPECT_EQ(1U, changed_dirs.size());
    445   EXPECT_TRUE(changed_dirs.count(
    446       base::FilePath::FromUTF8Unsafe("drive/root/Directory 1")));
    447 }
    448 
    449 TEST_F(ChangeListProcessorTest, DeltaAddFileToNewButDeletedDirectory) {
    450   // Create a change which contains the following updates:
    451   // 1) A new PDF file is added to a new directory
    452   // 2) but the new directory is marked "deleted" (i.e. moved to Trash)
    453   // Hence, the PDF file should be just ignored.
    454   ScopedVector<ChangeList> change_lists;
    455   change_lists.push_back(new ChangeList);
    456 
    457   ResourceEntry file;
    458   file.set_resource_id("pdf:file_added_in_deleted_id");
    459   file.set_title("new_pdf_file.pdf");
    460   file.set_deleted(true);
    461   change_lists[0]->mutable_entries()->push_back(file);
    462   change_lists[0]->mutable_parent_resource_ids()->push_back(
    463       "folder:new_folder_resource_id");
    464 
    465   ResourceEntry directory;
    466   directory.set_resource_id("folder:new_folder_resource_id");
    467   directory.set_title("New Directory");
    468   directory.mutable_file_info()->set_is_directory(true);
    469   directory.set_deleted(true);
    470   change_lists[0]->mutable_entries()->push_back(directory);
    471   change_lists[0]->mutable_parent_resource_ids()->push_back(kRootId);
    472 
    473   change_lists[0]->set_largest_changestamp(16730);
    474 
    475   // Apply the changelist and check the effect.
    476   EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList()));
    477   std::set<base::FilePath> changed_dirs;
    478   EXPECT_EQ(FILE_ERROR_OK, ApplyChangeList(change_lists.Pass(), &changed_dirs));
    479 
    480   int64 changestamp = 0;
    481   EXPECT_EQ(FILE_ERROR_OK, metadata_->GetLargestChangestamp(&changestamp));
    482   EXPECT_EQ(16730, changestamp);
    483   EXPECT_FALSE(GetResourceEntry("drive/root/New Directory/new_pdf_file.pdf"));
    484 
    485   EXPECT_TRUE(changed_dirs.empty());
    486 }
    487 
    488 TEST_F(ChangeListProcessorTest, RefreshDirectory) {
    489   // Prepare metadata.
    490   EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList()));
    491 
    492   // Create change list.
    493   scoped_ptr<ChangeList> change_list(new ChangeList);
    494 
    495   // Add a new file to the change list.
    496   ResourceEntry new_file;
    497   new_file.set_title("new_file");
    498   new_file.set_resource_id("new_file_id");
    499   change_list->mutable_entries()->push_back(new_file);
    500   change_list->mutable_parent_resource_ids()->push_back(kRootId);
    501 
    502   // Add "Directory 1" to the map with a new name.
    503   ResourceEntry dir1;
    504   EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath(
    505       util::GetDriveMyDriveRootPath().AppendASCII("Directory 1"), &dir1));
    506   dir1.set_title(dir1.title() + " (renamed)");
    507   change_list->mutable_entries()->push_back(dir1);
    508   change_list->mutable_parent_resource_ids()->push_back(kRootId);
    509 
    510   // Update the directory with the map.
    511   ResourceEntry root;
    512   EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath(
    513       util::GetDriveMyDriveRootPath(), &root));
    514   const int64 kNewChangestamp = 12345;
    515   ResourceEntryVector refreshed_entries;
    516   EXPECT_EQ(FILE_ERROR_OK, ChangeListProcessor::RefreshDirectory(
    517       metadata_.get(),
    518       DirectoryFetchInfo(root.local_id(), kRootId, kNewChangestamp),
    519       change_list.Pass(),
    520       &refreshed_entries));
    521 
    522   // "new_file" should be added.
    523   ResourceEntry entry;
    524   EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath(
    525       util::GetDriveMyDriveRootPath().AppendASCII(new_file.title()), &entry));
    526 
    527   // "Directory 1" should be renamed.
    528   EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath(
    529       util::GetDriveMyDriveRootPath().AppendASCII(dir1.title()), &entry));
    530 }
    531 
    532 TEST_F(ChangeListProcessorTest, RefreshDirectory_WrongParentId) {
    533   // Prepare metadata.
    534   EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList()));
    535 
    536   // Create change list and add a new file to it.
    537   scoped_ptr<ChangeList> change_list(new ChangeList);
    538   ResourceEntry new_file;
    539   new_file.set_title("new_file");
    540   new_file.set_resource_id("new_file_id");
    541   // This entry should not be added because the parent ID does not match.
    542   change_list->mutable_parent_resource_ids()->push_back(
    543       "some-random-resource-id");
    544   change_list->mutable_entries()->push_back(new_file);
    545 
    546 
    547   // Update the directory.
    548   ResourceEntry root;
    549   EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath(
    550       util::GetDriveMyDriveRootPath(), &root));
    551   const int64 kNewChangestamp = 12345;
    552   ResourceEntryVector refreshed_entries;
    553   EXPECT_EQ(FILE_ERROR_OK, ChangeListProcessor::RefreshDirectory(
    554       metadata_.get(),
    555       DirectoryFetchInfo(root.local_id(), kRootId, kNewChangestamp),
    556       change_list.Pass(),
    557       &refreshed_entries));
    558 
    559   // "new_file" should not be added.
    560   ResourceEntry entry;
    561   EXPECT_EQ(FILE_ERROR_NOT_FOUND, metadata_->GetResourceEntryByPath(
    562       util::GetDriveMyDriveRootPath().AppendASCII(new_file.title()), &entry));
    563 }
    564 
    565 TEST_F(ChangeListProcessorTest, SharedFilesWithNoParentInFeed) {
    566   // Prepare metadata.
    567   EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList()));
    568 
    569   // Create change lists.
    570   ScopedVector<ChangeList> change_lists;
    571   change_lists.push_back(new ChangeList);
    572 
    573   // Add a new file with non-existing parent resource id to the change lists.
    574   ResourceEntry new_file;
    575   new_file.set_title("new_file");
    576   new_file.set_resource_id("new_file_id");
    577   change_lists[0]->mutable_entries()->push_back(new_file);
    578   change_lists[0]->mutable_parent_resource_ids()->push_back("nonexisting");
    579   change_lists[0]->set_largest_changestamp(kBaseResourceListChangestamp + 1);
    580 
    581   std::set<base::FilePath> changed_dirs;
    582   EXPECT_EQ(FILE_ERROR_OK, ApplyChangeList(change_lists.Pass(), &changed_dirs));
    583 
    584   // "new_file" should be added under drive/other.
    585   ResourceEntry entry;
    586   EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath(
    587       util::GetDriveGrandRootPath().AppendASCII("other/new_file"), &entry));
    588 }
    589 
    590 TEST_F(ChangeListProcessorTest, ModificationDate) {
    591   // Prepare metadata.
    592   EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList()));
    593 
    594   // Create change lists with a new file.
    595   ScopedVector<ChangeList> change_lists;
    596   change_lists.push_back(new ChangeList);
    597 
    598   const base::Time now = base::Time::Now();
    599   ResourceEntry new_file_remote;
    600   new_file_remote.set_title("new_file_remote");
    601   new_file_remote.set_resource_id("new_file_id");
    602   new_file_remote.set_modification_date(now.ToInternalValue());
    603 
    604   change_lists[0]->mutable_entries()->push_back(new_file_remote);
    605   change_lists[0]->mutable_parent_resource_ids()->push_back(kRootId);
    606   change_lists[0]->set_largest_changestamp(kBaseResourceListChangestamp + 1);
    607 
    608   // Add the same file locally, but with a different name, a dirty metadata
    609   // state, and a newer modification date.
    610   ResourceEntry root;
    611   EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath(
    612       util::GetDriveMyDriveRootPath(), &root));
    613 
    614   ResourceEntry new_file_local;
    615   new_file_local.set_resource_id(new_file_remote.resource_id());
    616   new_file_local.set_parent_local_id(root.local_id());
    617   new_file_local.set_title("new_file_local");
    618   new_file_local.set_metadata_edit_state(ResourceEntry::DIRTY);
    619   new_file_local.set_modification_date(
    620       (now + base::TimeDelta::FromSeconds(1)).ToInternalValue());
    621   std::string local_id;
    622   EXPECT_EQ(FILE_ERROR_OK, metadata_->AddEntry(new_file_local, &local_id));
    623 
    624   // Apply the change.
    625   std::set<base::FilePath> changed_dirs;
    626   EXPECT_EQ(FILE_ERROR_OK, ApplyChangeList(change_lists.Pass(), &changed_dirs));
    627 
    628   // The change is rejected due to the old modification date.
    629   ResourceEntry entry;
    630   EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryById(local_id, &entry));
    631   EXPECT_EQ(new_file_local.title(), entry.title());
    632 }
    633 
    634 }  // namespace internal
    635 }  // namespace drive
    636