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