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/file_system.h" 6 7#include <string> 8#include <vector> 9 10#include "base/bind.h" 11#include "base/files/file_path.h" 12#include "base/files/file_util.h" 13#include "base/files/scoped_temp_dir.h" 14#include "base/memory/scoped_ptr.h" 15#include "base/message_loop/message_loop_proxy.h" 16#include "base/prefs/testing_pref_service.h" 17#include "base/run_loop.h" 18#include "chrome/browser/chromeos/drive/change_list_loader.h" 19#include "chrome/browser/chromeos/drive/drive.pb.h" 20#include "chrome/browser/chromeos/drive/fake_free_disk_space_getter.h" 21#include "chrome/browser/chromeos/drive/file_change.h" 22#include "chrome/browser/chromeos/drive/file_system_observer.h" 23#include "chrome/browser/chromeos/drive/file_system_util.h" 24#include "chrome/browser/chromeos/drive/job_scheduler.h" 25#include "chrome/browser/chromeos/drive/sync_client.h" 26#include "chrome/browser/chromeos/drive/test_util.h" 27#include "chrome/browser/drive/drive_api_util.h" 28#include "chrome/browser/drive/event_logger.h" 29#include "chrome/browser/drive/fake_drive_service.h" 30#include "chrome/browser/drive/test_util.h" 31#include "content/public/test/test_browser_thread_bundle.h" 32#include "google_apis/drive/drive_api_parser.h" 33#include "google_apis/drive/test_util.h" 34#include "testing/gtest/include/gtest/gtest.h" 35 36namespace drive { 37namespace { 38 39// Counts the number of invocation, and if it increased up to |expected_counter| 40// quits the current message loop by calling |quit|. 41void AsyncInitializationCallback( 42 int* counter, int expected_counter, const base::Closure& quit, 43 FileError error, scoped_ptr<ResourceEntry> entry) { 44 if (error != FILE_ERROR_OK || !entry) { 45 // If we hit an error case, quit the message loop immediately. 46 // Then the expectation in the test case can find it because the actual 47 // value of |counter| is different from the expected one. 48 quit.Run(); 49 return; 50 } 51 52 (*counter)++; 53 if (*counter >= expected_counter) 54 quit.Run(); 55} 56 57// This class is used to record directory changes and examine them later. 58class MockDirectoryChangeObserver : public FileSystemObserver { 59 public: 60 MockDirectoryChangeObserver() {} 61 virtual ~MockDirectoryChangeObserver() {} 62 63 // FileSystemObserver overrides. 64 virtual void OnDirectoryChanged( 65 const base::FilePath& directory_path) OVERRIDE { 66 changed_directories_.push_back(directory_path); 67 } 68 69 virtual void OnFileChanged(const FileChange& new_file_change) OVERRIDE { 70 changed_files_.Apply(new_file_change); 71 } 72 73 const std::vector<base::FilePath>& changed_directories() const { 74 return changed_directories_; 75 } 76 77 const FileChange& changed_files() const { return changed_files_; } 78 79 private: 80 std::vector<base::FilePath> changed_directories_; 81 FileChange changed_files_; 82 DISALLOW_COPY_AND_ASSIGN(MockDirectoryChangeObserver); 83}; 84 85} // namespace 86 87class FileSystemTest : public testing::Test { 88 protected: 89 virtual void SetUp() OVERRIDE { 90 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 91 pref_service_.reset(new TestingPrefServiceSimple); 92 test_util::RegisterDrivePrefs(pref_service_->registry()); 93 94 logger_.reset(new EventLogger); 95 fake_drive_service_.reset(new FakeDriveService); 96 test_util::SetUpTestEntries(fake_drive_service_.get()); 97 98 fake_free_disk_space_getter_.reset(new FakeFreeDiskSpaceGetter); 99 100 scheduler_.reset(new JobScheduler(pref_service_.get(), 101 logger_.get(), 102 fake_drive_service_.get(), 103 base::MessageLoopProxy::current().get())); 104 105 mock_directory_observer_.reset(new MockDirectoryChangeObserver); 106 107 SetUpResourceMetadataAndFileSystem(); 108 } 109 110 void SetUpResourceMetadataAndFileSystem() { 111 const base::FilePath metadata_dir = temp_dir_.path().AppendASCII("meta"); 112 ASSERT_TRUE(base::CreateDirectory(metadata_dir)); 113 metadata_storage_.reset(new internal::ResourceMetadataStorage( 114 metadata_dir, base::MessageLoopProxy::current().get())); 115 ASSERT_TRUE(metadata_storage_->Initialize()); 116 117 const base::FilePath cache_dir = temp_dir_.path().AppendASCII("files"); 118 ASSERT_TRUE(base::CreateDirectory(cache_dir)); 119 cache_.reset(new internal::FileCache( 120 metadata_storage_.get(), 121 cache_dir, 122 base::MessageLoopProxy::current().get(), 123 fake_free_disk_space_getter_.get())); 124 ASSERT_TRUE(cache_->Initialize()); 125 126 resource_metadata_.reset(new internal::ResourceMetadata( 127 metadata_storage_.get(), cache_.get(), 128 base::MessageLoopProxy::current())); 129 ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->Initialize()); 130 131 const base::FilePath temp_file_dir = temp_dir_.path().AppendASCII("tmp"); 132 ASSERT_TRUE(base::CreateDirectory(temp_file_dir)); 133 file_system_.reset(new FileSystem( 134 pref_service_.get(), 135 logger_.get(), 136 cache_.get(), 137 fake_drive_service_.get(), 138 scheduler_.get(), 139 resource_metadata_.get(), 140 base::MessageLoopProxy::current().get(), 141 temp_file_dir)); 142 file_system_->AddObserver(mock_directory_observer_.get()); 143 144 // Disable delaying so that the sync starts immediately. 145 file_system_->sync_client_for_testing()->set_delay_for_testing( 146 base::TimeDelta::FromSeconds(0)); 147 } 148 149 // Loads the full resource list via FakeDriveService. 150 bool LoadFullResourceList() { 151 FileError error = FILE_ERROR_FAILED; 152 file_system_->change_list_loader_for_testing()->LoadIfNeeded( 153 google_apis::test_util::CreateCopyResultCallback(&error)); 154 content::RunAllBlockingPoolTasksUntilIdle(); 155 return error == FILE_ERROR_OK; 156 } 157 158 // Gets resource entry by path synchronously. 159 scoped_ptr<ResourceEntry> GetResourceEntrySync( 160 const base::FilePath& file_path) { 161 FileError error = FILE_ERROR_FAILED; 162 scoped_ptr<ResourceEntry> entry; 163 file_system_->GetResourceEntry( 164 file_path, 165 google_apis::test_util::CreateCopyResultCallback(&error, &entry)); 166 content::RunAllBlockingPoolTasksUntilIdle(); 167 168 return entry.Pass(); 169 } 170 171 // Gets directory info by path synchronously. 172 scoped_ptr<ResourceEntryVector> ReadDirectorySync( 173 const base::FilePath& file_path) { 174 FileError error = FILE_ERROR_FAILED; 175 scoped_ptr<ResourceEntryVector> entries(new ResourceEntryVector); 176 file_system_->ReadDirectory( 177 file_path, 178 base::Bind(&AccumulateReadDirectoryResult, entries.get()), 179 google_apis::test_util::CreateCopyResultCallback(&error)); 180 content::RunAllBlockingPoolTasksUntilIdle(); 181 if (error != FILE_ERROR_OK) 182 entries.reset(); 183 return entries.Pass(); 184 } 185 186 // Used to implement ReadDirectorySync(). 187 static void AccumulateReadDirectoryResult( 188 ResourceEntryVector* out_entries, 189 scoped_ptr<ResourceEntryVector> entries) { 190 ASSERT_TRUE(entries); 191 out_entries->insert(out_entries->end(), entries->begin(), entries->end()); 192 } 193 194 // Returns true if an entry exists at |file_path|. 195 bool EntryExists(const base::FilePath& file_path) { 196 return GetResourceEntrySync(file_path); 197 } 198 199 // Flag for specifying the timestamp of the test filesystem cache. 200 enum SetUpTestFileSystemParam { 201 USE_OLD_TIMESTAMP, 202 USE_SERVER_TIMESTAMP, 203 }; 204 205 // Sets up a filesystem with directories: drive/root, drive/root/Dir1, 206 // drive/root/Dir1/SubDir2 and files drive/root/File1, drive/root/Dir1/File2, 207 // drive/root/Dir1/SubDir2/File3. If |use_up_to_date_timestamp| is true, sets 208 // the changestamp to that of FakeDriveService, indicating the cache is 209 // holding the latest file system info. 210 void SetUpTestFileSystem(SetUpTestFileSystemParam param) { 211 // Destroy the existing resource metadata to close DB. 212 resource_metadata_.reset(); 213 214 const base::FilePath metadata_dir = temp_dir_.path().AppendASCII("meta"); 215 ASSERT_TRUE(base::CreateDirectory(metadata_dir)); 216 scoped_ptr<internal::ResourceMetadataStorage, 217 test_util::DestroyHelperForTests> metadata_storage( 218 new internal::ResourceMetadataStorage( 219 metadata_dir, base::MessageLoopProxy::current().get())); 220 221 const base::FilePath cache_dir = temp_dir_.path().AppendASCII("files"); 222 scoped_ptr<internal::FileCache, test_util::DestroyHelperForTests> cache( 223 new internal::FileCache(metadata_storage.get(), 224 cache_dir, 225 base::MessageLoopProxy::current().get(), 226 fake_free_disk_space_getter_.get())); 227 228 scoped_ptr<internal::ResourceMetadata, test_util::DestroyHelperForTests> 229 resource_metadata(new internal::ResourceMetadata( 230 metadata_storage_.get(), cache.get(), 231 base::MessageLoopProxy::current())); 232 233 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->Initialize()); 234 235 const int64 changestamp = param == USE_SERVER_TIMESTAMP ? 236 fake_drive_service_->about_resource().largest_change_id() : 1; 237 ASSERT_EQ(FILE_ERROR_OK, 238 resource_metadata->SetLargestChangestamp(changestamp)); 239 240 // drive/root 241 ResourceEntry root; 242 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->GetResourceEntryByPath( 243 util::GetDriveMyDriveRootPath(), &root)); 244 root.set_resource_id(fake_drive_service_->GetRootResourceId()); 245 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->RefreshEntry(root)); 246 247 std::string local_id; 248 249 // drive/root/File1 250 ResourceEntry file1; 251 file1.set_title("File1"); 252 file1.set_resource_id("resource_id:File1"); 253 file1.set_parent_local_id(root.local_id()); 254 file1.mutable_file_specific_info()->set_md5("md5"); 255 file1.mutable_file_info()->set_is_directory(false); 256 file1.mutable_file_info()->set_size(1048576); 257 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(file1, &local_id)); 258 259 // drive/root/Dir1 260 ResourceEntry dir1; 261 dir1.set_title("Dir1"); 262 dir1.set_resource_id("resource_id:Dir1"); 263 dir1.set_parent_local_id(root.local_id()); 264 dir1.mutable_file_info()->set_is_directory(true); 265 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(dir1, &local_id)); 266 const std::string dir1_local_id = local_id; 267 268 // drive/root/Dir1/File2 269 ResourceEntry file2; 270 file2.set_title("File2"); 271 file2.set_resource_id("resource_id:File2"); 272 file2.set_parent_local_id(dir1_local_id); 273 file2.mutable_file_specific_info()->set_md5("md5"); 274 file2.mutable_file_info()->set_is_directory(false); 275 file2.mutable_file_info()->set_size(555); 276 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(file2, &local_id)); 277 278 // drive/root/Dir1/SubDir2 279 ResourceEntry dir2; 280 dir2.set_title("SubDir2"); 281 dir2.set_resource_id("resource_id:SubDir2"); 282 dir2.set_parent_local_id(dir1_local_id); 283 dir2.mutable_file_info()->set_is_directory(true); 284 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(dir2, &local_id)); 285 const std::string dir2_local_id = local_id; 286 287 // drive/root/Dir1/SubDir2/File3 288 ResourceEntry file3; 289 file3.set_title("File3"); 290 file3.set_resource_id("resource_id:File3"); 291 file3.set_parent_local_id(dir2_local_id); 292 file3.mutable_file_specific_info()->set_md5("md5"); 293 file3.mutable_file_info()->set_is_directory(false); 294 file3.mutable_file_info()->set_size(12345); 295 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(file3, &local_id)); 296 297 // Recreate resource metadata. 298 SetUpResourceMetadataAndFileSystem(); 299 } 300 301 content::TestBrowserThreadBundle thread_bundle_; 302 base::ScopedTempDir temp_dir_; 303 // We don't use TestingProfile::GetPrefs() in favor of having less 304 // dependencies to Profile in general. 305 scoped_ptr<TestingPrefServiceSimple> pref_service_; 306 307 scoped_ptr<EventLogger> logger_; 308 scoped_ptr<FakeDriveService> fake_drive_service_; 309 scoped_ptr<FakeFreeDiskSpaceGetter> fake_free_disk_space_getter_; 310 scoped_ptr<JobScheduler> scheduler_; 311 scoped_ptr<MockDirectoryChangeObserver> mock_directory_observer_; 312 313 scoped_ptr<internal::ResourceMetadataStorage, 314 test_util::DestroyHelperForTests> metadata_storage_; 315 scoped_ptr<internal::FileCache, test_util::DestroyHelperForTests> cache_; 316 scoped_ptr<internal::ResourceMetadata, test_util::DestroyHelperForTests> 317 resource_metadata_; 318 scoped_ptr<FileSystem> file_system_; 319}; 320 321TEST_F(FileSystemTest, Copy) { 322 base::FilePath src_file_path(FILE_PATH_LITERAL("drive/root/File 1.txt")); 323 base::FilePath dest_file_path(FILE_PATH_LITERAL("drive/root/Copied.txt")); 324 EXPECT_TRUE(GetResourceEntrySync(src_file_path)); 325 EXPECT_FALSE(GetResourceEntrySync(dest_file_path)); 326 327 FileError error = FILE_ERROR_FAILED; 328 file_system_->Copy(src_file_path, 329 dest_file_path, 330 false, // preserve_last_modified, 331 google_apis::test_util::CreateCopyResultCallback(&error)); 332 content::RunAllBlockingPoolTasksUntilIdle(); 333 EXPECT_EQ(FILE_ERROR_OK, error); 334 335 // Entry is added on the server. 336 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(dest_file_path); 337 ASSERT_TRUE(entry); 338 339 google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR; 340 scoped_ptr<google_apis::FileResource> server_entry; 341 fake_drive_service_->GetFileResource( 342 entry->resource_id(), 343 google_apis::test_util::CreateCopyResultCallback(&status, &server_entry)); 344 content::RunAllBlockingPoolTasksUntilIdle(); 345 EXPECT_EQ(google_apis::HTTP_SUCCESS, status); 346 ASSERT_TRUE(server_entry); 347 EXPECT_EQ(entry->title(), server_entry->title()); 348 EXPECT_FALSE(server_entry->IsDirectory()); 349} 350 351TEST_F(FileSystemTest, Move) { 352 base::FilePath src_file_path(FILE_PATH_LITERAL("drive/root/File 1.txt")); 353 base::FilePath dest_file_path( 354 FILE_PATH_LITERAL("drive/root/Directory 1/Moved.txt")); 355 EXPECT_TRUE(GetResourceEntrySync(src_file_path)); 356 EXPECT_FALSE(GetResourceEntrySync(dest_file_path)); 357 scoped_ptr<ResourceEntry> parent = 358 GetResourceEntrySync(dest_file_path.DirName()); 359 ASSERT_TRUE(parent); 360 361 FileError error = FILE_ERROR_FAILED; 362 file_system_->Move(src_file_path, 363 dest_file_path, 364 google_apis::test_util::CreateCopyResultCallback(&error)); 365 content::RunAllBlockingPoolTasksUntilIdle(); 366 EXPECT_EQ(FILE_ERROR_OK, error); 367 368 // Entry is moved on the server. 369 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(dest_file_path); 370 ASSERT_TRUE(entry); 371 372 google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR; 373 scoped_ptr<google_apis::FileResource> server_entry; 374 fake_drive_service_->GetFileResource( 375 entry->resource_id(), 376 google_apis::test_util::CreateCopyResultCallback(&status, &server_entry)); 377 content::RunAllBlockingPoolTasksUntilIdle(); 378 EXPECT_EQ(google_apis::HTTP_SUCCESS, status); 379 ASSERT_TRUE(server_entry); 380 EXPECT_EQ(entry->title(), server_entry->title()); 381 382 ASSERT_FALSE(server_entry->parents().empty()); 383 EXPECT_EQ(parent->resource_id(), server_entry->parents()[0].file_id()); 384} 385 386TEST_F(FileSystemTest, Remove) { 387 base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt")); 388 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(file_path); 389 ASSERT_TRUE(entry); 390 391 FileError error = FILE_ERROR_FAILED; 392 file_system_->Remove( 393 file_path, 394 false, // is_resursive 395 google_apis::test_util::CreateCopyResultCallback(&error)); 396 content::RunAllBlockingPoolTasksUntilIdle(); 397 EXPECT_EQ(FILE_ERROR_OK, error); 398 399 // Entry is removed on the server. 400 google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR; 401 scoped_ptr<google_apis::FileResource> server_entry; 402 fake_drive_service_->GetFileResource( 403 entry->resource_id(), 404 google_apis::test_util::CreateCopyResultCallback(&status, &server_entry)); 405 content::RunAllBlockingPoolTasksUntilIdle(); 406 EXPECT_EQ(google_apis::HTTP_SUCCESS, status); 407 ASSERT_TRUE(server_entry); 408 EXPECT_TRUE(server_entry->labels().is_trashed()); 409} 410 411TEST_F(FileSystemTest, CreateDirectory) { 412 base::FilePath directory_path(FILE_PATH_LITERAL("drive/root/New Directory")); 413 EXPECT_FALSE(GetResourceEntrySync(directory_path)); 414 415 FileError error = FILE_ERROR_FAILED; 416 file_system_->CreateDirectory( 417 directory_path, 418 true, // is_exclusive 419 false, // is_recursive 420 google_apis::test_util::CreateCopyResultCallback(&error)); 421 content::RunAllBlockingPoolTasksUntilIdle(); 422 EXPECT_EQ(FILE_ERROR_OK, error); 423 424 // Directory is created on the server. 425 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(directory_path); 426 ASSERT_TRUE(entry); 427 428 google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR; 429 scoped_ptr<google_apis::FileResource> server_entry; 430 fake_drive_service_->GetFileResource( 431 entry->resource_id(), 432 google_apis::test_util::CreateCopyResultCallback(&status, &server_entry)); 433 content::RunAllBlockingPoolTasksUntilIdle(); 434 EXPECT_EQ(google_apis::HTTP_SUCCESS, status); 435 ASSERT_TRUE(server_entry); 436 EXPECT_EQ(entry->title(), server_entry->title()); 437 EXPECT_TRUE(server_entry->IsDirectory()); 438} 439 440TEST_F(FileSystemTest, CreateFile) { 441 base::FilePath file_path(FILE_PATH_LITERAL("drive/root/New File.txt")); 442 EXPECT_FALSE(GetResourceEntrySync(file_path)); 443 444 FileError error = FILE_ERROR_FAILED; 445 file_system_->CreateFile( 446 file_path, 447 true, // is_exclusive 448 "text/plain", 449 google_apis::test_util::CreateCopyResultCallback(&error)); 450 content::RunAllBlockingPoolTasksUntilIdle(); 451 EXPECT_EQ(FILE_ERROR_OK, error); 452 453 // File is created on the server. 454 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(file_path); 455 ASSERT_TRUE(entry); 456 457 google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR; 458 scoped_ptr<google_apis::FileResource> server_entry; 459 fake_drive_service_->GetFileResource( 460 entry->resource_id(), 461 google_apis::test_util::CreateCopyResultCallback(&status, &server_entry)); 462 content::RunAllBlockingPoolTasksUntilIdle(); 463 EXPECT_EQ(google_apis::HTTP_SUCCESS, status); 464 ASSERT_TRUE(server_entry); 465 EXPECT_EQ(entry->title(), server_entry->title()); 466 EXPECT_FALSE(server_entry->IsDirectory()); 467} 468 469TEST_F(FileSystemTest, TouchFile) { 470 base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt")); 471 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(file_path); 472 ASSERT_TRUE(entry); 473 474 base::Time last_accessed = 475 base::Time::FromInternalValue(entry->file_info().last_accessed()) + 476 base::TimeDelta::FromSeconds(1); 477 base::Time last_modified = 478 base::Time::FromInternalValue(entry->file_info().last_modified()) + 479 base::TimeDelta::FromSeconds(1); 480 481 FileError error = FILE_ERROR_FAILED; 482 file_system_->TouchFile( 483 file_path, 484 last_accessed, 485 last_modified, 486 google_apis::test_util::CreateCopyResultCallback(&error)); 487 content::RunAllBlockingPoolTasksUntilIdle(); 488 EXPECT_EQ(FILE_ERROR_OK, error); 489 490 // File is touched on the server. 491 google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR; 492 scoped_ptr<google_apis::FileResource> server_entry; 493 fake_drive_service_->GetFileResource( 494 entry->resource_id(), 495 google_apis::test_util::CreateCopyResultCallback(&status, &server_entry)); 496 content::RunAllBlockingPoolTasksUntilIdle(); 497 EXPECT_EQ(google_apis::HTTP_SUCCESS, status); 498 ASSERT_TRUE(server_entry); 499 EXPECT_EQ(last_accessed, server_entry->last_viewed_by_me_date()); 500 EXPECT_EQ(last_modified, server_entry->modified_date()); 501} 502 503TEST_F(FileSystemTest, TruncateFile) { 504 base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt")); 505 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(file_path); 506 ASSERT_TRUE(entry); 507 508 const int64 kLength = entry->file_info().size() + 100; 509 510 FileError error = FILE_ERROR_FAILED; 511 file_system_->TruncateFile( 512 file_path, 513 kLength, 514 google_apis::test_util::CreateCopyResultCallback(&error)); 515 content::RunAllBlockingPoolTasksUntilIdle(); 516 EXPECT_EQ(FILE_ERROR_OK, error); 517 518 // File is touched on the server. 519 google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR; 520 scoped_ptr<google_apis::FileResource> server_entry; 521 fake_drive_service_->GetFileResource( 522 entry->resource_id(), 523 google_apis::test_util::CreateCopyResultCallback(&status, &server_entry)); 524 content::RunAllBlockingPoolTasksUntilIdle(); 525 EXPECT_EQ(google_apis::HTTP_SUCCESS, status); 526 ASSERT_TRUE(server_entry); 527 EXPECT_EQ(kLength, server_entry->file_size()); 528} 529 530TEST_F(FileSystemTest, DuplicatedAsyncInitialization) { 531 base::RunLoop loop; 532 533 int counter = 0; 534 const GetResourceEntryCallback& callback = base::Bind( 535 &AsyncInitializationCallback, &counter, 2, loop.QuitClosure()); 536 537 file_system_->GetResourceEntry( 538 base::FilePath(FILE_PATH_LITERAL("drive/root")), callback); 539 file_system_->GetResourceEntry( 540 base::FilePath(FILE_PATH_LITERAL("drive/root")), callback); 541 loop.Run(); // Wait to get our result 542 EXPECT_EQ(2, counter); 543 544 EXPECT_EQ(1, fake_drive_service_->file_list_load_count()); 545} 546 547TEST_F(FileSystemTest, GetGrandRootEntry) { 548 const base::FilePath kFilePath(FILE_PATH_LITERAL("drive")); 549 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath); 550 ASSERT_TRUE(entry); 551 EXPECT_EQ(util::kDriveGrandRootLocalId, entry->local_id()); 552} 553 554TEST_F(FileSystemTest, GetOtherDirEntry) { 555 const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/other")); 556 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath); 557 ASSERT_TRUE(entry); 558 EXPECT_EQ(util::kDriveOtherDirLocalId, entry->local_id()); 559} 560 561TEST_F(FileSystemTest, GetMyDriveRoot) { 562 const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root")); 563 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath); 564 ASSERT_TRUE(entry); 565 EXPECT_EQ(fake_drive_service_->GetRootResourceId(), entry->resource_id()); 566 567 // After "fast fetch" is done, full resource list is fetched. 568 EXPECT_EQ(1, fake_drive_service_->file_list_load_count()); 569} 570 571TEST_F(FileSystemTest, GetExistingFile) { 572 // Simulate the situation that full feed fetching takes very long time, 573 // to test the recursive "fast fetch" feature is properly working. 574 fake_drive_service_->set_never_return_all_file_list(true); 575 576 const base::FilePath kFilePath( 577 FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt")); 578 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath); 579 ASSERT_TRUE(entry); 580 EXPECT_EQ("subdirectory_file_1_id", entry->resource_id()); 581 582 EXPECT_EQ(1, fake_drive_service_->about_resource_load_count()); 583 EXPECT_EQ(2, fake_drive_service_->directory_load_count()); 584 EXPECT_EQ(1, fake_drive_service_->blocked_file_list_load_count()); 585} 586 587TEST_F(FileSystemTest, GetExistingDocument) { 588 const base::FilePath kFilePath( 589 FILE_PATH_LITERAL("drive/root/Document 1 excludeDir-test.gdoc")); 590 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath); 591 ASSERT_TRUE(entry); 592 EXPECT_EQ("5_document_resource_id", entry->resource_id()); 593} 594 595TEST_F(FileSystemTest, GetNonExistingFile) { 596 const base::FilePath kFilePath( 597 FILE_PATH_LITERAL("drive/root/nonexisting.file")); 598 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath); 599 EXPECT_FALSE(entry); 600} 601 602TEST_F(FileSystemTest, GetInSubSubdir) { 603 const base::FilePath kFilePath( 604 FILE_PATH_LITERAL("drive/root/Directory 1/Sub Directory Folder/" 605 "Sub Sub Directory Folder")); 606 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath); 607 ASSERT_TRUE(entry); 608 ASSERT_EQ("sub_sub_directory_folder_id", entry->resource_id()); 609} 610 611TEST_F(FileSystemTest, GetOrphanFile) { 612 ASSERT_TRUE(LoadFullResourceList()); 613 614 // Entry without parents are placed under "drive/other". 615 const base::FilePath kFilePath( 616 FILE_PATH_LITERAL("drive/other/Orphan File 1.txt")); 617 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath); 618 ASSERT_TRUE(entry); 619 EXPECT_EQ("1_orphanfile_resource_id", entry->resource_id()); 620} 621 622TEST_F(FileSystemTest, ReadDirectory_Root) { 623 // ReadDirectory() should kick off the resource list loading. 624 scoped_ptr<ResourceEntryVector> entries( 625 ReadDirectorySync(base::FilePath::FromUTF8Unsafe("drive"))); 626 // The root directory should be read correctly. 627 ASSERT_TRUE(entries); 628 ASSERT_EQ(3U, entries->size()); 629 630 // The found three directories should be /drive/root, /drive/other and 631 // /drive/trash. 632 std::set<base::FilePath> found; 633 for (size_t i = 0; i < entries->size(); ++i) 634 found.insert(base::FilePath::FromUTF8Unsafe((*entries)[i].title())); 635 EXPECT_EQ(3U, found.size()); 636 EXPECT_EQ(1U, found.count(base::FilePath(util::kDriveMyDriveRootDirName))); 637 EXPECT_EQ(1U, found.count(base::FilePath(util::kDriveOtherDirName))); 638 EXPECT_EQ(1U, found.count(base::FilePath(util::kDriveTrashDirName))); 639} 640 641TEST_F(FileSystemTest, ReadDirectory_NonRootDirectory) { 642 // ReadDirectory() should kick off the resource list loading. 643 scoped_ptr<ResourceEntryVector> entries( 644 ReadDirectorySync( 645 base::FilePath::FromUTF8Unsafe("drive/root/Directory 1"))); 646 // The non root directory should also be read correctly. 647 // There was a bug (crbug.com/181487), which broke this behavior. 648 // Make sure this is fixed. 649 ASSERT_TRUE(entries); 650 EXPECT_EQ(3U, entries->size()); 651} 652 653TEST_F(FileSystemTest, LoadFileSystemFromUpToDateCache) { 654 ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_SERVER_TIMESTAMP)); 655 656 // Kicks loading of cached file system and query for server update. 657 EXPECT_TRUE(ReadDirectorySync(util::GetDriveMyDriveRootPath())); 658 659 // SetUpTestFileSystem and FakeDriveService have the same 660 // changestamp (i.e. the local metadata is up-to-date), so no request for 661 // new resource list (i.e., call to GetResourceList) should happen. 662 EXPECT_EQ(0, fake_drive_service_->file_list_load_count()); 663 664 // Since the file system has verified that it holds the latest snapshot, 665 // it should change its state to "loaded", which admits periodic refresh. 666 // To test it, call CheckForUpdates and verify it does try to check updates. 667 const int about_resource_load_count_before = 668 fake_drive_service_->about_resource_load_count(); 669 file_system_->CheckForUpdates(); 670 content::RunAllBlockingPoolTasksUntilIdle(); 671 EXPECT_LT(about_resource_load_count_before, 672 fake_drive_service_->about_resource_load_count()); 673} 674 675TEST_F(FileSystemTest, LoadFileSystemFromCacheWhileOffline) { 676 ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_OLD_TIMESTAMP)); 677 678 // Make GetResourceList fail for simulating offline situation. This will 679 // leave the file system "loaded from cache, but not synced with server" 680 // state. 681 fake_drive_service_->set_offline(true); 682 683 // Load the root. 684 EXPECT_TRUE(ReadDirectorySync(util::GetDriveGrandRootPath())); 685 // Loading of about resource should not happen as it's offline. 686 EXPECT_EQ(0, fake_drive_service_->about_resource_load_count()); 687 688 // Load "My Drive". 689 EXPECT_TRUE(ReadDirectorySync(util::GetDriveMyDriveRootPath())); 690 EXPECT_EQ(0, fake_drive_service_->about_resource_load_count()); 691 692 // Tests that cached data can be loaded even if the server is not reachable. 693 EXPECT_TRUE(EntryExists(base::FilePath( 694 FILE_PATH_LITERAL("drive/root/File1")))); 695 EXPECT_TRUE(EntryExists(base::FilePath( 696 FILE_PATH_LITERAL("drive/root/Dir1")))); 697 EXPECT_TRUE(EntryExists(base::FilePath( 698 FILE_PATH_LITERAL("drive/root/Dir1/File2")))); 699 EXPECT_TRUE(EntryExists(base::FilePath( 700 FILE_PATH_LITERAL("drive/root/Dir1/SubDir2")))); 701 EXPECT_TRUE(EntryExists(base::FilePath( 702 FILE_PATH_LITERAL("drive/root/Dir1/SubDir2/File3")))); 703 704 // Since the file system has at least succeeded to load cached snapshot, 705 // the file system should be able to start periodic refresh. 706 // To test it, call CheckForUpdates and verify it does try to check 707 // updates, which will cause directory changes. 708 fake_drive_service_->set_offline(false); 709 710 file_system_->CheckForUpdates(); 711 712 content::RunAllBlockingPoolTasksUntilIdle(); 713 EXPECT_EQ(1, fake_drive_service_->about_resource_load_count()); 714 EXPECT_EQ(1, fake_drive_service_->change_list_load_count()); 715 716 ASSERT_LE(0u, mock_directory_observer_->changed_directories().size()); 717 ASSERT_LE(1u, mock_directory_observer_->changed_files().size()); 718} 719 720TEST_F(FileSystemTest, ReadDirectoryWhileRefreshing) { 721 // Use old timestamp so the fast fetch will be performed. 722 ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_OLD_TIMESTAMP)); 723 724 // The list of resources in "drive/root/Dir1" should be fetched. 725 EXPECT_TRUE(ReadDirectorySync(base::FilePath( 726 FILE_PATH_LITERAL("drive/root/Dir1")))); 727 EXPECT_EQ(1, fake_drive_service_->directory_load_count()); 728 729 ASSERT_LE(1u, mock_directory_observer_->changed_directories().size()); 730} 731 732TEST_F(FileSystemTest, GetResourceEntryNonExistentWhileRefreshing) { 733 // Use old timestamp so the fast fetch will be performed. 734 ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_OLD_TIMESTAMP)); 735 736 // If an entry is not found, parent directory's resource list is fetched. 737 EXPECT_FALSE(GetResourceEntrySync(base::FilePath( 738 FILE_PATH_LITERAL("drive/root/Dir1/NonExistentFile")))); 739 EXPECT_EQ(1, fake_drive_service_->directory_load_count()); 740 741 ASSERT_LE(1u, mock_directory_observer_->changed_directories().size()); 742} 743 744TEST_F(FileSystemTest, CreateDirectoryByImplicitLoad) { 745 // Intentionally *not* calling LoadFullResourceList(), for testing that 746 // CreateDirectory ensures the resource list is loaded before it runs. 747 748 base::FilePath existing_directory( 749 FILE_PATH_LITERAL("drive/root/Directory 1")); 750 FileError error = FILE_ERROR_FAILED; 751 file_system_->CreateDirectory( 752 existing_directory, 753 true, // is_exclusive 754 false, // is_recursive 755 google_apis::test_util::CreateCopyResultCallback(&error)); 756 content::RunAllBlockingPoolTasksUntilIdle(); 757 758 // It should fail because is_exclusive is set to true. 759 EXPECT_EQ(FILE_ERROR_EXISTS, error); 760} 761 762TEST_F(FileSystemTest, CreateDirectoryRecursively) { 763 // Intentionally *not* calling LoadFullResourceList(), for testing that 764 // CreateDirectory ensures the resource list is loaded before it runs. 765 766 base::FilePath new_directory( 767 FILE_PATH_LITERAL("drive/root/Directory 1/a/b/c/d")); 768 FileError error = FILE_ERROR_FAILED; 769 file_system_->CreateDirectory( 770 new_directory, 771 true, // is_exclusive 772 true, // is_recursive 773 google_apis::test_util::CreateCopyResultCallback(&error)); 774 content::RunAllBlockingPoolTasksUntilIdle(); 775 776 EXPECT_EQ(FILE_ERROR_OK, error); 777 778 scoped_ptr<ResourceEntry> entry(GetResourceEntrySync(new_directory)); 779 ASSERT_TRUE(entry); 780 EXPECT_TRUE(entry->file_info().is_directory()); 781} 782 783TEST_F(FileSystemTest, ReadDirectoryAfterUpdateWhileLoading) { 784 // Simulate the situation that full feed fetching takes very long time, 785 // to test the recursive "fast fetch" feature is properly working. 786 fake_drive_service_->set_never_return_all_file_list(true); 787 788 // On the fake server, create the test directory. 789 scoped_ptr<google_apis::FileResource> parent; 790 { 791 google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR; 792 fake_drive_service_->AddNewDirectory( 793 fake_drive_service_->GetRootResourceId(), 794 "UpdateWhileLoadingTestDir", 795 DriveServiceInterface::AddNewDirectoryOptions(), 796 google_apis::test_util::CreateCopyResultCallback(&error, &parent)); 797 base::RunLoop().RunUntilIdle(); 798 ASSERT_EQ(google_apis::HTTP_CREATED, error); 799 } 800 801 // Fetch the directory. Currently it is empty. 802 scoped_ptr<ResourceEntryVector> before = ReadDirectorySync(base::FilePath( 803 FILE_PATH_LITERAL("drive/root/UpdateWhileLoadingTestDir"))); 804 ASSERT_TRUE(before); 805 EXPECT_EQ(0u, before->size()); 806 807 // Create a file in the test directory. 808 scoped_ptr<google_apis::FileResource> entry; 809 { 810 google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR; 811 fake_drive_service_->AddNewFile( 812 "text/plain", 813 "(dummy data)", 814 parent->file_id(), 815 "TestFile", 816 false, // shared_with_me 817 google_apis::test_util::CreateCopyResultCallback(&error, &entry)); 818 base::RunLoop().RunUntilIdle(); 819 ASSERT_EQ(google_apis::HTTP_CREATED, error); 820 } 821 822 // Notify the update to the file system. 823 file_system_->CheckForUpdates(); 824 825 // Read the directory once again. Although the full feed fetching is not yet 826 // finished, the "fast fetch" of the directory works and the refreshed content 827 // is returned. 828 scoped_ptr<ResourceEntryVector> after = ReadDirectorySync(base::FilePath( 829 FILE_PATH_LITERAL("drive/root/UpdateWhileLoadingTestDir"))); 830 ASSERT_TRUE(after); 831 EXPECT_EQ(1u, after->size()); 832} 833 834TEST_F(FileSystemTest, PinAndUnpin) { 835 ASSERT_TRUE(LoadFullResourceList()); 836 837 base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt")); 838 839 // Get the file info. 840 scoped_ptr<ResourceEntry> entry(GetResourceEntrySync(file_path)); 841 ASSERT_TRUE(entry); 842 843 // Pin the file. 844 FileError error = FILE_ERROR_FAILED; 845 file_system_->Pin(file_path, 846 google_apis::test_util::CreateCopyResultCallback(&error)); 847 content::RunAllBlockingPoolTasksUntilIdle(); 848 EXPECT_EQ(FILE_ERROR_OK, error); 849 850 entry = GetResourceEntrySync(file_path); 851 ASSERT_TRUE(entry); 852 EXPECT_TRUE(entry->file_specific_info().cache_state().is_pinned()); 853 EXPECT_TRUE(entry->file_specific_info().cache_state().is_present()); 854 855 // Unpin the file. 856 error = FILE_ERROR_FAILED; 857 file_system_->Unpin(file_path, 858 google_apis::test_util::CreateCopyResultCallback(&error)); 859 content::RunAllBlockingPoolTasksUntilIdle(); 860 EXPECT_EQ(FILE_ERROR_OK, error); 861 862 entry = GetResourceEntrySync(file_path); 863 ASSERT_TRUE(entry); 864 EXPECT_FALSE(entry->file_specific_info().cache_state().is_pinned()); 865 866 // Pinned file gets synced and it results in entry state changes. 867 ASSERT_EQ(0u, mock_directory_observer_->changed_directories().size()); 868 ASSERT_EQ(1u, mock_directory_observer_->changed_files().size()); 869 EXPECT_EQ(1u, 870 mock_directory_observer_->changed_files().CountDirectory( 871 base::FilePath(FILE_PATH_LITERAL("drive/root")))); 872} 873 874TEST_F(FileSystemTest, PinAndUnpin_NotSynced) { 875 ASSERT_TRUE(LoadFullResourceList()); 876 877 base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt")); 878 879 // Get the file info. 880 scoped_ptr<ResourceEntry> entry(GetResourceEntrySync(file_path)); 881 ASSERT_TRUE(entry); 882 883 // Unpin the file just after pinning. File fetch should be cancelled. 884 FileError error_pin = FILE_ERROR_FAILED; 885 file_system_->Pin( 886 file_path, 887 google_apis::test_util::CreateCopyResultCallback(&error_pin)); 888 889 FileError error_unpin = FILE_ERROR_FAILED; 890 file_system_->Unpin( 891 file_path, 892 google_apis::test_util::CreateCopyResultCallback(&error_unpin)); 893 894 content::RunAllBlockingPoolTasksUntilIdle(); 895 EXPECT_EQ(FILE_ERROR_OK, error_pin); 896 EXPECT_EQ(FILE_ERROR_OK, error_unpin); 897 898 // No cache file available because the sync was cancelled by Unpin(). 899 entry = GetResourceEntrySync(file_path); 900 ASSERT_TRUE(entry); 901 EXPECT_FALSE(entry->file_specific_info().cache_state().is_present()); 902} 903 904TEST_F(FileSystemTest, GetAvailableSpace) { 905 FileError error = FILE_ERROR_OK; 906 int64 bytes_total; 907 int64 bytes_used; 908 file_system_->GetAvailableSpace( 909 google_apis::test_util::CreateCopyResultCallback( 910 &error, &bytes_total, &bytes_used)); 911 content::RunAllBlockingPoolTasksUntilIdle(); 912 EXPECT_EQ(6789012345LL, bytes_used); 913 EXPECT_EQ(9876543210LL, bytes_total); 914} 915 916TEST_F(FileSystemTest, MarkCacheFileAsMountedAndUnmounted) { 917 ASSERT_TRUE(LoadFullResourceList()); 918 919 base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt")); 920 921 // Make the file cached. 922 FileError error = FILE_ERROR_FAILED; 923 base::FilePath file_path; 924 scoped_ptr<ResourceEntry> entry; 925 file_system_->GetFile( 926 file_in_root, 927 google_apis::test_util::CreateCopyResultCallback( 928 &error, &file_path, &entry)); 929 content::RunAllBlockingPoolTasksUntilIdle(); 930 EXPECT_EQ(FILE_ERROR_OK, error); 931 932 // Test for mounting. 933 error = FILE_ERROR_FAILED; 934 file_path.clear(); 935 file_system_->MarkCacheFileAsMounted( 936 file_in_root, 937 google_apis::test_util::CreateCopyResultCallback(&error, &file_path)); 938 content::RunAllBlockingPoolTasksUntilIdle(); 939 EXPECT_EQ(FILE_ERROR_OK, error); 940 941 // Cannot remove a cache entry while it's being mounted. 942 EXPECT_EQ(FILE_ERROR_IN_USE, cache_->Remove(entry->local_id())); 943 944 // Test for unmounting. 945 error = FILE_ERROR_FAILED; 946 file_system_->MarkCacheFileAsUnmounted( 947 file_path, 948 google_apis::test_util::CreateCopyResultCallback(&error)); 949 content::RunAllBlockingPoolTasksUntilIdle(); 950 EXPECT_EQ(FILE_ERROR_OK, error); 951 952 // Now able to remove the cache entry. 953 EXPECT_EQ(FILE_ERROR_OK, cache_->Remove(entry->local_id())); 954} 955 956TEST_F(FileSystemTest, GetShareUrl) { 957 ASSERT_TRUE(LoadFullResourceList()); 958 959 const base::FilePath kFileInRoot(FILE_PATH_LITERAL("drive/root/File 1.txt")); 960 const GURL kEmbedOrigin("chrome-extension://test-id"); 961 962 // Try to fetch the URL for the sharing dialog. 963 FileError error = FILE_ERROR_FAILED; 964 GURL share_url; 965 file_system_->GetShareUrl( 966 kFileInRoot, 967 kEmbedOrigin, 968 google_apis::test_util::CreateCopyResultCallback(&error, &share_url)); 969 content::RunAllBlockingPoolTasksUntilIdle(); 970 971 // Verify the share url to the sharing dialog. 972 EXPECT_EQ(FILE_ERROR_OK, error); 973 EXPECT_TRUE(share_url.is_valid()); 974} 975 976} // namespace drive 977