1 // Copyright (c) 2012 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/resource_metadata.h" 6 7 #include <algorithm> 8 #include <string> 9 #include <vector> 10 11 #include "base/files/scoped_temp_dir.h" 12 #include "base/sequenced_task_runner.h" 13 #include "base/threading/sequenced_worker_pool.h" 14 #include "base/threading/thread_restrictions.h" 15 #include "chrome/browser/chromeos/drive/drive.pb.h" 16 #include "chrome/browser/chromeos/drive/file_system_util.h" 17 #include "chrome/browser/chromeos/drive/test_util.h" 18 #include "chrome/browser/google_apis/test_util.h" 19 #include "content/public/browser/browser_thread.h" 20 #include "content/public/test/test_browser_thread_bundle.h" 21 #include "testing/gtest/include/gtest/gtest.h" 22 23 namespace drive { 24 namespace internal { 25 namespace { 26 27 const char kTestRootResourceId[] = "test_root"; 28 29 // The changestamp of the resource metadata used in 30 // ResourceMetadataTest. 31 const int64 kTestChangestamp = 100; 32 33 // Returns the sorted base names from |entries|. 34 std::vector<std::string> GetSortedBaseNames( 35 const ResourceEntryVector& entries) { 36 std::vector<std::string> base_names; 37 for (size_t i = 0; i < entries.size(); ++i) 38 base_names.push_back(entries[i].base_name()); 39 std::sort(base_names.begin(), base_names.end()); 40 41 return base_names; 42 } 43 44 // Creates a ResourceEntry for a directory. 45 ResourceEntry CreateDirectoryEntry(const std::string& title, 46 const std::string& parent_resource_id) { 47 ResourceEntry entry; 48 entry.set_title(title); 49 entry.set_resource_id("resource_id:" + title); 50 entry.set_parent_resource_id(parent_resource_id); 51 entry.mutable_file_info()->set_is_directory(true); 52 entry.mutable_directory_specific_info()->set_changestamp(kTestChangestamp); 53 return entry; 54 } 55 56 // Creates a ResourceEntry for a file. 57 ResourceEntry CreateFileEntry(const std::string& title, 58 const std::string& parent_resource_id) { 59 ResourceEntry entry; 60 entry.set_title(title); 61 entry.set_resource_id("resource_id:" + title); 62 entry.set_parent_resource_id(parent_resource_id); 63 entry.mutable_file_info()->set_is_directory(false); 64 entry.mutable_file_info()->set_size(1024); 65 entry.mutable_file_specific_info()->set_md5("md5:" + title); 66 return entry; 67 } 68 69 // Creates the following files/directories 70 // drive/root/dir1/ 71 // drive/root/dir2/ 72 // drive/root/dir1/dir3/ 73 // drive/root/dir1/file4 74 // drive/root/dir1/file5 75 // drive/root/dir2/file6 76 // drive/root/dir2/file7 77 // drive/root/dir2/file8 78 // drive/root/dir1/dir3/file9 79 // drive/root/dir1/dir3/file10 80 void SetUpEntries(ResourceMetadata* resource_metadata) { 81 // Create mydrive root directory. 82 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry( 83 util::CreateMyDriveRootEntry(kTestRootResourceId))); 84 85 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry( 86 CreateDirectoryEntry("dir1", kTestRootResourceId))); 87 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry( 88 CreateDirectoryEntry("dir2", kTestRootResourceId))); 89 90 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry( 91 CreateDirectoryEntry("dir3", "resource_id:dir1"))); 92 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry( 93 CreateFileEntry("file4", "resource_id:dir1"))); 94 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry( 95 CreateFileEntry("file5", "resource_id:dir1"))); 96 97 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry( 98 CreateFileEntry("file6", "resource_id:dir2"))); 99 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry( 100 CreateFileEntry("file7", "resource_id:dir2"))); 101 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry( 102 CreateFileEntry("file8", "resource_id:dir2"))); 103 104 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry( 105 CreateFileEntry("file9", "resource_id:dir3"))); 106 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry( 107 CreateFileEntry("file10", "resource_id:dir3"))); 108 109 ASSERT_EQ(FILE_ERROR_OK, 110 resource_metadata->SetLargestChangestamp(kTestChangestamp)); 111 } 112 113 } // namespace 114 115 // Tests for methods invoked from the UI thread. 116 class ResourceMetadataTestOnUIThread : public testing::Test { 117 protected: 118 virtual void SetUp() OVERRIDE { 119 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 120 121 base::ThreadRestrictions::SetIOAllowed(false); // For strict thread check. 122 scoped_refptr<base::SequencedWorkerPool> pool = 123 content::BrowserThread::GetBlockingPool(); 124 blocking_task_runner_ = 125 pool->GetSequencedTaskRunner(pool->GetSequenceToken()); 126 127 metadata_storage_.reset(new ResourceMetadataStorage( 128 temp_dir_.path(), blocking_task_runner_.get())); 129 bool success = false; 130 base::PostTaskAndReplyWithResult( 131 blocking_task_runner_.get(), 132 FROM_HERE, 133 base::Bind(&ResourceMetadataStorage::Initialize, 134 base::Unretained(metadata_storage_.get())), 135 google_apis::test_util::CreateCopyResultCallback(&success)); 136 test_util::RunBlockingPoolTask(); 137 ASSERT_TRUE(success); 138 139 resource_metadata_.reset(new ResourceMetadata(metadata_storage_.get(), 140 blocking_task_runner_)); 141 142 FileError error = FILE_ERROR_FAILED; 143 base::PostTaskAndReplyWithResult( 144 blocking_task_runner_.get(), 145 FROM_HERE, 146 base::Bind(&ResourceMetadata::Initialize, 147 base::Unretained(resource_metadata_.get())), 148 google_apis::test_util::CreateCopyResultCallback(&error)); 149 test_util::RunBlockingPoolTask(); 150 ASSERT_EQ(FILE_ERROR_OK, error); 151 152 blocking_task_runner_->PostTask( 153 FROM_HERE, 154 base::Bind(&SetUpEntries, 155 base::Unretained(resource_metadata_.get()))); 156 test_util::RunBlockingPoolTask(); 157 } 158 159 virtual void TearDown() OVERRIDE { 160 metadata_storage_.reset(); 161 resource_metadata_.reset(); 162 base::ThreadRestrictions::SetIOAllowed(true); 163 } 164 165 // Gets the resource entry by path synchronously. Returns NULL on failure. 166 scoped_ptr<ResourceEntry> GetResourceEntryByPathSync( 167 const base::FilePath& file_path) { 168 FileError error = FILE_ERROR_OK; 169 scoped_ptr<ResourceEntry> entry; 170 resource_metadata_->GetResourceEntryByPathOnUIThread( 171 file_path, 172 google_apis::test_util::CreateCopyResultCallback(&error, &entry)); 173 test_util::RunBlockingPoolTask(); 174 EXPECT_TRUE(error == FILE_ERROR_OK || !entry); 175 return entry.Pass(); 176 } 177 178 // Reads the directory contents by path synchronously. Returns NULL on 179 // failure. 180 scoped_ptr<ResourceEntryVector> ReadDirectoryByPathSync( 181 const base::FilePath& directory_path) { 182 FileError error = FILE_ERROR_OK; 183 scoped_ptr<ResourceEntryVector> entries; 184 resource_metadata_->ReadDirectoryByPathOnUIThread( 185 directory_path, 186 google_apis::test_util::CreateCopyResultCallback(&error, &entries)); 187 test_util::RunBlockingPoolTask(); 188 EXPECT_TRUE(error == FILE_ERROR_OK || !entries); 189 return entries.Pass(); 190 } 191 192 content::TestBrowserThreadBundle thread_bundle_; 193 base::ScopedTempDir temp_dir_; 194 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; 195 scoped_ptr<ResourceMetadataStorage, test_util::DestroyHelperForTests> 196 metadata_storage_; 197 scoped_ptr<ResourceMetadata, test_util::DestroyHelperForTests> 198 resource_metadata_; 199 }; 200 201 TEST_F(ResourceMetadataTestOnUIThread, LargestChangestamp) { 202 FileError error = FILE_ERROR_FAILED; 203 int64 in_changestamp = 123456; 204 resource_metadata_->SetLargestChangestampOnUIThread( 205 in_changestamp, 206 google_apis::test_util::CreateCopyResultCallback(&error)); 207 test_util::RunBlockingPoolTask(); 208 EXPECT_EQ(FILE_ERROR_OK, error); 209 210 int64 out_changestamp = 0; 211 resource_metadata_->GetLargestChangestampOnUIThread( 212 google_apis::test_util::CreateCopyResultCallback(&out_changestamp)); 213 test_util::RunBlockingPoolTask(); 214 DCHECK_EQ(in_changestamp, out_changestamp); 215 } 216 217 TEST_F(ResourceMetadataTestOnUIThread, GetResourceEntryById_RootDirectory) { 218 // Look up the root directory by its resource ID. 219 FileError error = FILE_ERROR_FAILED; 220 scoped_ptr<ResourceEntry> entry; 221 resource_metadata_->GetResourceEntryByIdOnUIThread( 222 util::kDriveGrandRootSpecialResourceId, 223 google_apis::test_util::CreateCopyResultCallback(&error, &entry)); 224 test_util::RunBlockingPoolTask(); 225 EXPECT_EQ(FILE_ERROR_OK, error); 226 ASSERT_TRUE(entry.get()); 227 EXPECT_EQ("drive", entry->base_name()); 228 } 229 230 TEST_F(ResourceMetadataTestOnUIThread, GetResourceEntryById) { 231 // Confirm that an existing file is found. 232 FileError error = FILE_ERROR_FAILED; 233 scoped_ptr<ResourceEntry> entry; 234 resource_metadata_->GetResourceEntryByIdOnUIThread( 235 "resource_id:file4", 236 google_apis::test_util::CreateCopyResultCallback(&error, &entry)); 237 test_util::RunBlockingPoolTask(); 238 EXPECT_EQ(FILE_ERROR_OK, error); 239 ASSERT_TRUE(entry.get()); 240 EXPECT_EQ("file4", entry->base_name()); 241 242 // Confirm that a non existing file is not found. 243 error = FILE_ERROR_FAILED; 244 entry.reset(); 245 resource_metadata_->GetResourceEntryByIdOnUIThread( 246 "file:non_existing", 247 google_apis::test_util::CreateCopyResultCallback(&error, &entry)); 248 test_util::RunBlockingPoolTask(); 249 EXPECT_EQ(FILE_ERROR_NOT_FOUND, error); 250 EXPECT_FALSE(entry.get()); 251 } 252 253 TEST_F(ResourceMetadataTestOnUIThread, GetResourceEntryByPath) { 254 // Confirm that an existing file is found. 255 FileError error = FILE_ERROR_FAILED; 256 scoped_ptr<ResourceEntry> entry; 257 resource_metadata_->GetResourceEntryByPathOnUIThread( 258 base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"), 259 google_apis::test_util::CreateCopyResultCallback(&error, &entry)); 260 test_util::RunBlockingPoolTask(); 261 EXPECT_EQ(FILE_ERROR_OK, error); 262 ASSERT_TRUE(entry.get()); 263 EXPECT_EQ("file4", entry->base_name()); 264 265 // Confirm that a non existing file is not found. 266 error = FILE_ERROR_FAILED; 267 entry.reset(); 268 resource_metadata_->GetResourceEntryByPathOnUIThread( 269 base::FilePath::FromUTF8Unsafe("drive/root/dir1/non_existing"), 270 google_apis::test_util::CreateCopyResultCallback(&error, &entry)); 271 test_util::RunBlockingPoolTask(); 272 EXPECT_EQ(FILE_ERROR_NOT_FOUND, error); 273 EXPECT_FALSE(entry.get()); 274 275 // Confirm that the root is found. 276 error = FILE_ERROR_FAILED; 277 entry.reset(); 278 resource_metadata_->GetResourceEntryByPathOnUIThread( 279 base::FilePath::FromUTF8Unsafe("drive"), 280 google_apis::test_util::CreateCopyResultCallback(&error, &entry)); 281 test_util::RunBlockingPoolTask(); 282 EXPECT_EQ(FILE_ERROR_OK, error); 283 EXPECT_TRUE(entry.get()); 284 285 // Confirm that a non existing file is not found at the root level. 286 error = FILE_ERROR_FAILED; 287 entry.reset(); 288 resource_metadata_->GetResourceEntryByPathOnUIThread( 289 base::FilePath::FromUTF8Unsafe("non_existing"), 290 google_apis::test_util::CreateCopyResultCallback(&error, &entry)); 291 test_util::RunBlockingPoolTask(); 292 EXPECT_EQ(FILE_ERROR_NOT_FOUND, error); 293 EXPECT_FALSE(entry.get()); 294 295 // Confirm that an entry is not found with a wrong root. 296 error = FILE_ERROR_FAILED; 297 entry.reset(); 298 resource_metadata_->GetResourceEntryByPathOnUIThread( 299 base::FilePath::FromUTF8Unsafe("non_existing/root"), 300 google_apis::test_util::CreateCopyResultCallback(&error, &entry)); 301 test_util::RunBlockingPoolTask(); 302 EXPECT_EQ(FILE_ERROR_NOT_FOUND, error); 303 EXPECT_FALSE(entry.get()); 304 } 305 306 TEST_F(ResourceMetadataTestOnUIThread, ReadDirectoryByPath) { 307 // Confirm that an existing directory is found. 308 FileError error = FILE_ERROR_FAILED; 309 scoped_ptr<ResourceEntryVector> entries; 310 resource_metadata_->ReadDirectoryByPathOnUIThread( 311 base::FilePath::FromUTF8Unsafe("drive/root/dir1"), 312 google_apis::test_util::CreateCopyResultCallback(&error, &entries)); 313 test_util::RunBlockingPoolTask(); 314 EXPECT_EQ(FILE_ERROR_OK, error); 315 ASSERT_TRUE(entries.get()); 316 ASSERT_EQ(3U, entries->size()); 317 // The order is not guaranteed so we should sort the base names. 318 std::vector<std::string> base_names = GetSortedBaseNames(*entries); 319 EXPECT_EQ("dir3", base_names[0]); 320 EXPECT_EQ("file4", base_names[1]); 321 EXPECT_EQ("file5", base_names[2]); 322 323 // Confirm that a non existing directory is not found. 324 error = FILE_ERROR_FAILED; 325 entries.reset(); 326 resource_metadata_->ReadDirectoryByPathOnUIThread( 327 base::FilePath::FromUTF8Unsafe("drive/root/non_existing"), 328 google_apis::test_util::CreateCopyResultCallback(&error, &entries)); 329 test_util::RunBlockingPoolTask(); 330 EXPECT_EQ(FILE_ERROR_NOT_FOUND, error); 331 EXPECT_FALSE(entries.get()); 332 333 // Confirm that reading a file results in FILE_ERROR_NOT_A_DIRECTORY. 334 error = FILE_ERROR_FAILED; 335 entries.reset(); 336 resource_metadata_->ReadDirectoryByPathOnUIThread( 337 base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"), 338 google_apis::test_util::CreateCopyResultCallback(&error, &entries)); 339 test_util::RunBlockingPoolTask(); 340 EXPECT_EQ(FILE_ERROR_NOT_A_DIRECTORY, error); 341 EXPECT_FALSE(entries.get()); 342 } 343 344 TEST_F(ResourceMetadataTestOnUIThread, GetResourceEntryPairByPaths) { 345 // Confirm that existing two files are found. 346 scoped_ptr<EntryInfoPairResult> pair_result; 347 resource_metadata_->GetResourceEntryPairByPathsOnUIThread( 348 base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"), 349 base::FilePath::FromUTF8Unsafe("drive/root/dir1/file5"), 350 google_apis::test_util::CreateCopyResultCallback(&pair_result)); 351 test_util::RunBlockingPoolTask(); 352 // The first entry should be found. 353 EXPECT_EQ(FILE_ERROR_OK, pair_result->first.error); 354 EXPECT_EQ(base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"), 355 pair_result->first.path); 356 ASSERT_TRUE(pair_result->first.entry.get()); 357 EXPECT_EQ("file4", pair_result->first.entry->base_name()); 358 // The second entry should be found. 359 EXPECT_EQ(FILE_ERROR_OK, pair_result->second.error); 360 EXPECT_EQ(base::FilePath::FromUTF8Unsafe("drive/root/dir1/file5"), 361 pair_result->second.path); 362 ASSERT_TRUE(pair_result->second.entry.get()); 363 EXPECT_EQ("file5", pair_result->second.entry->base_name()); 364 365 // Confirm that the first non existent file is not found. 366 pair_result.reset(); 367 resource_metadata_->GetResourceEntryPairByPathsOnUIThread( 368 base::FilePath::FromUTF8Unsafe("drive/root/dir1/non_existent"), 369 base::FilePath::FromUTF8Unsafe("drive/root/dir1/file5"), 370 google_apis::test_util::CreateCopyResultCallback(&pair_result)); 371 test_util::RunBlockingPoolTask(); 372 // The first entry should not be found. 373 EXPECT_EQ(FILE_ERROR_NOT_FOUND, pair_result->first.error); 374 EXPECT_EQ(base::FilePath::FromUTF8Unsafe("drive/root/dir1/non_existent"), 375 pair_result->first.path); 376 ASSERT_FALSE(pair_result->first.entry.get()); 377 // The second entry should not be found, because the first one failed. 378 EXPECT_EQ(FILE_ERROR_FAILED, pair_result->second.error); 379 EXPECT_EQ(base::FilePath(), pair_result->second.path); 380 ASSERT_FALSE(pair_result->second.entry.get()); 381 382 // Confirm that the second non existent file is not found. 383 pair_result.reset(); 384 resource_metadata_->GetResourceEntryPairByPathsOnUIThread( 385 base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"), 386 base::FilePath::FromUTF8Unsafe("drive/root/dir1/non_existent"), 387 google_apis::test_util::CreateCopyResultCallback(&pair_result)); 388 test_util::RunBlockingPoolTask(); 389 // The first entry should be found. 390 EXPECT_EQ(FILE_ERROR_OK, pair_result->first.error); 391 EXPECT_EQ(base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"), 392 pair_result->first.path); 393 ASSERT_TRUE(pair_result->first.entry.get()); 394 EXPECT_EQ("file4", pair_result->first.entry->base_name()); 395 // The second entry should not be found. 396 EXPECT_EQ(FILE_ERROR_NOT_FOUND, pair_result->second.error); 397 EXPECT_EQ(base::FilePath::FromUTF8Unsafe("drive/root/dir1/non_existent"), 398 pair_result->second.path); 399 ASSERT_FALSE(pair_result->second.entry.get()); 400 } 401 402 TEST_F(ResourceMetadataTestOnUIThread, MoveEntryToDirectory) { 403 FileError error = FILE_ERROR_FAILED; 404 base::FilePath drive_file_path; 405 scoped_ptr<ResourceEntry> entry; 406 407 // Move file8 to drive/dir1. 408 resource_metadata_->MoveEntryToDirectoryOnUIThread( 409 base::FilePath::FromUTF8Unsafe("drive/root/dir2/file8"), 410 base::FilePath::FromUTF8Unsafe("drive/root/dir1"), 411 google_apis::test_util::CreateCopyResultCallback( 412 &error, &drive_file_path)); 413 test_util::RunBlockingPoolTask(); 414 EXPECT_EQ(FILE_ERROR_OK, error); 415 EXPECT_EQ(base::FilePath::FromUTF8Unsafe("drive/root/dir1/file8"), 416 drive_file_path); 417 418 // Look up the entry by its resource id and make sure it really moved. 419 resource_metadata_->GetResourceEntryByIdOnUIThread( 420 "resource_id:file8", 421 google_apis::test_util::CreateCopyResultCallback(&error, &entry)); 422 test_util::RunBlockingPoolTask(); 423 EXPECT_EQ(FILE_ERROR_OK, error); 424 425 // Move non-existent file to drive/dir1. This should fail. 426 resource_metadata_->MoveEntryToDirectoryOnUIThread( 427 base::FilePath::FromUTF8Unsafe("drive/root/dir2/file8"), 428 base::FilePath::FromUTF8Unsafe("drive/root/dir1"), 429 google_apis::test_util::CreateCopyResultCallback( 430 &error, &drive_file_path)); 431 test_util::RunBlockingPoolTask(); 432 EXPECT_EQ(FILE_ERROR_NOT_FOUND, error); 433 EXPECT_EQ(base::FilePath(), drive_file_path); 434 435 // Move existing file to non-existent directory. This should fail. 436 resource_metadata_->MoveEntryToDirectoryOnUIThread( 437 base::FilePath::FromUTF8Unsafe("drive/root/dir1/file8"), 438 base::FilePath::FromUTF8Unsafe("drive/root/dir4"), 439 google_apis::test_util::CreateCopyResultCallback( 440 &error, &drive_file_path)); 441 test_util::RunBlockingPoolTask(); 442 EXPECT_EQ(FILE_ERROR_NOT_FOUND, error); 443 EXPECT_EQ(base::FilePath(), drive_file_path); 444 445 // Move existing file to existing file (non-directory). This should fail. 446 resource_metadata_->MoveEntryToDirectoryOnUIThread( 447 base::FilePath::FromUTF8Unsafe("drive/root/dir1/file8"), 448 base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"), 449 google_apis::test_util::CreateCopyResultCallback( 450 &error, &drive_file_path)); 451 test_util::RunBlockingPoolTask(); 452 EXPECT_EQ(FILE_ERROR_NOT_A_DIRECTORY, error); 453 EXPECT_EQ(base::FilePath(), drive_file_path); 454 455 // Move the file to root. 456 resource_metadata_->MoveEntryToDirectoryOnUIThread( 457 base::FilePath::FromUTF8Unsafe("drive/root/dir1/file8"), 458 base::FilePath::FromUTF8Unsafe("drive/root"), 459 google_apis::test_util::CreateCopyResultCallback( 460 &error, &drive_file_path)); 461 test_util::RunBlockingPoolTask(); 462 EXPECT_EQ(FILE_ERROR_OK, error); 463 EXPECT_EQ(base::FilePath::FromUTF8Unsafe("drive/root/file8"), 464 drive_file_path); 465 466 // Move the file from root. 467 resource_metadata_->MoveEntryToDirectoryOnUIThread( 468 base::FilePath::FromUTF8Unsafe("drive/root/file8"), 469 base::FilePath::FromUTF8Unsafe("drive/root/dir2"), 470 google_apis::test_util::CreateCopyResultCallback( 471 &error, &drive_file_path)); 472 test_util::RunBlockingPoolTask(); 473 EXPECT_EQ(FILE_ERROR_OK, error); 474 EXPECT_EQ(base::FilePath::FromUTF8Unsafe("drive/root/dir2/file8"), 475 drive_file_path); 476 477 // Make sure file is still ok. 478 resource_metadata_->GetResourceEntryByIdOnUIThread( 479 "resource_id:file8", 480 google_apis::test_util::CreateCopyResultCallback(&error, &entry)); 481 test_util::RunBlockingPoolTask(); 482 EXPECT_EQ(FILE_ERROR_OK, error); 483 } 484 485 TEST_F(ResourceMetadataTestOnUIThread, RenameEntry) { 486 FileError error = FILE_ERROR_FAILED; 487 base::FilePath drive_file_path; 488 scoped_ptr<ResourceEntry> entry; 489 490 // Rename file8 to file11. 491 resource_metadata_->RenameEntryOnUIThread( 492 base::FilePath::FromUTF8Unsafe("drive/root/dir2/file8"), 493 "file11", 494 google_apis::test_util::CreateCopyResultCallback( 495 &error, &drive_file_path)); 496 test_util::RunBlockingPoolTask(); 497 EXPECT_EQ(FILE_ERROR_OK, error); 498 EXPECT_EQ(base::FilePath::FromUTF8Unsafe("drive/root/dir2/file11"), 499 drive_file_path); 500 501 // Lookup the file by resource id to make sure the file actually got renamed. 502 resource_metadata_->GetResourceEntryByIdOnUIThread( 503 "resource_id:file8", 504 google_apis::test_util::CreateCopyResultCallback(&error, &entry)); 505 test_util::RunBlockingPoolTask(); 506 EXPECT_EQ(FILE_ERROR_OK, error); 507 508 // Rename to file7 to force a duplicate name. 509 resource_metadata_->RenameEntryOnUIThread( 510 base::FilePath::FromUTF8Unsafe("drive/root/dir2/file11"), 511 "file7", 512 google_apis::test_util::CreateCopyResultCallback( 513 &error, &drive_file_path)); 514 test_util::RunBlockingPoolTask(); 515 EXPECT_EQ(FILE_ERROR_OK, error); 516 EXPECT_EQ(base::FilePath::FromUTF8Unsafe("drive/root/dir2/file7 (1)"), 517 drive_file_path); 518 519 // Rename to same name. This should fail. 520 resource_metadata_->RenameEntryOnUIThread( 521 base::FilePath::FromUTF8Unsafe("drive/root/dir2/file7 (1)"), 522 "file7 (1)", 523 google_apis::test_util::CreateCopyResultCallback( 524 &error, &drive_file_path)); 525 test_util::RunBlockingPoolTask(); 526 EXPECT_EQ(FILE_ERROR_EXISTS, error); 527 EXPECT_EQ(base::FilePath(), drive_file_path); 528 529 // Rename non-existent. 530 resource_metadata_->RenameEntryOnUIThread( 531 base::FilePath::FromUTF8Unsafe("drive/root/dir2/file11"), 532 "file11", 533 google_apis::test_util::CreateCopyResultCallback( 534 &error, &drive_file_path)); 535 test_util::RunBlockingPoolTask(); 536 EXPECT_EQ(FILE_ERROR_NOT_FOUND, error); 537 EXPECT_EQ(base::FilePath(), drive_file_path); 538 } 539 540 TEST_F(ResourceMetadataTestOnUIThread, RefreshDirectory_EmptyMap) { 541 base::FilePath kDirectoryPath(FILE_PATH_LITERAL("drive/root/dir1")); 542 const int64 kNewChangestamp = kTestChangestamp + 1; 543 544 // Read the directory. 545 FileError error = FILE_ERROR_FAILED; 546 scoped_ptr<ResourceEntryVector> entries; 547 entries = ReadDirectoryByPathSync(base::FilePath(kDirectoryPath)); 548 ASSERT_TRUE(entries.get()); 549 // "file4", "file5", "dir3" should exist in drive/dir1. 550 ASSERT_EQ(3U, entries->size()); 551 std::vector<std::string> base_names = GetSortedBaseNames(*entries); 552 EXPECT_EQ("dir3", base_names[0]); 553 EXPECT_EQ("file4", base_names[1]); 554 EXPECT_EQ("file5", base_names[2]); 555 556 // Get the directory. 557 scoped_ptr<ResourceEntry> dir1_proto; 558 dir1_proto = GetResourceEntryByPathSync(kDirectoryPath); 559 ASSERT_TRUE(dir1_proto.get()); 560 // The changestamp should be initially kTestChangestamp. 561 EXPECT_EQ(kTestChangestamp, 562 dir1_proto->directory_specific_info().changestamp()); 563 564 // Update the directory with an empty map. 565 base::FilePath file_path; 566 ResourceEntryMap entry_map; 567 resource_metadata_->RefreshDirectoryOnUIThread( 568 DirectoryFetchInfo(dir1_proto->resource_id(), kNewChangestamp), 569 entry_map, 570 google_apis::test_util::CreateCopyResultCallback(&error, &file_path)); 571 test_util::RunBlockingPoolTask(); 572 EXPECT_EQ(FILE_ERROR_OK, error); 573 EXPECT_EQ(kDirectoryPath, file_path); 574 575 // Get the directory again. 576 dir1_proto = GetResourceEntryByPathSync(kDirectoryPath); 577 ASSERT_TRUE(dir1_proto.get()); 578 // The new changestamp should be set. 579 EXPECT_EQ(kNewChangestamp, 580 dir1_proto->directory_specific_info().changestamp()); 581 582 // Read the directory again. 583 entries = ReadDirectoryByPathSync(base::FilePath(kDirectoryPath)); 584 ASSERT_TRUE(entries.get()); 585 } 586 587 TEST_F(ResourceMetadataTestOnUIThread, RefreshDirectory_NonEmptyMap) { 588 base::FilePath kDirectoryPath(FILE_PATH_LITERAL("drive/root/dir1")); 589 const int64 kNewChangestamp = kTestChangestamp + 1; 590 591 // Read the directory. 592 FileError error = FILE_ERROR_FAILED; 593 scoped_ptr<ResourceEntryVector> entries; 594 entries = ReadDirectoryByPathSync(kDirectoryPath); 595 ASSERT_TRUE(entries.get()); 596 // "file4", "file5", "dir3" should exist in drive/dir1. 597 ASSERT_EQ(3U, entries->size()); 598 std::vector<std::string> base_names = GetSortedBaseNames(*entries); 599 EXPECT_EQ("dir3", base_names[0]); 600 EXPECT_EQ("file4", base_names[1]); 601 EXPECT_EQ("file5", base_names[2]); 602 603 // Get the directory dir1. 604 scoped_ptr<ResourceEntry> dir1_proto; 605 dir1_proto = GetResourceEntryByPathSync(kDirectoryPath); 606 ASSERT_TRUE(dir1_proto.get()); 607 // The changestamp should be initially kTestChangestamp. 608 EXPECT_EQ(kTestChangestamp, 609 dir1_proto->directory_specific_info().changestamp()); 610 611 // Get the directory dir2 (existing non-child directory). 612 // This directory will be moved to "drive/dir1/dir2". 613 scoped_ptr<ResourceEntry> dir2_proto; 614 dir2_proto = GetResourceEntryByPathSync( 615 base::FilePath::FromUTF8Unsafe("drive/root/dir2")); 616 ASSERT_TRUE(dir2_proto.get()); 617 EXPECT_EQ(kTestChangestamp, 618 dir2_proto->directory_specific_info().changestamp()); 619 // Change the parent resource ID, as dir2 will be moved to "drive/dir1/dir2". 620 dir2_proto->set_parent_resource_id(dir1_proto->resource_id()); 621 622 // Get the directory dir3 (existing child directory). 623 // This directory will remain as "drive/dir1/dir3". 624 scoped_ptr<ResourceEntry> dir3_proto; 625 dir3_proto = GetResourceEntryByPathSync( 626 base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3")); 627 ASSERT_TRUE(dir3_proto.get()); 628 EXPECT_EQ(kTestChangestamp, 629 dir3_proto->directory_specific_info().changestamp()); 630 631 // Create a map. 632 ResourceEntryMap entry_map; 633 634 // Add a new file to the map. 635 ResourceEntry new_file; 636 new_file.set_title("new_file"); 637 new_file.set_resource_id("new_file_id"); 638 new_file.set_parent_resource_id(dir1_proto->resource_id()); 639 entry_map["new_file_id"] = new_file; 640 641 // Add a new directory to the map. 642 ResourceEntry new_directory; 643 new_directory.set_title("new_directory"); 644 new_directory.set_resource_id("new_directory_id"); 645 new_directory.set_parent_resource_id(dir1_proto->resource_id()); 646 new_directory.mutable_file_info()->set_is_directory(true); 647 entry_map["new_directory_id"] = new_directory; 648 649 // Add dir2 and dir3 as well. 650 entry_map[dir2_proto->resource_id()] = *dir2_proto; 651 entry_map[dir3_proto->resource_id()] = *dir3_proto; 652 653 // Update the directory with the map. 654 base::FilePath file_path; 655 resource_metadata_->RefreshDirectoryOnUIThread( 656 DirectoryFetchInfo(dir1_proto->resource_id(), kNewChangestamp), 657 entry_map, 658 google_apis::test_util::CreateCopyResultCallback(&error, &file_path)); 659 test_util::RunBlockingPoolTask(); 660 EXPECT_EQ(FILE_ERROR_OK, error); 661 EXPECT_EQ(kDirectoryPath, file_path); 662 663 // Get the directory again. 664 dir1_proto = GetResourceEntryByPathSync(kDirectoryPath); 665 ASSERT_TRUE(dir1_proto.get()); 666 // The new changestamp should be set. 667 EXPECT_EQ(kNewChangestamp, 668 dir1_proto->directory_specific_info().changestamp()); 669 670 // Read the directory again. 671 entries = ReadDirectoryByPathSync(kDirectoryPath); 672 ASSERT_TRUE(entries.get()); 673 // "new_file", "new_directory", "dir2" should now be added. 674 base_names = GetSortedBaseNames(*entries); 675 EXPECT_EQ(1, std::count(base_names.begin(), base_names.end(), "dir2")); 676 EXPECT_EQ(1, 677 std::count(base_names.begin(), base_names.end(), "new_directory")); 678 EXPECT_EQ(1, 679 std::count(base_names.begin(), base_names.end(), "new_file")); 680 681 // Get the new directory. 682 scoped_ptr<ResourceEntry> new_directory_proto; 683 new_directory_proto = GetResourceEntryByPathSync( 684 base::FilePath::FromUTF8Unsafe("drive/root/dir1/new_directory")); 685 ASSERT_TRUE(new_directory_proto.get()); 686 // The changestamp should be 0 for a new directory. 687 EXPECT_EQ(0, new_directory_proto->directory_specific_info().changestamp()); 688 689 // Get the directory dir3 (existing child directory) again. 690 dir3_proto = GetResourceEntryByPathSync( 691 base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3")); 692 ASSERT_TRUE(dir3_proto.get()); 693 // The changestamp should not be changed. 694 EXPECT_EQ(kTestChangestamp, 695 dir3_proto->directory_specific_info().changestamp()); 696 697 // Read the directory dir3. The contents should remain. 698 // See the comment at Init() for the contents of the dir3. 699 entries = ReadDirectoryByPathSync( 700 base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3")); 701 ASSERT_TRUE(entries.get()); 702 ASSERT_EQ(2U, entries->size()); 703 704 // Get the directory dir2 (existing non-child directory) again using the 705 // old path. This should fail, as dir2 is now moved to drive/dir1/dir2. 706 dir2_proto = GetResourceEntryByPathSync( 707 base::FilePath::FromUTF8Unsafe("drive/root/dir2")); 708 ASSERT_FALSE(dir2_proto.get()); 709 710 // Get the directory dir2 (existing non-child directory) again using the 711 // new path. This should succeed. 712 dir2_proto = GetResourceEntryByPathSync( 713 base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir2")); 714 ASSERT_TRUE(dir2_proto.get()); 715 // The changestamp should not be changed. 716 EXPECT_EQ(kTestChangestamp, 717 dir2_proto->directory_specific_info().changestamp()); 718 719 // Read the directory dir2. The contents should remain. 720 // See the comment at Init() for the contents of the dir2. 721 entries = ReadDirectoryByPathSync( 722 base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir2")); 723 ASSERT_TRUE(entries.get()); 724 ASSERT_EQ(3U, entries->size()); 725 } 726 727 TEST_F(ResourceMetadataTestOnUIThread, RefreshDirectory_WrongParentResourceId) { 728 base::FilePath kDirectoryPath(FILE_PATH_LITERAL("drive/root/dir1")); 729 const int64 kNewChangestamp = kTestChangestamp + 1; 730 731 // Get the directory dir1. 732 scoped_ptr<ResourceEntry> dir1_proto; 733 dir1_proto = GetResourceEntryByPathSync(kDirectoryPath); 734 ASSERT_TRUE(dir1_proto.get()); 735 736 // Create a map and add a new file to it. 737 ResourceEntryMap entry_map; 738 ResourceEntry new_file; 739 new_file.set_title("new_file"); 740 new_file.set_resource_id("new_file_id"); 741 // Set a random parent resource ID. This entry should not be added because 742 // the parent resource ID does not match dir1_proto->resource_id(). 743 new_file.set_parent_resource_id("some-random-resource-id"); 744 entry_map["new_file_id"] = new_file; 745 746 // Update the directory with the map. 747 base::FilePath file_path; 748 FileError error = FILE_ERROR_FAILED; 749 resource_metadata_->RefreshDirectoryOnUIThread( 750 DirectoryFetchInfo(dir1_proto->resource_id(), kNewChangestamp), 751 entry_map, 752 google_apis::test_util::CreateCopyResultCallback(&error, &file_path)); 753 test_util::RunBlockingPoolTask(); 754 EXPECT_EQ(FILE_ERROR_OK, error); 755 EXPECT_EQ(kDirectoryPath, file_path); 756 757 // Read the directory. Confirm that the new file is not added. 758 scoped_ptr<ResourceEntryVector> entries; 759 entries = ReadDirectoryByPathSync(kDirectoryPath); 760 ASSERT_TRUE(entries.get()); 761 std::vector<std::string> base_names = GetSortedBaseNames(*entries); 762 EXPECT_EQ(0, std::count(base_names.begin(), base_names.end(), "new_file")); 763 } 764 765 TEST_F(ResourceMetadataTestOnUIThread, AddEntry) { 766 FileError error = FILE_ERROR_FAILED; 767 base::FilePath drive_file_path; 768 769 // Add a file to dir3. 770 ResourceEntry file_entry = CreateFileEntry("file100", "resource_id:dir3"); 771 resource_metadata_->AddEntryOnUIThread( 772 file_entry, 773 google_apis::test_util::CreateCopyResultCallback( 774 &error, &drive_file_path)); 775 test_util::RunBlockingPoolTask(); 776 EXPECT_EQ(FILE_ERROR_OK, error); 777 EXPECT_EQ(base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3/file100"), 778 drive_file_path); 779 780 // Add a directory. 781 ResourceEntry dir_entry = CreateDirectoryEntry("dir101", "resource_id:dir1"); 782 resource_metadata_->AddEntryOnUIThread( 783 dir_entry, 784 google_apis::test_util::CreateCopyResultCallback( 785 &error, &drive_file_path)); 786 test_util::RunBlockingPoolTask(); 787 EXPECT_EQ(FILE_ERROR_OK, error); 788 EXPECT_EQ(base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir101"), 789 drive_file_path); 790 791 // Add to an invalid parent. 792 ResourceEntry file_entry3 = CreateFileEntry("file103", "resource_id:invalid"); 793 resource_metadata_->AddEntryOnUIThread( 794 file_entry3, 795 google_apis::test_util::CreateCopyResultCallback( 796 &error, &drive_file_path)); 797 test_util::RunBlockingPoolTask(); 798 EXPECT_EQ(FILE_ERROR_NOT_FOUND, error); 799 800 // Add an existing file. 801 resource_metadata_->AddEntryOnUIThread( 802 file_entry, 803 google_apis::test_util::CreateCopyResultCallback( 804 &error, &drive_file_path)); 805 test_util::RunBlockingPoolTask(); 806 EXPECT_EQ(FILE_ERROR_EXISTS, error); 807 } 808 809 TEST_F(ResourceMetadataTestOnUIThread, Reset) { 810 // The grand root has "root" which is not empty. 811 scoped_ptr<ResourceEntryVector> entries; 812 entries = ReadDirectoryByPathSync( 813 base::FilePath::FromUTF8Unsafe("drive/root")); 814 ASSERT_TRUE(entries.get()); 815 ASSERT_FALSE(entries->empty()); 816 817 // Reset. 818 FileError error = FILE_ERROR_FAILED; 819 resource_metadata_->ResetOnUIThread( 820 google_apis::test_util::CreateCopyResultCallback(&error)); 821 test_util::RunBlockingPoolTask(); 822 EXPECT_EQ(FILE_ERROR_OK, error); 823 824 base::FilePath drive_file_path; 825 scoped_ptr<ResourceEntry> entry; 826 827 // change stamp should be reset. 828 int64 changestamp = -1; 829 resource_metadata_->GetLargestChangestampOnUIThread( 830 google_apis::test_util::CreateCopyResultCallback(&changestamp)); 831 test_util::RunBlockingPoolTask(); 832 EXPECT_EQ(0, changestamp); 833 834 // root should continue to exist. 835 entry = GetResourceEntryByPathSync(base::FilePath::FromUTF8Unsafe("drive")); 836 ASSERT_TRUE(entry.get()); 837 EXPECT_EQ("drive", entry->base_name()); 838 ASSERT_TRUE(entry->file_info().is_directory()); 839 EXPECT_EQ(util::kDriveGrandRootSpecialResourceId, entry->resource_id()); 840 841 // There is "other", which are both empty. 842 entries = ReadDirectoryByPathSync(base::FilePath::FromUTF8Unsafe("drive")); 843 ASSERT_TRUE(entries.get()); 844 EXPECT_EQ(1U, entries->size()); 845 846 scoped_ptr<ResourceEntryVector> entries_in_other = 847 ReadDirectoryByPathSync(base::FilePath::FromUTF8Unsafe("drive/other")); 848 ASSERT_TRUE(entries_in_other.get()); 849 EXPECT_TRUE(entries_in_other->empty()); 850 } 851 852 // Tests for methods running on the blocking task runner. 853 class ResourceMetadataTest : public testing::Test { 854 protected: 855 virtual void SetUp() OVERRIDE { 856 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 857 858 metadata_storage_.reset(new ResourceMetadataStorage( 859 temp_dir_.path(), base::MessageLoopProxy::current().get())); 860 ASSERT_TRUE(metadata_storage_->Initialize()); 861 862 resource_metadata_.reset(new ResourceMetadata( 863 metadata_storage_.get(), base::MessageLoopProxy::current())); 864 865 ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->Initialize()); 866 867 SetUpEntries(resource_metadata_.get()); 868 } 869 870 base::ScopedTempDir temp_dir_; 871 content::TestBrowserThreadBundle thread_bundle_; 872 scoped_ptr<ResourceMetadataStorage, test_util::DestroyHelperForTests> 873 metadata_storage_; 874 scoped_ptr<ResourceMetadata, test_util::DestroyHelperForTests> 875 resource_metadata_; 876 }; 877 878 TEST_F(ResourceMetadataTest, RefreshEntry) { 879 base::FilePath drive_file_path; 880 ResourceEntry entry; 881 882 // Get file9. 883 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath( 884 base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3/file9"), &entry)); 885 EXPECT_EQ("file9", entry.base_name()); 886 EXPECT_TRUE(!entry.file_info().is_directory()); 887 EXPECT_EQ("md5:file9", entry.file_specific_info().md5()); 888 889 // Rename it. 890 ResourceEntry file_entry(entry); 891 file_entry.set_title("file100"); 892 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->RefreshEntry(file_entry)); 893 894 EXPECT_EQ( 895 "drive/root/dir1/dir3/file100", 896 resource_metadata_->GetFilePath(file_entry.resource_id()).AsUTF8Unsafe()); 897 entry.Clear(); 898 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById( 899 file_entry.resource_id(), &entry)); 900 EXPECT_EQ("file100", entry.base_name()); 901 EXPECT_TRUE(!entry.file_info().is_directory()); 902 EXPECT_EQ("md5:file9", entry.file_specific_info().md5()); 903 904 // Update the file md5. 905 const std::string updated_md5("md5:updated"); 906 file_entry = entry; 907 file_entry.mutable_file_specific_info()->set_md5(updated_md5); 908 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->RefreshEntry(file_entry)); 909 910 EXPECT_EQ( 911 "drive/root/dir1/dir3/file100", 912 resource_metadata_->GetFilePath(file_entry.resource_id()).AsUTF8Unsafe()); 913 entry.Clear(); 914 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById( 915 file_entry.resource_id(), &entry)); 916 EXPECT_EQ("file100", entry.base_name()); 917 EXPECT_TRUE(!entry.file_info().is_directory()); 918 EXPECT_EQ(updated_md5, entry.file_specific_info().md5()); 919 920 // Make sure we get the same thing from GetResourceEntryByPath. 921 entry.Clear(); 922 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath( 923 base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3/file100"), &entry)); 924 EXPECT_EQ("file100", entry.base_name()); 925 ASSERT_TRUE(!entry.file_info().is_directory()); 926 EXPECT_EQ(updated_md5, entry.file_specific_info().md5()); 927 928 // Get dir2. 929 entry.Clear(); 930 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath( 931 base::FilePath::FromUTF8Unsafe("drive/root/dir2"), &entry)); 932 EXPECT_EQ("dir2", entry.base_name()); 933 ASSERT_TRUE(entry.file_info().is_directory()); 934 935 // Change the name to dir100 and change the parent to drive/dir1/dir3. 936 ResourceEntry dir_entry(entry); 937 dir_entry.set_title("dir100"); 938 dir_entry.set_parent_resource_id("resource_id:dir3"); 939 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->RefreshEntry(dir_entry)); 940 941 EXPECT_EQ( 942 "drive/root/dir1/dir3/dir100", 943 resource_metadata_->GetFilePath(dir_entry.resource_id()).AsUTF8Unsafe()); 944 entry.Clear(); 945 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById( 946 dir_entry.resource_id(), &entry)); 947 EXPECT_EQ("dir100", entry.base_name()); 948 EXPECT_TRUE(entry.file_info().is_directory()); 949 EXPECT_EQ("resource_id:dir2", entry.resource_id()); 950 951 // Make sure the children have moved over. Test file6. 952 entry.Clear(); 953 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath( 954 base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3/dir100/file6"), 955 &entry)); 956 EXPECT_EQ("file6", entry.base_name()); 957 958 // Make sure dir2 no longer exists. 959 EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->GetResourceEntryByPath( 960 base::FilePath::FromUTF8Unsafe("drive/root/dir2"), &entry)); 961 962 // Cannot refresh root. 963 dir_entry.Clear(); 964 dir_entry.set_resource_id(util::kDriveGrandRootSpecialResourceId); 965 dir_entry.set_title("new-root-name"); 966 dir_entry.set_parent_resource_id("resource_id:dir1"); 967 EXPECT_EQ(FILE_ERROR_INVALID_OPERATION, 968 resource_metadata_->RefreshEntry(dir_entry)); 969 } 970 971 TEST_F(ResourceMetadataTest, GetChildDirectories) { 972 std::set<base::FilePath> child_directories; 973 974 // file9: not a directory, so no children. 975 resource_metadata_->GetChildDirectories("resource_id:file9", 976 &child_directories); 977 EXPECT_TRUE(child_directories.empty()); 978 979 // dir2: no child directories. 980 resource_metadata_->GetChildDirectories("resource_id:dir2", 981 &child_directories); 982 EXPECT_TRUE(child_directories.empty()); 983 984 // dir1: dir3 is the only child 985 resource_metadata_->GetChildDirectories("resource_id:dir1", 986 &child_directories); 987 EXPECT_EQ(1u, child_directories.size()); 988 EXPECT_EQ(1u, child_directories.count( 989 base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3"))); 990 child_directories.clear(); 991 992 // Add a few more directories to make sure deeper nesting works. 993 // dir2/dir100 994 // dir2/dir101 995 // dir2/dir101/dir102 996 // dir2/dir101/dir103 997 // dir2/dir101/dir104 998 // dir2/dir101/dir102/dir105 999 // dir2/dir101/dir102/dir105/dir106 1000 // dir2/dir101/dir102/dir105/dir106/dir107 1001 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( 1002 CreateDirectoryEntry("dir100", "resource_id:dir2"))); 1003 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( 1004 CreateDirectoryEntry("dir101", "resource_id:dir2"))); 1005 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( 1006 CreateDirectoryEntry("dir102", "resource_id:dir101"))); 1007 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( 1008 CreateDirectoryEntry("dir103", "resource_id:dir101"))); 1009 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( 1010 CreateDirectoryEntry("dir104", "resource_id:dir101"))); 1011 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( 1012 CreateDirectoryEntry("dir105", "resource_id:dir102"))); 1013 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( 1014 CreateDirectoryEntry("dir106", "resource_id:dir105"))); 1015 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( 1016 CreateDirectoryEntry("dir107", "resource_id:dir106"))); 1017 1018 resource_metadata_->GetChildDirectories("resource_id:dir2", 1019 &child_directories); 1020 EXPECT_EQ(8u, child_directories.size()); 1021 EXPECT_EQ(1u, child_directories.count(base::FilePath::FromUTF8Unsafe( 1022 "drive/root/dir2/dir101"))); 1023 EXPECT_EQ(1u, child_directories.count(base::FilePath::FromUTF8Unsafe( 1024 "drive/root/dir2/dir101/dir104"))); 1025 EXPECT_EQ(1u, child_directories.count(base::FilePath::FromUTF8Unsafe( 1026 "drive/root/dir2/dir101/dir102/dir105/dir106/dir107"))); 1027 } 1028 1029 TEST_F(ResourceMetadataTest, RemoveEntry) { 1030 // Make sure file9 is found. 1031 const std::string file9_resource_id = "resource_id:file9"; 1032 ResourceEntry entry; 1033 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById( 1034 file9_resource_id, &entry)); 1035 EXPECT_EQ("file9", entry.base_name()); 1036 1037 // Remove file9. 1038 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->RemoveEntry(file9_resource_id)); 1039 1040 // file9 should no longer exist. 1041 EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->GetResourceEntryById( 1042 file9_resource_id, &entry)); 1043 1044 // Look for dir3. 1045 const std::string dir3_resource_id = "resource_id:dir3"; 1046 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById( 1047 dir3_resource_id, &entry)); 1048 EXPECT_EQ("dir3", entry.base_name()); 1049 1050 // Remove dir3. 1051 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->RemoveEntry(dir3_resource_id)); 1052 1053 // dir3 should no longer exist. 1054 EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->GetResourceEntryById( 1055 dir3_resource_id, &entry)); 1056 1057 // Remove unknown resource_id using RemoveEntry. 1058 EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->RemoveEntry("foo")); 1059 1060 // Try removing root. This should fail. 1061 EXPECT_EQ(FILE_ERROR_ACCESS_DENIED, resource_metadata_->RemoveEntry( 1062 util::kDriveGrandRootSpecialResourceId)); 1063 } 1064 1065 TEST_F(ResourceMetadataTest, Iterate) { 1066 scoped_ptr<ResourceMetadata::Iterator> it = resource_metadata_->GetIterator(); 1067 ASSERT_TRUE(it); 1068 1069 int file_count = 0, directory_count = 0; 1070 for (; !it->IsAtEnd(); it->Advance()) { 1071 if (!it->Get().file_info().is_directory()) 1072 ++file_count; 1073 else 1074 ++directory_count; 1075 } 1076 1077 EXPECT_EQ(7, file_count); 1078 EXPECT_EQ(6, directory_count); 1079 } 1080 1081 } // namespace internal 1082 } // namespace drive 1083