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