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