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/strings/stringprintf.h" 13 #include "chrome/browser/chromeos/drive/drive.pb.h" 14 #include "chrome/browser/chromeos/drive/fake_free_disk_space_getter.h" 15 #include "chrome/browser/chromeos/drive/file_cache.h" 16 #include "chrome/browser/chromeos/drive/file_system_util.h" 17 #include "chrome/browser/chromeos/drive/test_util.h" 18 #include "content/public/test/test_browser_thread_bundle.h" 19 #include "testing/gtest/include/gtest/gtest.h" 20 21 namespace drive { 22 namespace internal { 23 namespace { 24 25 // The changestamp of the resource metadata used in 26 // ResourceMetadataTest. 27 const int64 kTestChangestamp = 100; 28 29 // Returns the sorted base names from |entries|. 30 std::vector<std::string> GetSortedBaseNames( 31 const ResourceEntryVector& entries) { 32 std::vector<std::string> base_names; 33 for (size_t i = 0; i < entries.size(); ++i) 34 base_names.push_back(entries[i].base_name()); 35 std::sort(base_names.begin(), base_names.end()); 36 37 return base_names; 38 } 39 40 // Creates a ResourceEntry for a directory with explicitly set resource_id. 41 ResourceEntry CreateDirectoryEntryWithResourceId( 42 const std::string& title, 43 const std::string& resource_id, 44 const std::string& parent_local_id) { 45 ResourceEntry entry; 46 entry.set_title(title); 47 entry.set_resource_id(resource_id); 48 entry.set_parent_local_id(parent_local_id); 49 entry.mutable_file_info()->set_is_directory(true); 50 entry.mutable_directory_specific_info()->set_changestamp(kTestChangestamp); 51 return entry; 52 } 53 54 // Creates a ResourceEntry for a directory. 55 ResourceEntry CreateDirectoryEntry(const std::string& title, 56 const std::string& parent_local_id) { 57 return CreateDirectoryEntryWithResourceId( 58 title, "id:" + title, parent_local_id); 59 } 60 61 // Creates a ResourceEntry for a file with explicitly set resource_id. 62 ResourceEntry CreateFileEntryWithResourceId( 63 const std::string& title, 64 const std::string& resource_id, 65 const std::string& parent_local_id) { 66 ResourceEntry entry; 67 entry.set_title(title); 68 entry.set_resource_id(resource_id); 69 entry.set_parent_local_id(parent_local_id); 70 entry.mutable_file_info()->set_is_directory(false); 71 entry.mutable_file_info()->set_size(1024); 72 entry.mutable_file_specific_info()->set_md5("md5:" + title); 73 return entry; 74 } 75 76 // Creates a ResourceEntry for a file. 77 ResourceEntry CreateFileEntry(const std::string& title, 78 const std::string& parent_local_id) { 79 return CreateFileEntryWithResourceId(title, "id:" + title, parent_local_id); 80 } 81 82 // Creates the following files/directories 83 // drive/root/dir1/ 84 // drive/root/dir2/ 85 // drive/root/dir1/dir3/ 86 // drive/root/dir1/file4 87 // drive/root/dir1/file5 88 // drive/root/dir2/file6 89 // drive/root/dir2/file7 90 // drive/root/dir2/file8 91 // drive/root/dir1/dir3/file9 92 // drive/root/dir1/dir3/file10 93 void SetUpEntries(ResourceMetadata* resource_metadata) { 94 std::string local_id; 95 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->GetIdByPath( 96 util::GetDriveMyDriveRootPath(), &local_id)); 97 const std::string root_local_id = local_id; 98 99 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry( 100 CreateDirectoryEntry("dir1", root_local_id), &local_id)); 101 const std::string local_id_dir1 = local_id; 102 103 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry( 104 CreateDirectoryEntry("dir2", root_local_id), &local_id)); 105 const std::string local_id_dir2 = local_id; 106 107 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry( 108 CreateDirectoryEntry("dir3", local_id_dir1), &local_id)); 109 const std::string local_id_dir3 = local_id; 110 111 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry( 112 CreateFileEntry("file4", local_id_dir1), &local_id)); 113 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry( 114 CreateFileEntry("file5", local_id_dir1), &local_id)); 115 116 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry( 117 CreateFileEntry("file6", local_id_dir2), &local_id)); 118 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry( 119 CreateFileEntry("file7", local_id_dir2), &local_id)); 120 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry( 121 CreateFileEntry("file8", local_id_dir2), &local_id)); 122 123 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry( 124 CreateFileEntry("file9", local_id_dir3), &local_id)); 125 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry( 126 CreateFileEntry("file10", local_id_dir3), &local_id)); 127 128 ASSERT_EQ(FILE_ERROR_OK, 129 resource_metadata->SetLargestChangestamp(kTestChangestamp)); 130 } 131 132 } // namespace 133 134 // Tests for methods running on the blocking task runner. 135 class ResourceMetadataTest : public testing::Test { 136 protected: 137 virtual void SetUp() OVERRIDE { 138 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 139 140 metadata_storage_.reset(new ResourceMetadataStorage( 141 temp_dir_.path(), base::MessageLoopProxy::current().get())); 142 ASSERT_TRUE(metadata_storage_->Initialize()); 143 144 fake_free_disk_space_getter_.reset(new FakeFreeDiskSpaceGetter); 145 cache_.reset(new FileCache(metadata_storage_.get(), 146 temp_dir_.path(), 147 base::MessageLoopProxy::current().get(), 148 fake_free_disk_space_getter_.get())); 149 ASSERT_TRUE(cache_->Initialize()); 150 151 resource_metadata_.reset(new ResourceMetadata( 152 metadata_storage_.get(), cache_.get(), 153 base::MessageLoopProxy::current())); 154 155 ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->Initialize()); 156 157 SetUpEntries(resource_metadata_.get()); 158 } 159 160 base::ScopedTempDir temp_dir_; 161 content::TestBrowserThreadBundle thread_bundle_; 162 scoped_ptr<ResourceMetadataStorage, test_util::DestroyHelperForTests> 163 metadata_storage_; 164 scoped_ptr<FakeFreeDiskSpaceGetter> fake_free_disk_space_getter_; 165 scoped_ptr<FileCache, test_util::DestroyHelperForTests> cache_; 166 scoped_ptr<ResourceMetadata, test_util::DestroyHelperForTests> 167 resource_metadata_; 168 }; 169 170 TEST_F(ResourceMetadataTest, LargestChangestamp) { 171 const int64 kChangestamp = 123456; 172 EXPECT_EQ(FILE_ERROR_OK, 173 resource_metadata_->SetLargestChangestamp(kChangestamp)); 174 int64 changestamp = 0; 175 EXPECT_EQ(FILE_ERROR_OK, 176 resource_metadata_->GetLargestChangestamp(&changestamp)); 177 EXPECT_EQ(kChangestamp, changestamp); 178 } 179 180 TEST_F(ResourceMetadataTest, GetResourceEntryByPath) { 181 // Confirm that an existing file is found. 182 ResourceEntry entry; 183 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath( 184 base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"), &entry)); 185 EXPECT_EQ("file4", entry.base_name()); 186 187 // Confirm that a non existing file is not found. 188 EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->GetResourceEntryByPath( 189 base::FilePath::FromUTF8Unsafe("drive/root/dir1/non_existing"), &entry)); 190 191 // Confirm that the root is found. 192 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath( 193 base::FilePath::FromUTF8Unsafe("drive"), &entry)); 194 195 // Confirm that a non existing file is not found at the root level. 196 EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->GetResourceEntryByPath( 197 base::FilePath::FromUTF8Unsafe("non_existing"), &entry)); 198 199 // Confirm that an entry is not found with a wrong root. 200 EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->GetResourceEntryByPath( 201 base::FilePath::FromUTF8Unsafe("non_existing/root"), &entry)); 202 } 203 204 TEST_F(ResourceMetadataTest, ReadDirectoryByPath) { 205 // Confirm that an existing directory is found. 206 ResourceEntryVector entries; 207 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->ReadDirectoryByPath( 208 base::FilePath::FromUTF8Unsafe("drive/root/dir1"), &entries)); 209 ASSERT_EQ(3U, entries.size()); 210 // The order is not guaranteed so we should sort the base names. 211 std::vector<std::string> base_names = GetSortedBaseNames(entries); 212 EXPECT_EQ("dir3", base_names[0]); 213 EXPECT_EQ("file4", base_names[1]); 214 EXPECT_EQ("file5", base_names[2]); 215 216 // Confirm that a non existing directory is not found. 217 EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->ReadDirectoryByPath( 218 base::FilePath::FromUTF8Unsafe("drive/root/non_existing"), &entries)); 219 220 // Confirm that reading a file results in FILE_ERROR_NOT_A_DIRECTORY. 221 EXPECT_EQ(FILE_ERROR_NOT_A_DIRECTORY, resource_metadata_->ReadDirectoryByPath( 222 base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"), &entries)); 223 } 224 225 TEST_F(ResourceMetadataTest, RefreshEntry) { 226 base::FilePath drive_file_path; 227 ResourceEntry entry; 228 229 // Get file9. 230 std::string file_id; 231 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath( 232 base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3/file9"), &file_id)); 233 EXPECT_EQ(FILE_ERROR_OK, 234 resource_metadata_->GetResourceEntryById(file_id, &entry)); 235 EXPECT_EQ("file9", entry.base_name()); 236 EXPECT_TRUE(!entry.file_info().is_directory()); 237 EXPECT_EQ("md5:file9", entry.file_specific_info().md5()); 238 239 // Rename it. 240 ResourceEntry file_entry(entry); 241 file_entry.set_title("file100"); 242 EXPECT_EQ(FILE_ERROR_OK, 243 resource_metadata_->RefreshEntry(file_entry)); 244 245 base::FilePath path; 246 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetFilePath(file_id, &path)); 247 EXPECT_EQ("drive/root/dir1/dir3/file100", path.AsUTF8Unsafe()); 248 entry.Clear(); 249 EXPECT_EQ(FILE_ERROR_OK, 250 resource_metadata_->GetResourceEntryById(file_id, &entry)); 251 EXPECT_EQ("file100", entry.base_name()); 252 EXPECT_TRUE(!entry.file_info().is_directory()); 253 EXPECT_EQ("md5:file9", entry.file_specific_info().md5()); 254 255 // Update the file md5. 256 const std::string updated_md5("md5:updated"); 257 file_entry = entry; 258 file_entry.mutable_file_specific_info()->set_md5(updated_md5); 259 EXPECT_EQ(FILE_ERROR_OK, 260 resource_metadata_->RefreshEntry(file_entry)); 261 262 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetFilePath(file_id, &path)); 263 EXPECT_EQ("drive/root/dir1/dir3/file100", path.AsUTF8Unsafe()); 264 entry.Clear(); 265 EXPECT_EQ(FILE_ERROR_OK, 266 resource_metadata_->GetResourceEntryById(file_id, &entry)); 267 EXPECT_EQ("file100", entry.base_name()); 268 EXPECT_TRUE(!entry.file_info().is_directory()); 269 EXPECT_EQ(updated_md5, entry.file_specific_info().md5()); 270 271 // Make sure we get the same thing from GetResourceEntryByPath. 272 entry.Clear(); 273 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath( 274 base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3/file100"), &entry)); 275 EXPECT_EQ("file100", entry.base_name()); 276 ASSERT_TRUE(!entry.file_info().is_directory()); 277 EXPECT_EQ(updated_md5, entry.file_specific_info().md5()); 278 279 // Get dir2. 280 entry.Clear(); 281 std::string dir_id; 282 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath( 283 base::FilePath::FromUTF8Unsafe("drive/root/dir2"), &dir_id)); 284 EXPECT_EQ(FILE_ERROR_OK, 285 resource_metadata_->GetResourceEntryById(dir_id, &entry)); 286 EXPECT_EQ("dir2", entry.base_name()); 287 ASSERT_TRUE(entry.file_info().is_directory()); 288 289 // Get dir3's ID. 290 std::string dir3_id; 291 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath( 292 base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3"), &dir3_id)); 293 294 // Change the name to dir100 and change the parent to drive/dir1/dir3. 295 ResourceEntry dir_entry(entry); 296 dir_entry.set_title("dir100"); 297 dir_entry.set_parent_local_id(dir3_id); 298 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->RefreshEntry(dir_entry)); 299 300 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetFilePath(dir_id, &path)); 301 EXPECT_EQ("drive/root/dir1/dir3/dir100", path.AsUTF8Unsafe()); 302 entry.Clear(); 303 EXPECT_EQ(FILE_ERROR_OK, 304 resource_metadata_->GetResourceEntryById(dir_id, &entry)); 305 EXPECT_EQ("dir100", entry.base_name()); 306 EXPECT_TRUE(entry.file_info().is_directory()); 307 EXPECT_EQ("id:dir2", entry.resource_id()); 308 309 // Make sure the children have moved over. Test file6. 310 entry.Clear(); 311 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath( 312 base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3/dir100/file6"), 313 &entry)); 314 EXPECT_EQ("file6", entry.base_name()); 315 316 // Make sure dir2 no longer exists. 317 EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->GetResourceEntryByPath( 318 base::FilePath::FromUTF8Unsafe("drive/root/dir2"), &entry)); 319 320 // Make sure that directory cannot move under a file. 321 dir_entry.set_parent_local_id(file_id); 322 EXPECT_EQ(FILE_ERROR_NOT_A_DIRECTORY, 323 resource_metadata_->RefreshEntry(dir_entry)); 324 325 // Cannot refresh root. 326 dir_entry.Clear(); 327 dir_entry.set_local_id(util::kDriveGrandRootLocalId); 328 dir_entry.set_title("new-root-name"); 329 dir_entry.set_parent_local_id(dir3_id); 330 EXPECT_EQ(FILE_ERROR_INVALID_OPERATION, 331 resource_metadata_->RefreshEntry(dir_entry)); 332 } 333 334 TEST_F(ResourceMetadataTest, RefreshEntry_ResourceIDCheck) { 335 // Get an entry with a non-empty resource ID. 336 ResourceEntry entry; 337 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath( 338 base::FilePath::FromUTF8Unsafe("drive/root/dir1"), &entry)); 339 EXPECT_FALSE(entry.resource_id().empty()); 340 341 // Add a new entry with an empty resource ID. 342 ResourceEntry new_entry; 343 new_entry.set_parent_local_id(entry.local_id()); 344 new_entry.set_title("new entry"); 345 std::string local_id; 346 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(new_entry, &local_id)); 347 348 // Try to refresh the new entry with a used resource ID. 349 new_entry.set_local_id(local_id); 350 new_entry.set_resource_id(entry.resource_id()); 351 EXPECT_EQ(FILE_ERROR_INVALID_OPERATION, 352 resource_metadata_->RefreshEntry(new_entry)); 353 } 354 355 TEST_F(ResourceMetadataTest, RefreshEntry_DoNotOverwriteCacheState) { 356 ResourceEntry entry; 357 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath( 358 base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"), &entry)); 359 360 // Try to set MD5 with RefreshEntry. 361 entry.mutable_file_specific_info()->mutable_cache_state()->set_md5("md5"); 362 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->RefreshEntry(entry)); 363 364 // Cache state is unchanged. 365 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath( 366 base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"), &entry)); 367 EXPECT_TRUE(entry.file_specific_info().cache_state().md5().empty()); 368 369 // Pin the file. 370 EXPECT_EQ(FILE_ERROR_OK, cache_->Pin(entry.local_id())); 371 372 // Try to clear the cache state with RefreshEntry. 373 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath( 374 base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"), &entry)); 375 entry.mutable_file_specific_info()->clear_cache_state(); 376 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->RefreshEntry(entry)); 377 378 // Cache state is not cleared. 379 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath( 380 base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"), &entry)); 381 EXPECT_TRUE(entry.file_specific_info().cache_state().is_pinned()); 382 } 383 384 TEST_F(ResourceMetadataTest, GetSubDirectoriesRecursively) { 385 std::set<base::FilePath> sub_directories; 386 387 // file9: not a directory, so no children. 388 std::string local_id; 389 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath( 390 base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3/file9"), &local_id)); 391 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetSubDirectoriesRecursively( 392 local_id, &sub_directories)); 393 EXPECT_TRUE(sub_directories.empty()); 394 395 // dir2: no child directories. 396 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath( 397 base::FilePath::FromUTF8Unsafe("drive/root/dir2"), &local_id)); 398 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetSubDirectoriesRecursively( 399 local_id, &sub_directories)); 400 EXPECT_TRUE(sub_directories.empty()); 401 const std::string dir2_id = local_id; 402 403 // dir1: dir3 is the only child 404 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath( 405 base::FilePath::FromUTF8Unsafe("drive/root/dir1"), &local_id)); 406 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetSubDirectoriesRecursively( 407 local_id, &sub_directories)); 408 EXPECT_EQ(1u, sub_directories.size()); 409 EXPECT_EQ(1u, sub_directories.count( 410 base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3"))); 411 sub_directories.clear(); 412 413 // Add a few more directories to make sure deeper nesting works. 414 // dir2/dir100 415 // dir2/dir101 416 // dir2/dir101/dir102 417 // dir2/dir101/dir103 418 // dir2/dir101/dir104 419 // dir2/dir101/dir104/dir105 420 // dir2/dir101/dir104/dir105/dir106 421 // dir2/dir101/dir104/dir105/dir106/dir107 422 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( 423 CreateDirectoryEntry("dir100", dir2_id), &local_id)); 424 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( 425 CreateDirectoryEntry("dir101", dir2_id), &local_id)); 426 const std::string dir101_id = local_id; 427 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( 428 CreateDirectoryEntry("dir102", dir101_id), &local_id)); 429 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( 430 CreateDirectoryEntry("dir103", dir101_id), &local_id)); 431 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( 432 CreateDirectoryEntry("dir104", dir101_id), &local_id)); 433 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( 434 CreateDirectoryEntry("dir105", local_id), &local_id)); 435 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( 436 CreateDirectoryEntry("dir106", local_id), &local_id)); 437 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( 438 CreateDirectoryEntry("dir107", local_id), &local_id)); 439 440 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetSubDirectoriesRecursively( 441 dir2_id, &sub_directories)); 442 EXPECT_EQ(8u, sub_directories.size()); 443 EXPECT_EQ(1u, sub_directories.count(base::FilePath::FromUTF8Unsafe( 444 "drive/root/dir2/dir101"))); 445 EXPECT_EQ(1u, sub_directories.count(base::FilePath::FromUTF8Unsafe( 446 "drive/root/dir2/dir101/dir104"))); 447 EXPECT_EQ(1u, sub_directories.count(base::FilePath::FromUTF8Unsafe( 448 "drive/root/dir2/dir101/dir104/dir105/dir106/dir107"))); 449 } 450 451 TEST_F(ResourceMetadataTest, AddEntry) { 452 // Add a file to dir3. 453 std::string local_id; 454 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath( 455 base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3"), &local_id)); 456 ResourceEntry file_entry = CreateFileEntry("file100", local_id); 457 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(file_entry, &local_id)); 458 base::FilePath path; 459 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetFilePath(local_id, &path)); 460 EXPECT_EQ("drive/root/dir1/dir3/file100", path.AsUTF8Unsafe()); 461 462 // Add a directory. 463 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath( 464 base::FilePath::FromUTF8Unsafe("drive/root/dir1"), &local_id)); 465 ResourceEntry dir_entry = CreateDirectoryEntry("dir101", local_id); 466 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(dir_entry, &local_id)); 467 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetFilePath(local_id, &path)); 468 EXPECT_EQ("drive/root/dir1/dir101", path.AsUTF8Unsafe()); 469 470 // Add to an invalid parent. 471 ResourceEntry file_entry3 = CreateFileEntry("file103", "id:invalid"); 472 EXPECT_EQ(FILE_ERROR_NOT_FOUND, 473 resource_metadata_->AddEntry(file_entry3, &local_id)); 474 475 // Add an existing file. 476 EXPECT_EQ(FILE_ERROR_EXISTS, 477 resource_metadata_->AddEntry(file_entry, &local_id)); 478 } 479 480 TEST_F(ResourceMetadataTest, RemoveEntry) { 481 // Make sure file9 is found. 482 std::string file9_local_id; 483 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath( 484 base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3/file9"), 485 &file9_local_id)); 486 ResourceEntry entry; 487 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById( 488 file9_local_id, &entry)); 489 EXPECT_EQ("file9", entry.base_name()); 490 491 // Remove file9. 492 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->RemoveEntry(file9_local_id)); 493 494 // file9 should no longer exist. 495 EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->GetResourceEntryById( 496 file9_local_id, &entry)); 497 498 // Look for dir3. 499 std::string dir3_local_id; 500 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath( 501 base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3"), &dir3_local_id)); 502 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById( 503 dir3_local_id, &entry)); 504 EXPECT_EQ("dir3", entry.base_name()); 505 506 // Remove dir3. 507 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->RemoveEntry(dir3_local_id)); 508 509 // dir3 should no longer exist. 510 EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->GetResourceEntryById( 511 dir3_local_id, &entry)); 512 513 // Remove unknown local_id using RemoveEntry. 514 EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->RemoveEntry("foo")); 515 516 // Try removing root. This should fail. 517 EXPECT_EQ(FILE_ERROR_ACCESS_DENIED, resource_metadata_->RemoveEntry( 518 util::kDriveGrandRootLocalId)); 519 } 520 521 TEST_F(ResourceMetadataTest, GetResourceEntryById_RootDirectory) { 522 // Look up the root directory by its ID. 523 ResourceEntry entry; 524 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById( 525 util::kDriveGrandRootLocalId, &entry)); 526 EXPECT_EQ("drive", entry.base_name()); 527 } 528 529 TEST_F(ResourceMetadataTest, GetResourceEntryById) { 530 // Get file4 by path. 531 std::string local_id; 532 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath( 533 base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"), &local_id)); 534 535 // Confirm that an existing file is found. 536 ResourceEntry entry; 537 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById( 538 local_id, &entry)); 539 EXPECT_EQ("file4", entry.base_name()); 540 541 // Confirm that a non existing file is not found. 542 EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->GetResourceEntryById( 543 "file:non_existing", &entry)); 544 } 545 546 TEST_F(ResourceMetadataTest, Iterate) { 547 scoped_ptr<ResourceMetadata::Iterator> it = resource_metadata_->GetIterator(); 548 ASSERT_TRUE(it); 549 550 int file_count = 0, directory_count = 0; 551 for (; !it->IsAtEnd(); it->Advance()) { 552 if (!it->GetValue().file_info().is_directory()) 553 ++file_count; 554 else 555 ++directory_count; 556 } 557 558 EXPECT_EQ(7, file_count); 559 EXPECT_EQ(7, directory_count); 560 } 561 562 TEST_F(ResourceMetadataTest, DuplicatedNames) { 563 std::string root_local_id; 564 ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath( 565 base::FilePath::FromUTF8Unsafe("drive/root"), &root_local_id)); 566 567 ResourceEntry entry; 568 569 // When multiple entries with the same title are added in a single directory, 570 // their base_names are de-duped. 571 // - drive/root/foo 572 // - drive/root/foo (1) 573 std::string dir_id_0; 574 ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( 575 CreateDirectoryEntryWithResourceId( 576 "foo", "foo0", root_local_id), &dir_id_0)); 577 std::string dir_id_1; 578 ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( 579 CreateDirectoryEntryWithResourceId( 580 "foo", "foo1", root_local_id), &dir_id_1)); 581 582 ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById( 583 dir_id_0, &entry)); 584 EXPECT_EQ("foo", entry.base_name()); 585 ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById( 586 dir_id_1, &entry)); 587 EXPECT_EQ("foo (1)", entry.base_name()); 588 589 // - drive/root/foo/bar.txt 590 // - drive/root/foo/bar (1).txt 591 // - drive/root/foo/bar (2).txt 592 // ... 593 // - drive/root/foo/bar (99).txt 594 std::vector<std::string> file_ids(100); 595 for (size_t i = 0; i < file_ids.size(); ++i) { 596 ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( 597 CreateFileEntryWithResourceId( 598 "bar.txt", base::StringPrintf("bar%d", static_cast<int>(i)), 599 dir_id_0), &file_ids[i])); 600 } 601 602 ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById( 603 file_ids[0], &entry)); 604 EXPECT_EQ("bar.txt", entry.base_name()); 605 for (size_t i = 1; i < file_ids.size(); ++i) { 606 ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById( 607 file_ids[i], &entry)) << i; 608 EXPECT_EQ(base::StringPrintf("bar (%d).txt", static_cast<int>(i)), 609 entry.base_name()); 610 } 611 612 // Same name but different parent. No renaming. 613 // - drive/root/foo (1)/bar.txt 614 std::string file_id_3; 615 ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( 616 CreateFileEntryWithResourceId( 617 "bar.txt", "bar_different_parent", dir_id_1), &file_id_3)); 618 619 ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById( 620 file_id_3, &entry)); 621 EXPECT_EQ("bar.txt", entry.base_name()); 622 623 // Checks that the entries can be looked up by the de-duped paths. 624 ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath( 625 base::FilePath::FromUTF8Unsafe("drive/root/foo/bar (2).txt"), &entry)); 626 EXPECT_EQ("bar2", entry.resource_id()); 627 ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath( 628 base::FilePath::FromUTF8Unsafe("drive/root/foo (1)/bar.txt"), &entry)); 629 EXPECT_EQ("bar_different_parent", entry.resource_id()); 630 } 631 632 TEST_F(ResourceMetadataTest, EncodedNames) { 633 std::string root_local_id; 634 ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath( 635 base::FilePath::FromUTF8Unsafe("drive/root"), &root_local_id)); 636 637 ResourceEntry entry; 638 639 std::string dir_id; 640 ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( 641 CreateDirectoryEntry("\\(^o^)/", root_local_id), &dir_id)); 642 ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById( 643 dir_id, &entry)); 644 EXPECT_EQ("\\(^o^)_", entry.base_name()); 645 646 std::string file_id; 647 ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( 648 CreateFileEntryWithResourceId("Slash /.txt", "myfile", dir_id), 649 &file_id)); 650 ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById( 651 file_id, &entry)); 652 EXPECT_EQ("Slash _.txt", entry.base_name()); 653 654 ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath( 655 base::FilePath::FromUTF8Unsafe( 656 "drive/root/\\(^o^)_/Slash _.txt"), 657 &entry)); 658 EXPECT_EQ("myfile", entry.resource_id()); 659 } 660 661 TEST_F(ResourceMetadataTest, Reset) { 662 // The grand root has "root" which is not empty. 663 std::vector<ResourceEntry> entries; 664 ASSERT_EQ(FILE_ERROR_OK, 665 resource_metadata_->ReadDirectoryByPath( 666 base::FilePath::FromUTF8Unsafe("drive/root"), &entries)); 667 ASSERT_FALSE(entries.empty()); 668 669 // Reset. 670 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->Reset()); 671 672 // change stamp should be reset. 673 int64 changestamp = 0; 674 EXPECT_EQ(FILE_ERROR_OK, 675 resource_metadata_->GetLargestChangestamp(&changestamp)); 676 EXPECT_EQ(0, changestamp); 677 678 // root should continue to exist. 679 ResourceEntry entry; 680 ASSERT_EQ(FILE_ERROR_OK, 681 resource_metadata_->GetResourceEntryByPath( 682 base::FilePath::FromUTF8Unsafe("drive"), &entry)); 683 EXPECT_EQ("drive", entry.base_name()); 684 ASSERT_TRUE(entry.file_info().is_directory()); 685 EXPECT_EQ(util::kDriveGrandRootLocalId, entry.local_id()); 686 687 // There are "other", "trash" and "root" under "drive". 688 ASSERT_EQ(FILE_ERROR_OK, 689 resource_metadata_->ReadDirectoryByPath( 690 base::FilePath::FromUTF8Unsafe("drive"), &entries)); 691 EXPECT_EQ(3U, entries.size()); 692 693 // The "other" directory should be empty. 694 ASSERT_EQ(FILE_ERROR_OK, 695 resource_metadata_->ReadDirectoryByPath( 696 base::FilePath::FromUTF8Unsafe("drive/other"), &entries)); 697 EXPECT_TRUE(entries.empty()); 698 699 // The "trash" directory should be empty. 700 ASSERT_EQ(FILE_ERROR_OK, 701 resource_metadata_->ReadDirectoryByPath( 702 base::FilePath::FromUTF8Unsafe("drive/trash"), &entries)); 703 EXPECT_TRUE(entries.empty()); 704 } 705 706 } // namespace internal 707 } // namespace drive 708