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