Home | History | Annotate | Download | only in sync
      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/sync/entry_update_performer.h"
      6 
      7 #include "base/callback_helpers.h"
      8 #include "base/files/file_util.h"
      9 #include "base/md5.h"
     10 #include "base/task_runner_util.h"
     11 #include "chrome/browser/chromeos/drive/file_cache.h"
     12 #include "chrome/browser/chromeos/drive/file_system/download_operation.h"
     13 #include "chrome/browser/chromeos/drive/file_system/operation_test_base.h"
     14 #include "chrome/browser/chromeos/drive/job_scheduler.h"
     15 #include "chrome/browser/chromeos/drive/resource_metadata.h"
     16 #include "chrome/browser/drive/drive_api_util.h"
     17 #include "chrome/browser/drive/fake_drive_service.h"
     18 #include "content/public/test/test_utils.h"
     19 #include "google_apis/drive/drive_api_parser.h"
     20 #include "google_apis/drive/test_util.h"
     21 #include "testing/gtest/include/gtest/gtest.h"
     22 
     23 namespace drive {
     24 namespace internal {
     25 
     26 class EntryUpdatePerformerTest : public file_system::OperationTestBase {
     27  protected:
     28   virtual void SetUp() OVERRIDE {
     29     OperationTestBase::SetUp();
     30     performer_.reset(new EntryUpdatePerformer(blocking_task_runner(),
     31                                               delegate(),
     32                                               scheduler(),
     33                                               metadata(),
     34                                               cache(),
     35                                               loader_controller()));
     36   }
     37 
     38   // Stores |content| to the cache and mark it as dirty.
     39   FileError StoreAndMarkDirty(const std::string& local_id,
     40                               const std::string& content) {
     41     base::FilePath path;
     42     if (!base::CreateTemporaryFileInDir(temp_dir(), &path) ||
     43         !google_apis::test_util::WriteStringToFile(path, content))
     44       return FILE_ERROR_FAILED;
     45 
     46     // Store the file to cache.
     47     FileError error = FILE_ERROR_FAILED;
     48     base::PostTaskAndReplyWithResult(
     49         blocking_task_runner(),
     50         FROM_HERE,
     51         base::Bind(&FileCache::Store,
     52                    base::Unretained(cache()),
     53                    local_id, std::string(), path,
     54                    FileCache::FILE_OPERATION_COPY),
     55         google_apis::test_util::CreateCopyResultCallback(&error));
     56     content::RunAllBlockingPoolTasksUntilIdle();
     57     return error;
     58   }
     59 
     60   scoped_ptr<EntryUpdatePerformer> performer_;
     61 };
     62 
     63 TEST_F(EntryUpdatePerformerTest, UpdateEntry) {
     64   base::FilePath src_path(
     65       FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt"));
     66   base::FilePath dest_path(
     67       FILE_PATH_LITERAL("drive/root/Directory 1/Sub Directory Folder"));
     68 
     69   ResourceEntry src_entry, dest_entry;
     70   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &src_entry));
     71   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path, &dest_entry));
     72 
     73   // Update local entry.
     74   base::Time new_last_modified = base::Time::FromInternalValue(
     75       src_entry.file_info().last_modified()) + base::TimeDelta::FromSeconds(1);
     76   base::Time new_last_accessed = base::Time::FromInternalValue(
     77       src_entry.file_info().last_accessed()) + base::TimeDelta::FromSeconds(2);
     78 
     79   src_entry.set_parent_local_id(dest_entry.local_id());
     80   src_entry.set_title("Moved" + src_entry.title());
     81   src_entry.mutable_file_info()->set_last_modified(
     82       new_last_modified.ToInternalValue());
     83   src_entry.mutable_file_info()->set_last_accessed(
     84       new_last_accessed.ToInternalValue());
     85   src_entry.set_metadata_edit_state(ResourceEntry::DIRTY);
     86 
     87   FileError error = FILE_ERROR_FAILED;
     88   base::PostTaskAndReplyWithResult(
     89       blocking_task_runner(),
     90       FROM_HERE,
     91       base::Bind(&ResourceMetadata::RefreshEntry,
     92                  base::Unretained(metadata()),
     93                  src_entry),
     94       google_apis::test_util::CreateCopyResultCallback(&error));
     95   content::RunAllBlockingPoolTasksUntilIdle();
     96   EXPECT_EQ(FILE_ERROR_OK, error);
     97 
     98   // Perform server side update.
     99   error = FILE_ERROR_FAILED;
    100   performer_->UpdateEntry(
    101       src_entry.local_id(),
    102       ClientContext(USER_INITIATED),
    103       google_apis::test_util::CreateCopyResultCallback(&error));
    104   content::RunAllBlockingPoolTasksUntilIdle();
    105   EXPECT_EQ(FILE_ERROR_OK, error);
    106 
    107   // Verify the file is updated on the server.
    108   google_apis::GDataErrorCode gdata_error = google_apis::GDATA_OTHER_ERROR;
    109   scoped_ptr<google_apis::FileResource> gdata_entry;
    110   fake_service()->GetFileResource(
    111       src_entry.resource_id(),
    112       google_apis::test_util::CreateCopyResultCallback(&gdata_error,
    113                                                        &gdata_entry));
    114   content::RunAllBlockingPoolTasksUntilIdle();
    115   EXPECT_EQ(google_apis::HTTP_SUCCESS, gdata_error);
    116   ASSERT_TRUE(gdata_entry);
    117 
    118   EXPECT_EQ(src_entry.title(), gdata_entry->title());
    119   EXPECT_EQ(new_last_modified, gdata_entry->modified_date());
    120   EXPECT_EQ(new_last_accessed, gdata_entry->last_viewed_by_me_date());
    121 
    122   ASSERT_FALSE(gdata_entry->parents().empty());
    123   EXPECT_EQ(dest_entry.resource_id(), gdata_entry->parents()[0].file_id());
    124 }
    125 
    126 // Tests updating metadata of a file with a non-dirty cache file.
    127 TEST_F(EntryUpdatePerformerTest, UpdateEntry_WithNonDirtyCache) {
    128   base::FilePath src_path(
    129       FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt"));
    130 
    131   // Download the file content to prepare a non-dirty cache file.
    132   file_system::DownloadOperation download_operation(
    133       blocking_task_runner(), delegate(), scheduler(), metadata(), cache(),
    134       temp_dir());
    135   FileError error = FILE_ERROR_FAILED;
    136   base::FilePath cache_file_path;
    137   scoped_ptr<ResourceEntry> src_entry;
    138   download_operation.EnsureFileDownloadedByPath(
    139       src_path,
    140       ClientContext(USER_INITIATED),
    141       GetFileContentInitializedCallback(),
    142       google_apis::GetContentCallback(),
    143       google_apis::test_util::CreateCopyResultCallback(
    144           &error, &cache_file_path, &src_entry));
    145   content::RunAllBlockingPoolTasksUntilIdle();
    146   EXPECT_EQ(FILE_ERROR_OK, error);
    147   ASSERT_TRUE(src_entry);
    148 
    149   // Update the entry locally.
    150   src_entry->set_title("Updated" + src_entry->title());
    151   src_entry->set_metadata_edit_state(ResourceEntry::DIRTY);
    152 
    153   error = FILE_ERROR_FAILED;
    154   base::PostTaskAndReplyWithResult(
    155       blocking_task_runner(),
    156       FROM_HERE,
    157       base::Bind(&ResourceMetadata::RefreshEntry,
    158                  base::Unretained(metadata()),
    159                  *src_entry),
    160       google_apis::test_util::CreateCopyResultCallback(&error));
    161   content::RunAllBlockingPoolTasksUntilIdle();
    162   EXPECT_EQ(FILE_ERROR_OK, error);
    163 
    164   // Perform server side update. This shouldn't fail. (crbug.com/358590)
    165   error = FILE_ERROR_FAILED;
    166   performer_->UpdateEntry(
    167       src_entry->local_id(),
    168       ClientContext(USER_INITIATED),
    169       google_apis::test_util::CreateCopyResultCallback(&error));
    170   content::RunAllBlockingPoolTasksUntilIdle();
    171   EXPECT_EQ(FILE_ERROR_OK, error);
    172 
    173   // Verify the file is updated on the server.
    174   google_apis::GDataErrorCode gdata_error = google_apis::GDATA_OTHER_ERROR;
    175   scoped_ptr<google_apis::FileResource> gdata_entry;
    176   fake_service()->GetFileResource(
    177       src_entry->resource_id(),
    178       google_apis::test_util::CreateCopyResultCallback(&gdata_error,
    179                                                        &gdata_entry));
    180   content::RunAllBlockingPoolTasksUntilIdle();
    181   EXPECT_EQ(google_apis::HTTP_SUCCESS, gdata_error);
    182   ASSERT_TRUE(gdata_entry);
    183   EXPECT_EQ(src_entry->title(), gdata_entry->title());
    184 }
    185 
    186 TEST_F(EntryUpdatePerformerTest, UpdateEntry_NotFound) {
    187   const std::string id = "this ID should result in NOT_FOUND";
    188   FileError error = FILE_ERROR_FAILED;
    189   performer_->UpdateEntry(
    190       id, ClientContext(USER_INITIATED),
    191       google_apis::test_util::CreateCopyResultCallback(&error));
    192   content::RunAllBlockingPoolTasksUntilIdle();
    193   EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
    194 }
    195 
    196 TEST_F(EntryUpdatePerformerTest, UpdateEntry_ContentUpdate) {
    197   const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/File 1.txt"));
    198   const std::string kResourceId("2_file_resource_id");
    199 
    200   const std::string local_id = GetLocalId(kFilePath);
    201   EXPECT_FALSE(local_id.empty());
    202 
    203   const std::string kTestFileContent = "I'm being uploaded! Yay!";
    204   EXPECT_EQ(FILE_ERROR_OK, StoreAndMarkDirty(local_id, kTestFileContent));
    205 
    206   int64 original_changestamp =
    207       fake_service()->about_resource().largest_change_id();
    208 
    209   // The callback will be called upon completion of UpdateEntry().
    210   FileError error = FILE_ERROR_FAILED;
    211   performer_->UpdateEntry(
    212       local_id,
    213       ClientContext(USER_INITIATED),
    214       google_apis::test_util::CreateCopyResultCallback(&error));
    215   content::RunAllBlockingPoolTasksUntilIdle();
    216   EXPECT_EQ(FILE_ERROR_OK, error);
    217 
    218   // Check that the server has received an update.
    219   EXPECT_LT(original_changestamp,
    220             fake_service()->about_resource().largest_change_id());
    221 
    222   // Check that the file size is updated to that of the updated content.
    223   google_apis::GDataErrorCode gdata_error = google_apis::GDATA_OTHER_ERROR;
    224   scoped_ptr<google_apis::FileResource> server_entry;
    225   fake_service()->GetFileResource(
    226       kResourceId,
    227       google_apis::test_util::CreateCopyResultCallback(&gdata_error,
    228                                                        &server_entry));
    229   content::RunAllBlockingPoolTasksUntilIdle();
    230   EXPECT_EQ(google_apis::HTTP_SUCCESS, gdata_error);
    231   EXPECT_EQ(static_cast<int64>(kTestFileContent.size()),
    232             server_entry->file_size());
    233 
    234   // Make sure that the cache is no longer dirty.
    235   ResourceEntry entry;
    236   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry));
    237   EXPECT_FALSE(entry.file_specific_info().cache_state().is_dirty());
    238 }
    239 
    240 TEST_F(EntryUpdatePerformerTest, UpdateEntry_ContentUpdateMd5Check) {
    241   const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/File 1.txt"));
    242   const std::string kResourceId("2_file_resource_id");
    243 
    244   const std::string local_id = GetLocalId(kFilePath);
    245   EXPECT_FALSE(local_id.empty());
    246 
    247   const std::string kTestFileContent = "I'm being uploaded! Yay!";
    248   EXPECT_EQ(FILE_ERROR_OK, StoreAndMarkDirty(local_id, kTestFileContent));
    249 
    250   int64 original_changestamp =
    251       fake_service()->about_resource().largest_change_id();
    252 
    253   // The callback will be called upon completion of UpdateEntry().
    254   FileError error = FILE_ERROR_FAILED;
    255   performer_->UpdateEntry(
    256       local_id,
    257       ClientContext(USER_INITIATED),
    258       google_apis::test_util::CreateCopyResultCallback(&error));
    259   content::RunAllBlockingPoolTasksUntilIdle();
    260   EXPECT_EQ(FILE_ERROR_OK, error);
    261 
    262   // Check that the server has received an update.
    263   EXPECT_LT(original_changestamp,
    264             fake_service()->about_resource().largest_change_id());
    265 
    266   // Check that the file size is updated to that of the updated content.
    267   google_apis::GDataErrorCode gdata_error = google_apis::GDATA_OTHER_ERROR;
    268   scoped_ptr<google_apis::FileResource> server_entry;
    269   fake_service()->GetFileResource(
    270       kResourceId,
    271       google_apis::test_util::CreateCopyResultCallback(&gdata_error,
    272                                                        &server_entry));
    273   content::RunAllBlockingPoolTasksUntilIdle();
    274   EXPECT_EQ(google_apis::HTTP_SUCCESS, gdata_error);
    275   EXPECT_EQ(static_cast<int64>(kTestFileContent.size()),
    276             server_entry->file_size());
    277 
    278   // Make sure that the cache is no longer dirty.
    279   ResourceEntry entry;
    280   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry));
    281   EXPECT_FALSE(entry.file_specific_info().cache_state().is_dirty());
    282 
    283   // Again mark the cache file dirty.
    284   scoped_ptr<base::ScopedClosureRunner> file_closer;
    285   error = FILE_ERROR_FAILED;
    286   base::PostTaskAndReplyWithResult(
    287       blocking_task_runner(),
    288       FROM_HERE,
    289       base::Bind(&FileCache::OpenForWrite,
    290                  base::Unretained(cache()),
    291                  local_id,
    292                  &file_closer),
    293       google_apis::test_util::CreateCopyResultCallback(&error));
    294   content::RunAllBlockingPoolTasksUntilIdle();
    295   EXPECT_EQ(FILE_ERROR_OK, error);
    296   file_closer.reset();
    297 
    298   // And call UpdateEntry again.
    299   // In this case, although the file is marked as dirty, but the content
    300   // hasn't been changed. Thus, the actual uploading should be skipped.
    301   original_changestamp = fake_service()->about_resource().largest_change_id();
    302   error = FILE_ERROR_FAILED;
    303   performer_->UpdateEntry(
    304       local_id,
    305       ClientContext(USER_INITIATED),
    306       google_apis::test_util::CreateCopyResultCallback(&error));
    307   content::RunAllBlockingPoolTasksUntilIdle();
    308   EXPECT_EQ(FILE_ERROR_OK, error);
    309 
    310   EXPECT_EQ(original_changestamp,
    311             fake_service()->about_resource().largest_change_id());
    312 
    313   // Make sure that the cache is no longer dirty.
    314   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry));
    315   EXPECT_FALSE(entry.file_specific_info().cache_state().is_dirty());
    316 }
    317 
    318 TEST_F(EntryUpdatePerformerTest, UpdateEntry_OpenedForWrite) {
    319   const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/File 1.txt"));
    320   const std::string kResourceId("2_file_resource_id");
    321 
    322   const std::string local_id = GetLocalId(kFilePath);
    323   EXPECT_FALSE(local_id.empty());
    324 
    325   const std::string kTestFileContent = "I'm being uploaded! Yay!";
    326   EXPECT_EQ(FILE_ERROR_OK, StoreAndMarkDirty(local_id, kTestFileContent));
    327 
    328   // Emulate a situation where someone is writing to the file.
    329   scoped_ptr<base::ScopedClosureRunner> file_closer;
    330   FileError error = FILE_ERROR_FAILED;
    331   base::PostTaskAndReplyWithResult(
    332       blocking_task_runner(),
    333       FROM_HERE,
    334       base::Bind(&FileCache::OpenForWrite,
    335                  base::Unretained(cache()),
    336                  local_id,
    337                  &file_closer),
    338       google_apis::test_util::CreateCopyResultCallback(&error));
    339   content::RunAllBlockingPoolTasksUntilIdle();
    340   EXPECT_EQ(FILE_ERROR_OK, error);
    341 
    342   // Update. This should not clear the dirty bit.
    343   error = FILE_ERROR_FAILED;
    344   performer_->UpdateEntry(
    345       local_id,
    346       ClientContext(USER_INITIATED),
    347       google_apis::test_util::CreateCopyResultCallback(&error));
    348   content::RunAllBlockingPoolTasksUntilIdle();
    349   EXPECT_EQ(FILE_ERROR_OK, error);
    350 
    351   // Make sure that the cache is still dirty.
    352   ResourceEntry entry;
    353   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry));
    354   EXPECT_TRUE(entry.file_specific_info().cache_state().is_dirty());
    355 
    356   // Close the file.
    357   file_closer.reset();
    358 
    359   // Update. This should clear the dirty bit.
    360   error = FILE_ERROR_FAILED;
    361   performer_->UpdateEntry(
    362       local_id,
    363       ClientContext(USER_INITIATED),
    364       google_apis::test_util::CreateCopyResultCallback(&error));
    365   content::RunAllBlockingPoolTasksUntilIdle();
    366   EXPECT_EQ(FILE_ERROR_OK, error);
    367 
    368   // Make sure that the cache is no longer dirty.
    369   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry));
    370   EXPECT_FALSE(entry.file_specific_info().cache_state().is_dirty());
    371 }
    372 
    373 TEST_F(EntryUpdatePerformerTest, UpdateEntry_UploadNewFile) {
    374   // Create a new file locally.
    375   const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/New File.txt"));
    376 
    377   ResourceEntry parent;
    378   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath.DirName(), &parent));
    379 
    380   ResourceEntry entry;
    381   entry.set_parent_local_id(parent.local_id());
    382   entry.set_title(kFilePath.BaseName().AsUTF8Unsafe());
    383   entry.mutable_file_specific_info()->set_content_mime_type("text/plain");
    384   entry.set_metadata_edit_state(ResourceEntry::DIRTY);
    385 
    386   FileError error = FILE_ERROR_FAILED;
    387   std::string local_id;
    388   base::PostTaskAndReplyWithResult(
    389       blocking_task_runner(),
    390       FROM_HERE,
    391       base::Bind(&internal::ResourceMetadata::AddEntry,
    392                  base::Unretained(metadata()),
    393                  entry,
    394                  &local_id),
    395       google_apis::test_util::CreateCopyResultCallback(&error));
    396   content::RunAllBlockingPoolTasksUntilIdle();
    397   EXPECT_EQ(FILE_ERROR_OK, error);
    398 
    399   // Update. This should result in creating a new file on the server.
    400   error = FILE_ERROR_FAILED;
    401   performer_->UpdateEntry(
    402       local_id,
    403       ClientContext(USER_INITIATED),
    404       google_apis::test_util::CreateCopyResultCallback(&error));
    405   content::RunAllBlockingPoolTasksUntilIdle();
    406   EXPECT_EQ(FILE_ERROR_OK, error);
    407 
    408   // The entry got a resource ID.
    409   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry));
    410   EXPECT_FALSE(entry.resource_id().empty());
    411   EXPECT_EQ(ResourceEntry::CLEAN, entry.metadata_edit_state());
    412 
    413   // Make sure that the cache is no longer dirty.
    414   EXPECT_FALSE(entry.file_specific_info().cache_state().is_dirty());
    415 
    416   // Make sure that we really created a file.
    417   google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR;
    418   scoped_ptr<google_apis::FileResource> server_entry;
    419   fake_service()->GetFileResource(
    420       entry.resource_id(),
    421       google_apis::test_util::CreateCopyResultCallback(&status, &server_entry));
    422   content::RunAllBlockingPoolTasksUntilIdle();
    423   EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
    424   ASSERT_TRUE(server_entry);
    425   EXPECT_FALSE(server_entry->IsDirectory());
    426 }
    427 
    428 TEST_F(EntryUpdatePerformerTest, UpdateEntry_NewFileOpendForWrite) {
    429   // Create a new file locally.
    430   const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/New File.txt"));
    431 
    432   ResourceEntry parent;
    433   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath.DirName(), &parent));
    434 
    435   ResourceEntry entry;
    436   entry.set_parent_local_id(parent.local_id());
    437   entry.set_title(kFilePath.BaseName().AsUTF8Unsafe());
    438   entry.mutable_file_specific_info()->set_content_mime_type("text/plain");
    439   entry.set_metadata_edit_state(ResourceEntry::DIRTY);
    440 
    441   FileError error = FILE_ERROR_FAILED;
    442   std::string local_id;
    443   base::PostTaskAndReplyWithResult(
    444       blocking_task_runner(),
    445       FROM_HERE,
    446       base::Bind(&internal::ResourceMetadata::AddEntry,
    447                  base::Unretained(metadata()),
    448                  entry,
    449                  &local_id),
    450       google_apis::test_util::CreateCopyResultCallback(&error));
    451   content::RunAllBlockingPoolTasksUntilIdle();
    452   EXPECT_EQ(FILE_ERROR_OK, error);
    453 
    454   const std::string kTestFileContent = "This is a new file.";
    455   EXPECT_EQ(FILE_ERROR_OK, StoreAndMarkDirty(local_id, kTestFileContent));
    456 
    457   // Emulate a situation where someone is writing to the file.
    458   scoped_ptr<base::ScopedClosureRunner> file_closer;
    459   error = FILE_ERROR_FAILED;
    460   base::PostTaskAndReplyWithResult(
    461       blocking_task_runner(),
    462       FROM_HERE,
    463       base::Bind(&FileCache::OpenForWrite,
    464                  base::Unretained(cache()),
    465                  local_id,
    466                  &file_closer),
    467       google_apis::test_util::CreateCopyResultCallback(&error));
    468   content::RunAllBlockingPoolTasksUntilIdle();
    469   EXPECT_EQ(FILE_ERROR_OK, error);
    470 
    471   // Update, but no update is performed because the file is opened.
    472   error = FILE_ERROR_FAILED;
    473   performer_->UpdateEntry(
    474       local_id,
    475       ClientContext(USER_INITIATED),
    476       google_apis::test_util::CreateCopyResultCallback(&error));
    477   content::RunAllBlockingPoolTasksUntilIdle();
    478   EXPECT_EQ(FILE_ERROR_OK, error);
    479 
    480   // The entry hasn't got a resource ID yet.
    481   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry));
    482   EXPECT_TRUE(entry.resource_id().empty());
    483 
    484   // Close the file.
    485   file_closer.reset();
    486 
    487   // Update. This should result in creating a new file on the server.
    488   error = FILE_ERROR_FAILED;
    489   performer_->UpdateEntry(
    490       local_id,
    491       ClientContext(USER_INITIATED),
    492       google_apis::test_util::CreateCopyResultCallback(&error));
    493   content::RunAllBlockingPoolTasksUntilIdle();
    494   EXPECT_EQ(FILE_ERROR_OK, error);
    495 
    496   // The entry got a resource ID.
    497   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry));
    498   EXPECT_FALSE(entry.resource_id().empty());
    499   EXPECT_EQ(ResourceEntry::CLEAN, entry.metadata_edit_state());
    500 }
    501 
    502 TEST_F(EntryUpdatePerformerTest, UpdateEntry_CreateDirectory) {
    503   // Create a new directory locally.
    504   const base::FilePath kPath(FILE_PATH_LITERAL("drive/root/New Directory"));
    505 
    506   ResourceEntry parent;
    507   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kPath.DirName(), &parent));
    508 
    509   ResourceEntry entry;
    510   entry.set_parent_local_id(parent.local_id());
    511   entry.set_title(kPath.BaseName().AsUTF8Unsafe());
    512   entry.mutable_file_info()->set_is_directory(true);
    513   entry.set_metadata_edit_state(ResourceEntry::DIRTY);
    514 
    515   FileError error = FILE_ERROR_FAILED;
    516   std::string local_id;
    517   base::PostTaskAndReplyWithResult(
    518       blocking_task_runner(),
    519       FROM_HERE,
    520       base::Bind(&internal::ResourceMetadata::AddEntry,
    521                  base::Unretained(metadata()),
    522                  entry,
    523                  &local_id),
    524       google_apis::test_util::CreateCopyResultCallback(&error));
    525   content::RunAllBlockingPoolTasksUntilIdle();
    526   EXPECT_EQ(FILE_ERROR_OK, error);
    527 
    528   // Update. This should result in creating a new directory on the server.
    529   error = FILE_ERROR_FAILED;
    530   performer_->UpdateEntry(
    531       local_id,
    532       ClientContext(USER_INITIATED),
    533       google_apis::test_util::CreateCopyResultCallback(&error));
    534   content::RunAllBlockingPoolTasksUntilIdle();
    535   EXPECT_EQ(FILE_ERROR_OK, error);
    536 
    537   // The entry got a resource ID.
    538   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kPath, &entry));
    539   EXPECT_FALSE(entry.resource_id().empty());
    540   EXPECT_EQ(ResourceEntry::CLEAN, entry.metadata_edit_state());
    541 
    542   // Make sure that we really created a directory.
    543   google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR;
    544   scoped_ptr<google_apis::FileResource> server_entry;
    545   fake_service()->GetFileResource(
    546       entry.resource_id(),
    547       google_apis::test_util::CreateCopyResultCallback(&status, &server_entry));
    548   content::RunAllBlockingPoolTasksUntilIdle();
    549   EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
    550   ASSERT_TRUE(server_entry);
    551   EXPECT_TRUE(server_entry->IsDirectory());
    552 }
    553 
    554 TEST_F(EntryUpdatePerformerTest, UpdateEntry_InsufficientPermission) {
    555   base::FilePath src_path(
    556       FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt"));
    557 
    558   ResourceEntry src_entry;
    559   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &src_entry));
    560 
    561   // Update local entry.
    562   ResourceEntry updated_entry(src_entry);
    563   updated_entry.set_title("Moved" + src_entry.title());
    564   updated_entry.set_metadata_edit_state(ResourceEntry::DIRTY);
    565 
    566   FileError error = FILE_ERROR_FAILED;
    567   base::PostTaskAndReplyWithResult(
    568       blocking_task_runner(),
    569       FROM_HERE,
    570       base::Bind(&ResourceMetadata::RefreshEntry,
    571                  base::Unretained(metadata()),
    572                  updated_entry),
    573       google_apis::test_util::CreateCopyResultCallback(&error));
    574   content::RunAllBlockingPoolTasksUntilIdle();
    575   EXPECT_EQ(FILE_ERROR_OK, error);
    576 
    577   // Set user permission to forbid server side update.
    578   EXPECT_EQ(google_apis::HTTP_SUCCESS, fake_service()->SetUserPermission(
    579       src_entry.resource_id(), google_apis::drive::PERMISSION_ROLE_READER));
    580 
    581   // Try to perform update.
    582   error = FILE_ERROR_FAILED;
    583   performer_->UpdateEntry(
    584       src_entry.local_id(),
    585       ClientContext(USER_INITIATED),
    586       google_apis::test_util::CreateCopyResultCallback(&error));
    587   content::RunAllBlockingPoolTasksUntilIdle();
    588   EXPECT_EQ(FILE_ERROR_OK, error);
    589 
    590   // This should result in reverting the local change.
    591   ResourceEntry result_entry;
    592   EXPECT_EQ(FILE_ERROR_OK,
    593             GetLocalResourceEntryById(src_entry.local_id(), &result_entry));
    594   EXPECT_EQ(src_entry.title(), result_entry.title());
    595 }
    596 
    597 }  // namespace internal
    598 }  // namespace drive
    599