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