Home | History | Annotate | Download | only in file_system
      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/file_system/copy_operation.h"
      6 
      7 #include "base/file_util.h"
      8 #include "base/task_runner_util.h"
      9 #include "chrome/browser/chromeos/drive/file_cache.h"
     10 #include "chrome/browser/chromeos/drive/file_system/operation_test_base.h"
     11 #include "chrome/browser/chromeos/drive/file_system_util.h"
     12 #include "chrome/browser/drive/drive_api_util.h"
     13 #include "chrome/browser/drive/fake_drive_service.h"
     14 #include "google_apis/drive/drive_api_parser.h"
     15 #include "google_apis/drive/test_util.h"
     16 #include "testing/gtest/include/gtest/gtest.h"
     17 
     18 namespace drive {
     19 namespace file_system {
     20 
     21 class CopyOperationTest : public OperationTestBase {
     22  protected:
     23   virtual void SetUp() OVERRIDE {
     24    OperationTestBase::SetUp();
     25    operation_.reset(new CopyOperation(
     26        blocking_task_runner(),
     27        observer(),
     28        scheduler(),
     29        metadata(),
     30        cache(),
     31        util::GetIdentityResourceIdCanonicalizer()));
     32   }
     33 
     34   scoped_ptr<CopyOperation> operation_;
     35 };
     36 
     37 TEST_F(CopyOperationTest, TransferFileFromLocalToRemote_RegularFile) {
     38   const base::FilePath local_src_path = temp_dir().AppendASCII("local.txt");
     39   const base::FilePath remote_dest_path(
     40       FILE_PATH_LITERAL("drive/root/remote.txt"));
     41 
     42   // Prepare a local file.
     43   ASSERT_TRUE(
     44       google_apis::test_util::WriteStringToFile(local_src_path, "hello"));
     45   // Confirm that the remote file does not exist.
     46   ResourceEntry entry;
     47   ASSERT_EQ(FILE_ERROR_NOT_FOUND,
     48             GetLocalResourceEntry(remote_dest_path, &entry));
     49 
     50   // Transfer the local file to Drive.
     51   FileError error = FILE_ERROR_FAILED;
     52   operation_->TransferFileFromLocalToRemote(
     53       local_src_path,
     54       remote_dest_path,
     55       google_apis::test_util::CreateCopyResultCallback(&error));
     56   test_util::RunBlockingPoolTask();
     57   EXPECT_EQ(FILE_ERROR_OK, error);
     58 
     59   // TransferFileFromLocalToRemote stores a copy of the local file in the cache,
     60   // marks it dirty and requests the observer to upload the file.
     61   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(remote_dest_path, &entry));
     62   EXPECT_EQ(1U, observer()->updated_local_ids().count(entry.local_id()));
     63   EXPECT_TRUE(entry.file_specific_info().cache_state().is_present());
     64   EXPECT_TRUE(entry.file_specific_info().cache_state().is_dirty());
     65 
     66   EXPECT_EQ(1U, observer()->get_changed_paths().size());
     67   EXPECT_TRUE(observer()->get_changed_paths().count(
     68       remote_dest_path.DirName()));
     69 }
     70 
     71 TEST_F(CopyOperationTest, TransferFileFromLocalToRemote_Overwrite) {
     72   const base::FilePath local_src_path = temp_dir().AppendASCII("local.txt");
     73   const base::FilePath remote_dest_path(
     74       FILE_PATH_LITERAL("drive/root/File 1.txt"));
     75 
     76   // Prepare a local file.
     77   EXPECT_TRUE(
     78       google_apis::test_util::WriteStringToFile(local_src_path, "hello"));
     79   // Confirm that the remote file exists.
     80   ResourceEntry entry;
     81   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(remote_dest_path, &entry));
     82 
     83   // Transfer the local file to Drive.
     84   FileError error = FILE_ERROR_FAILED;
     85   operation_->TransferFileFromLocalToRemote(
     86       local_src_path,
     87       remote_dest_path,
     88       google_apis::test_util::CreateCopyResultCallback(&error));
     89   test_util::RunBlockingPoolTask();
     90   EXPECT_EQ(FILE_ERROR_OK, error);
     91 
     92   // TransferFileFromLocalToRemote stores a copy of the local file in the cache,
     93   // marks it dirty and requests the observer to upload the file.
     94   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(remote_dest_path, &entry));
     95   EXPECT_EQ(1U, observer()->updated_local_ids().count(entry.local_id()));
     96   EXPECT_TRUE(entry.file_specific_info().cache_state().is_present());
     97   EXPECT_TRUE(entry.file_specific_info().cache_state().is_dirty());
     98 
     99   EXPECT_EQ(1U, observer()->get_changed_paths().size());
    100   EXPECT_TRUE(observer()->get_changed_paths().count(
    101       remote_dest_path.DirName()));
    102 }
    103 
    104 TEST_F(CopyOperationTest,
    105        TransferFileFromLocalToRemote_ExistingHostedDocument) {
    106   const base::FilePath local_src_path = temp_dir().AppendASCII("local.gdoc");
    107   const base::FilePath remote_dest_path(FILE_PATH_LITERAL(
    108       "drive/root/Directory 1/copied.gdoc"));
    109 
    110   // Prepare a local file, which is a json file of a hosted document, which
    111   // matches "drive/root/Document 1 excludeDir-test".
    112   ASSERT_TRUE(util::CreateGDocFile(
    113       local_src_path,
    114       GURL("https://3_document_self_link/document:5_document_resource_id"),
    115       "document:5_document_resource_id"));
    116 
    117   ResourceEntry entry;
    118   ASSERT_EQ(FILE_ERROR_NOT_FOUND,
    119             GetLocalResourceEntry(remote_dest_path, &entry));
    120 
    121   // Transfer the local file to Drive.
    122   FileError error = FILE_ERROR_FAILED;
    123   operation_->TransferFileFromLocalToRemote(
    124       local_src_path,
    125       remote_dest_path,
    126       google_apis::test_util::CreateCopyResultCallback(&error));
    127   test_util::RunBlockingPoolTask();
    128   EXPECT_EQ(FILE_ERROR_OK, error);
    129 
    130   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(remote_dest_path, &entry));
    131 
    132   EXPECT_EQ(1U, observer()->get_changed_paths().size());
    133   EXPECT_TRUE(
    134       observer()->get_changed_paths().count(remote_dest_path.DirName()));
    135   // New copy is created.
    136   EXPECT_NE("document:5_document_resource_id", entry.resource_id());
    137 }
    138 
    139 TEST_F(CopyOperationTest, TransferFileFromLocalToRemote_OrphanHostedDocument) {
    140   const base::FilePath local_src_path = temp_dir().AppendASCII("local.gdoc");
    141   const base::FilePath remote_dest_path(FILE_PATH_LITERAL(
    142       "drive/root/Directory 1/moved.gdoc"));
    143 
    144   // Prepare a local file, which is a json file of a hosted document, which
    145   // matches "drive/other/Orphan Document".
    146   ASSERT_TRUE(util::CreateGDocFile(
    147       local_src_path,
    148       GURL("https://3_document_self_link/document:orphan_doc_1"),
    149       "document:orphan_doc_1"));
    150 
    151   ResourceEntry entry;
    152   ASSERT_EQ(FILE_ERROR_NOT_FOUND,
    153             GetLocalResourceEntry(remote_dest_path, &entry));
    154 
    155   // Transfer the local file to Drive.
    156   FileError error = FILE_ERROR_FAILED;
    157   operation_->TransferFileFromLocalToRemote(
    158       local_src_path,
    159       remote_dest_path,
    160       google_apis::test_util::CreateCopyResultCallback(&error));
    161   test_util::RunBlockingPoolTask();
    162   EXPECT_EQ(FILE_ERROR_OK, error);
    163 
    164   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(remote_dest_path, &entry));
    165   EXPECT_EQ(ResourceEntry::DIRTY, entry.metadata_edit_state());
    166   EXPECT_TRUE(observer()->updated_local_ids().count(entry.local_id()));
    167 
    168   EXPECT_EQ(1U, observer()->get_changed_paths().size());
    169   EXPECT_TRUE(
    170       observer()->get_changed_paths().count(remote_dest_path.DirName()));
    171   // The original document got new parent.
    172   EXPECT_EQ("document:orphan_doc_1", entry.resource_id());
    173 }
    174 
    175 TEST_F(CopyOperationTest, TransferFileFromLocalToRemote_NewHostedDocument) {
    176   const base::FilePath local_src_path = temp_dir().AppendASCII("local.gdoc");
    177   const base::FilePath remote_dest_path(FILE_PATH_LITERAL(
    178       "drive/root/Directory 1/moved.gdoc"));
    179 
    180   // Create a hosted document on the server that is not synced to local yet.
    181   google_apis::GDataErrorCode gdata_error = google_apis::GDATA_OTHER_ERROR;
    182   scoped_ptr<google_apis::FileResource> new_gdoc_entry;
    183   fake_service()->AddNewFile(
    184       "application/vnd.google-apps.document", "", "", "title", true,
    185       google_apis::test_util::CreateCopyResultCallback(&gdata_error,
    186                                                        &new_gdoc_entry));
    187   test_util::RunBlockingPoolTask();
    188   ASSERT_EQ(google_apis::HTTP_CREATED, gdata_error);
    189 
    190   // Prepare a local file, which is a json file of the added hosted document.
    191   ASSERT_TRUE(util::CreateGDocFile(
    192       local_src_path,
    193       GURL("https://3_document_self_link/" + new_gdoc_entry->file_id()),
    194       new_gdoc_entry->file_id()));
    195 
    196   ResourceEntry entry;
    197   ASSERT_EQ(FILE_ERROR_NOT_FOUND,
    198             GetLocalResourceEntry(remote_dest_path, &entry));
    199 
    200   // Transfer the local file to Drive.
    201   FileError error = FILE_ERROR_FAILED;
    202   operation_->TransferFileFromLocalToRemote(
    203       local_src_path,
    204       remote_dest_path,
    205       google_apis::test_util::CreateCopyResultCallback(&error));
    206   test_util::RunBlockingPoolTask();
    207   EXPECT_EQ(FILE_ERROR_OK, error);
    208 
    209   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(remote_dest_path, &entry));
    210 
    211   EXPECT_EQ(1U, observer()->get_changed_paths().size());
    212   EXPECT_TRUE(
    213       observer()->get_changed_paths().count(remote_dest_path.DirName()));
    214   // The original document got new parent.
    215   EXPECT_EQ(new_gdoc_entry->file_id(), entry.resource_id());
    216 }
    217 
    218 TEST_F(CopyOperationTest, CopyNotExistingFile) {
    219   base::FilePath src_path(FILE_PATH_LITERAL("drive/root/Dummy file.txt"));
    220   base::FilePath dest_path(FILE_PATH_LITERAL("drive/root/Test.log"));
    221 
    222   ResourceEntry entry;
    223   ASSERT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(src_path, &entry));
    224 
    225   FileError error = FILE_ERROR_OK;
    226   operation_->Copy(src_path,
    227                    dest_path,
    228                    false,
    229                    google_apis::test_util::CreateCopyResultCallback(&error));
    230   test_util::RunBlockingPoolTask();
    231   EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
    232 
    233   EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(src_path, &entry));
    234   EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(dest_path, &entry));
    235   EXPECT_TRUE(observer()->get_changed_paths().empty());
    236 }
    237 
    238 TEST_F(CopyOperationTest, CopyFileToNonExistingDirectory) {
    239   base::FilePath src_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
    240   base::FilePath dest_path(FILE_PATH_LITERAL("drive/root/Dummy/Test.log"));
    241 
    242   ResourceEntry entry;
    243   ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &entry));
    244   ASSERT_EQ(FILE_ERROR_NOT_FOUND,
    245             GetLocalResourceEntry(dest_path.DirName(), &entry));
    246 
    247   FileError error = FILE_ERROR_OK;
    248   operation_->Copy(src_path,
    249                    dest_path,
    250                    false,
    251                    google_apis::test_util::CreateCopyResultCallback(&error));
    252   test_util::RunBlockingPoolTask();
    253   EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
    254 
    255   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &entry));
    256   EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(dest_path, &entry));
    257   EXPECT_TRUE(observer()->get_changed_paths().empty());
    258 }
    259 
    260 // Test the case where the parent of the destination path is an existing file,
    261 // not a directory.
    262 TEST_F(CopyOperationTest, CopyFileToInvalidPath) {
    263   base::FilePath src_path(FILE_PATH_LITERAL(
    264       "drive/root/Document 1 excludeDir-test.gdoc"));
    265   base::FilePath dest_path(FILE_PATH_LITERAL(
    266       "drive/root/Duplicate Name.txt/Document 1 excludeDir-test.gdoc"));
    267 
    268   ResourceEntry entry;
    269   ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &entry));
    270   ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path.DirName(), &entry));
    271   ASSERT_FALSE(entry.file_info().is_directory());
    272 
    273   FileError error = FILE_ERROR_OK;
    274   operation_->Copy(src_path,
    275                    dest_path,
    276                    false,
    277                    google_apis::test_util::CreateCopyResultCallback(&error));
    278   test_util::RunBlockingPoolTask();
    279   EXPECT_EQ(FILE_ERROR_NOT_A_DIRECTORY, error);
    280 
    281   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &entry));
    282   EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(dest_path, &entry));
    283   EXPECT_TRUE(observer()->get_changed_paths().empty());
    284 }
    285 
    286 TEST_F(CopyOperationTest, CopyDirtyFile) {
    287   base::FilePath src_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
    288   base::FilePath dest_path(FILE_PATH_LITERAL(
    289       "drive/root/Directory 1/New File.txt"));
    290 
    291   ResourceEntry src_entry;
    292   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &src_entry));
    293 
    294   // Store a dirty cache file.
    295   base::FilePath temp_file;
    296   EXPECT_TRUE(base::CreateTemporaryFileInDir(temp_dir(), &temp_file));
    297   std::string contents = "test content";
    298   EXPECT_TRUE(google_apis::test_util::WriteStringToFile(temp_file, contents));
    299   FileError error = FILE_ERROR_FAILED;
    300   base::PostTaskAndReplyWithResult(
    301       blocking_task_runner(),
    302       FROM_HERE,
    303       base::Bind(&internal::FileCache::Store,
    304                  base::Unretained(cache()),
    305                  src_entry.local_id(),
    306                  std::string(),
    307                  temp_file,
    308                  internal::FileCache::FILE_OPERATION_MOVE),
    309       google_apis::test_util::CreateCopyResultCallback(&error));
    310   test_util::RunBlockingPoolTask();
    311   EXPECT_EQ(FILE_ERROR_OK, error);
    312 
    313   // Copy.
    314   operation_->Copy(src_path,
    315                    dest_path,
    316                    false,
    317                    google_apis::test_util::CreateCopyResultCallback(&error));
    318   test_util::RunBlockingPoolTask();
    319   EXPECT_EQ(FILE_ERROR_OK, error);
    320 
    321   ResourceEntry dest_entry;
    322   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path, &dest_entry));
    323   EXPECT_EQ(ResourceEntry::DIRTY, dest_entry.metadata_edit_state());
    324 
    325   EXPECT_EQ(1u, observer()->updated_local_ids().size());
    326   EXPECT_TRUE(observer()->updated_local_ids().count(dest_entry.local_id()));
    327   EXPECT_EQ(1u, observer()->get_changed_paths().size());
    328   EXPECT_TRUE(observer()->get_changed_paths().count(dest_path.DirName()));
    329 
    330   // Copied cache file should be dirty.
    331   EXPECT_TRUE(dest_entry.file_specific_info().cache_state().is_dirty());
    332 
    333   // File contents should match.
    334   base::FilePath cache_file_path;
    335   base::PostTaskAndReplyWithResult(
    336       blocking_task_runner(),
    337       FROM_HERE,
    338       base::Bind(&internal::FileCache::GetFile,
    339                  base::Unretained(cache()),
    340                  dest_entry.local_id(),
    341                  &cache_file_path),
    342       google_apis::test_util::CreateCopyResultCallback(&error));
    343   test_util::RunBlockingPoolTask();
    344   EXPECT_EQ(FILE_ERROR_OK, error);
    345 
    346   std::string copied_contents;
    347   EXPECT_TRUE(base::ReadFileToString(cache_file_path, &copied_contents));
    348   EXPECT_EQ(contents, copied_contents);
    349 }
    350 
    351 TEST_F(CopyOperationTest, CopyFileOverwriteFile) {
    352   base::FilePath src_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
    353   base::FilePath dest_path(FILE_PATH_LITERAL(
    354       "drive/root/Directory 1/SubDirectory File 1.txt"));
    355 
    356   ResourceEntry old_dest_entry;
    357   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path, &old_dest_entry));
    358 
    359   FileError error = FILE_ERROR_OK;
    360   operation_->Copy(src_path,
    361                    dest_path,
    362                    false,
    363                    google_apis::test_util::CreateCopyResultCallback(&error));
    364   test_util::RunBlockingPoolTask();
    365   EXPECT_EQ(FILE_ERROR_OK, error);
    366 
    367   ResourceEntry new_dest_entry;
    368   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path, &new_dest_entry));
    369 
    370   EXPECT_EQ(1u, observer()->updated_local_ids().size());
    371   EXPECT_TRUE(observer()->updated_local_ids().count(old_dest_entry.local_id()));
    372   EXPECT_EQ(1u, observer()->get_changed_paths().size());
    373   EXPECT_TRUE(observer()->get_changed_paths().count(dest_path.DirName()));
    374 }
    375 
    376 TEST_F(CopyOperationTest, CopyFileOverwriteDirectory) {
    377   base::FilePath src_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
    378   base::FilePath dest_path(FILE_PATH_LITERAL("drive/root/Directory 1"));
    379 
    380   FileError error = FILE_ERROR_OK;
    381   operation_->Copy(src_path,
    382                    dest_path,
    383                    false,
    384                    google_apis::test_util::CreateCopyResultCallback(&error));
    385   test_util::RunBlockingPoolTask();
    386   EXPECT_EQ(FILE_ERROR_INVALID_OPERATION, error);
    387 }
    388 
    389 TEST_F(CopyOperationTest, CopyDirectory) {
    390   base::FilePath src_path(FILE_PATH_LITERAL("drive/root/Directory 1"));
    391   base::FilePath dest_path(FILE_PATH_LITERAL("drive/root/New Directory"));
    392 
    393   ResourceEntry entry;
    394   ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &entry));
    395   ASSERT_TRUE(entry.file_info().is_directory());
    396   ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path.DirName(), &entry));
    397   ASSERT_TRUE(entry.file_info().is_directory());
    398 
    399   FileError error = FILE_ERROR_OK;
    400   operation_->Copy(src_path,
    401                    dest_path,
    402                    false,
    403                    google_apis::test_util::CreateCopyResultCallback(&error));
    404   test_util::RunBlockingPoolTask();
    405   EXPECT_EQ(FILE_ERROR_NOT_A_FILE, error);
    406 }
    407 
    408 TEST_F(CopyOperationTest, PreserveLastModified) {
    409   base::FilePath src_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
    410   base::FilePath dest_path(FILE_PATH_LITERAL("drive/root/File 2.txt"));
    411 
    412   ResourceEntry entry;
    413   ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &entry));
    414   ASSERT_EQ(FILE_ERROR_OK,
    415             GetLocalResourceEntry(dest_path.DirName(), &entry));
    416 
    417   FileError error = FILE_ERROR_OK;
    418   operation_->Copy(src_path,
    419                    dest_path,
    420                    true,  // Preserve last modified.
    421                    google_apis::test_util::CreateCopyResultCallback(&error));
    422   test_util::RunBlockingPoolTask();
    423   EXPECT_EQ(FILE_ERROR_OK, error);
    424 
    425   ResourceEntry entry2;
    426   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &entry));
    427   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path, &entry2));
    428   EXPECT_EQ(entry.file_info().last_modified(),
    429             entry2.file_info().last_modified());
    430 }
    431 
    432 }  // namespace file_system
    433 }  // namespace drive
    434