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.
5 #include "chrome/browser/chromeos/drive/file_system.h"
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/change_list_processor.h"
20 #include "chrome/browser/chromeos/drive/drive.pb.h"
21 #include "chrome/browser/chromeos/drive/fake_free_disk_space_getter.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/fake_drive_service.h"
28 #include "chrome/browser/google_apis/drive_api_parser.h"
29 #include "chrome/browser/google_apis/test_util.h"
30 #include "content/public/test/test_browser_thread_bundle.h"
31 #include "testing/gtest/include/gtest/gtest.h"
36 // Counts the number of invocation, and if it increased up to |expected_counter|
37 // quits the current message loop by calling |quit|.
38 void AsyncInitializationCallback(
39 int* counter, int expected_counter, const base::Closure& quit,
40 FileError error, scoped_ptr<ResourceEntry> entry) {
41 if (error != FILE_ERROR_OK || !entry) {
42 // If we hit an error case, quit the message loop immediately.
43 // Then the expectation in the test case can find it because the actual
44 // value of |counter| is different from the expected one.
50 if (*counter >= expected_counter)
54 // This class is used to record directory changes and examine them later.
55 class MockDirectoryChangeObserver : public FileSystemObserver {
57 MockDirectoryChangeObserver() {}
58 virtual ~MockDirectoryChangeObserver() {}
60 // FileSystemObserver overrides.
61 virtual void OnDirectoryChanged(
62 const base::FilePath& directory_path) OVERRIDE {
63 changed_directories_.push_back(directory_path);
66 const std::vector<base::FilePath>& changed_directories() const {
67 return changed_directories_;
71 std::vector<base::FilePath> changed_directories_;
72 DISALLOW_COPY_AND_ASSIGN(MockDirectoryChangeObserver);
77 class FileSystemTest : public testing::Test {
79 virtual void SetUp() OVERRIDE {
80 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
81 pref_service_.reset(new TestingPrefServiceSimple);
82 test_util::RegisterDrivePrefs(pref_service_->registry());
84 fake_drive_service_.reset(new FakeDriveService);
85 fake_drive_service_->LoadResourceListForWapi(
86 "gdata/root_feed.json");
87 fake_drive_service_->LoadAccountMetadataForWapi(
88 "gdata/account_metadata.json");
90 fake_free_disk_space_getter_.reset(new FakeFreeDiskSpaceGetter);
92 scheduler_.reset(new JobScheduler(pref_service_.get(),
93 fake_drive_service_.get(),
94 base::MessageLoopProxy::current().get()));
96 mock_directory_observer_.reset(new MockDirectoryChangeObserver);
98 SetUpResourceMetadataAndFileSystem();
101 void SetUpResourceMetadataAndFileSystem() {
102 const base::FilePath metadata_dir = temp_dir_.path().AppendASCII("meta");
103 ASSERT_TRUE(file_util::CreateDirectory(metadata_dir));
104 metadata_storage_.reset(new internal::ResourceMetadataStorage(
105 metadata_dir, base::MessageLoopProxy::current().get()));
106 ASSERT_TRUE(metadata_storage_->Initialize());
108 const base::FilePath cache_dir = temp_dir_.path().AppendASCII("files");
109 ASSERT_TRUE(file_util::CreateDirectory(cache_dir));
110 cache_.reset(new internal::FileCache(
111 metadata_storage_.get(),
113 base::MessageLoopProxy::current().get(),
114 fake_free_disk_space_getter_.get()));
115 ASSERT_TRUE(cache_->Initialize());
117 resource_metadata_.reset(new internal::ResourceMetadata(
118 metadata_storage_.get(), base::MessageLoopProxy::current()));
119 ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->Initialize());
121 const base::FilePath temp_file_dir = temp_dir_.path().AppendASCII("tmp");
122 ASSERT_TRUE(file_util::CreateDirectory(temp_file_dir));
123 file_system_.reset(new FileSystem(
126 fake_drive_service_.get(),
128 resource_metadata_.get(),
129 base::MessageLoopProxy::current().get(),
131 file_system_->AddObserver(mock_directory_observer_.get());
133 // Disable delaying so that the sync starts immediately.
134 file_system_->sync_client_for_testing()->set_delay_for_testing(
135 base::TimeDelta::FromSeconds(0));
138 // Loads the full resource list via FakeDriveService.
139 bool LoadFullResourceList() {
140 FileError error = FILE_ERROR_FAILED;
141 file_system_->change_list_loader_for_testing()->LoadIfNeeded(
142 internal::DirectoryFetchInfo(),
143 google_apis::test_util::CreateCopyResultCallback(&error));
144 test_util::RunBlockingPoolTask();
145 return error == FILE_ERROR_OK;
148 // Gets resource entry by path synchronously.
149 scoped_ptr<ResourceEntry> GetResourceEntryByPathSync(
150 const base::FilePath& file_path) {
151 FileError error = FILE_ERROR_FAILED;
152 scoped_ptr<ResourceEntry> entry;
153 file_system_->GetResourceEntryByPath(
155 google_apis::test_util::CreateCopyResultCallback(&error, &entry));
156 test_util::RunBlockingPoolTask();
161 // Gets directory info by path synchronously.
162 scoped_ptr<ResourceEntryVector> ReadDirectoryByPathSync(
163 const base::FilePath& file_path) {
164 FileError error = FILE_ERROR_FAILED;
165 scoped_ptr<ResourceEntryVector> entries;
166 file_system_->ReadDirectoryByPath(
168 google_apis::test_util::CreateCopyResultCallback(&error, &entries));
169 test_util::RunBlockingPoolTask();
171 return entries.Pass();
174 // Returns true if an entry exists at |file_path|.
175 bool EntryExists(const base::FilePath& file_path) {
176 return GetResourceEntryByPathSync(file_path);
179 // Flag for specifying the timestamp of the test filesystem cache.
180 enum SetUpTestFileSystemParam {
182 USE_SERVER_TIMESTAMP,
185 // Sets up a filesystem with directories: drive/root, drive/root/Dir1,
186 // drive/root/Dir1/SubDir2 and files drive/root/File1, drive/root/Dir1/File2,
187 // drive/root/Dir1/SubDir2/File3. If |use_up_to_date_timestamp| is true, sets
188 // the changestamp to 654321, equal to that of "account_metadata.json" test
189 // data, indicating the cache is holding the latest file system info.
190 void SetUpTestFileSystem(SetUpTestFileSystemParam param) {
191 // Destroy the existing resource metadata to close DB.
192 resource_metadata_.reset();
194 const base::FilePath metadata_dir = temp_dir_.path().AppendASCII("meta");
195 ASSERT_TRUE(file_util::CreateDirectory(metadata_dir));
196 scoped_ptr<internal::ResourceMetadataStorage,
197 test_util::DestroyHelperForTests> metadata_storage(
198 new internal::ResourceMetadataStorage(
199 metadata_dir, base::MessageLoopProxy::current().get()));
201 scoped_ptr<internal::ResourceMetadata, test_util::DestroyHelperForTests>
202 resource_metadata(new internal::ResourceMetadata(
203 metadata_storage_.get(), base::MessageLoopProxy::current()));
205 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->Initialize());
207 const int64 changestamp = param == USE_SERVER_TIMESTAMP ? 654321 : 1;
208 ASSERT_EQ(FILE_ERROR_OK,
209 resource_metadata->SetLargestChangestamp(changestamp));
212 const std::string root_resource_id =
213 fake_drive_service_->GetRootResourceId();
214 std::string local_id;
215 ASSERT_EQ(FILE_ERROR_OK,
216 resource_metadata->AddEntry(util::CreateMyDriveRootEntry(
217 root_resource_id), &local_id));
218 const std::string root_local_id = local_id;
222 file1.set_title("File1");
223 file1.set_resource_id("resource_id:File1");
224 file1.set_parent_local_id(root_local_id);
225 file1.mutable_file_specific_info()->set_md5("md5");
226 file1.mutable_file_info()->set_is_directory(false);
227 file1.mutable_file_info()->set_size(1048576);
228 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(file1, &local_id));
232 dir1.set_title("Dir1");
233 dir1.set_resource_id("resource_id:Dir1");
234 dir1.set_parent_local_id(root_local_id);
235 dir1.mutable_file_info()->set_is_directory(true);
236 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(dir1, &local_id));
237 const std::string dir1_local_id = local_id;
239 // drive/root/Dir1/File2
241 file2.set_title("File2");
242 file2.set_resource_id("resource_id:File2");
243 file2.set_parent_local_id(dir1_local_id);
244 file2.mutable_file_specific_info()->set_md5("md5");
245 file2.mutable_file_info()->set_is_directory(false);
246 file2.mutable_file_info()->set_size(555);
247 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(file2, &local_id));
249 // drive/root/Dir1/SubDir2
251 dir2.set_title("SubDir2");
252 dir2.set_resource_id("resource_id:SubDir2");
253 dir2.set_parent_local_id(dir1_local_id);
254 dir2.mutable_file_info()->set_is_directory(true);
255 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(dir2, &local_id));
256 const std::string dir2_local_id = local_id;
258 // drive/root/Dir1/SubDir2/File3
260 file3.set_title("File3");
261 file3.set_resource_id("resource_id:File3");
262 file3.set_parent_local_id(dir2_local_id);
263 file3.mutable_file_specific_info()->set_md5("md5");
264 file3.mutable_file_info()->set_is_directory(false);
265 file3.mutable_file_info()->set_size(12345);
266 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(file3, &local_id));
268 // Recreate resource metadata.
269 SetUpResourceMetadataAndFileSystem();
272 content::TestBrowserThreadBundle thread_bundle_;
273 base::ScopedTempDir temp_dir_;
274 // We don't use TestingProfile::GetPrefs() in favor of having less
275 // dependencies to Profile in general.
276 scoped_ptr<TestingPrefServiceSimple> pref_service_;
278 scoped_ptr<FakeDriveService> fake_drive_service_;
279 scoped_ptr<FakeFreeDiskSpaceGetter> fake_free_disk_space_getter_;
280 scoped_ptr<JobScheduler> scheduler_;
281 scoped_ptr<MockDirectoryChangeObserver> mock_directory_observer_;
283 scoped_ptr<internal::ResourceMetadataStorage,
284 test_util::DestroyHelperForTests> metadata_storage_;
285 scoped_ptr<internal::FileCache, test_util::DestroyHelperForTests> cache_;
286 scoped_ptr<internal::ResourceMetadata, test_util::DestroyHelperForTests>
288 scoped_ptr<FileSystem> file_system_;
291 TEST_F(FileSystemTest, DuplicatedAsyncInitialization) {
295 const GetResourceEntryCallback& callback = base::Bind(
296 &AsyncInitializationCallback, &counter, 2, loop.QuitClosure());
298 file_system_->GetResourceEntryByPath(
299 base::FilePath(FILE_PATH_LITERAL("drive/root")), callback);
300 file_system_->GetResourceEntryByPath(
301 base::FilePath(FILE_PATH_LITERAL("drive/root")), callback);
302 loop.Run(); // Wait to get our result
303 EXPECT_EQ(2, counter);
305 // Although GetResourceEntryByPath() was called twice, the resource list
306 // should only be loaded once. In the past, there was a bug that caused
307 // it to be loaded twice.
308 EXPECT_EQ(1, fake_drive_service_->resource_list_load_count());
309 // See the comment in GetMyDriveRoot test case why this is 2.
310 EXPECT_EQ(2, fake_drive_service_->about_resource_load_count());
312 // "Fast fetch" will fire an OnirectoryChanged event.
313 ASSERT_EQ(1u, mock_directory_observer_->changed_directories().size());
314 EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("drive")),
315 mock_directory_observer_->changed_directories()[0]);
318 TEST_F(FileSystemTest, GetGrandRootEntry) {
319 const base::FilePath kFilePath(FILE_PATH_LITERAL("drive"));
320 scoped_ptr<ResourceEntry> entry = GetResourceEntryByPathSync(kFilePath);
322 EXPECT_EQ(util::kDriveGrandRootSpecialResourceId, entry->resource_id());
324 // Getting the grand root entry should not cause the resource load to happen.
325 EXPECT_EQ(0, fake_drive_service_->about_resource_load_count());
326 EXPECT_EQ(0, fake_drive_service_->resource_list_load_count());
329 TEST_F(FileSystemTest, GetOtherDirEntry) {
330 const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/other"));
331 scoped_ptr<ResourceEntry> entry = GetResourceEntryByPathSync(kFilePath);
333 EXPECT_EQ(util::kDriveOtherDirSpecialResourceId, entry->resource_id());
335 // Getting the "other" directory entry should not cause the resource load to
337 EXPECT_EQ(0, fake_drive_service_->about_resource_load_count());
338 EXPECT_EQ(0, fake_drive_service_->resource_list_load_count());
341 TEST_F(FileSystemTest, GetMyDriveRoot) {
342 const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root"));
343 scoped_ptr<ResourceEntry> entry = GetResourceEntryByPathSync(kFilePath);
345 EXPECT_EQ(fake_drive_service_->GetRootResourceId(), entry->resource_id());
347 // Absence of "drive/root" in the local metadata triggers the "fast fetch"
348 // of "drive" directory. Fetch of "drive" grand root directory has a special
349 // implementation. Instead of normal GetResourceListInDirectory(), it is
350 // emulated by calling GetAboutResource() so that the resource_id of
351 // "drive/root" is listed.
352 // Together with the normal GetAboutResource() call to retrieve the largest
353 // changestamp, the method is called twice.
354 EXPECT_EQ(2, fake_drive_service_->about_resource_load_count());
356 // After "fast fetch" is done, full resource list is fetched.
357 EXPECT_EQ(1, fake_drive_service_->resource_list_load_count());
359 // "Fast fetch" will fire an OnirectoryChanged event.
360 ASSERT_EQ(1u, mock_directory_observer_->changed_directories().size());
361 EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("drive")),
362 mock_directory_observer_->changed_directories()[0]);
365 TEST_F(FileSystemTest, GetExistingFile) {
366 // Simulate the situation that full feed fetching takes very long time,
367 // to test the recursive "fast fetch" feature is properly working.
368 fake_drive_service_->set_never_return_all_resource_list(true);
370 const base::FilePath kFilePath(
371 FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt"));
372 scoped_ptr<ResourceEntry> entry = GetResourceEntryByPathSync(kFilePath);
374 EXPECT_EQ("file:subdirectory_file_1_id", entry->resource_id());
376 // One server changestamp check (about_resource), three directory load for
377 // "drive", "drive/root", and "drive/root/Directory 1", and one background
378 // full resource list loading. Note that the directory load for "drive" is
379 // special and resorts to about_resource.
380 EXPECT_EQ(2, fake_drive_service_->about_resource_load_count());
381 EXPECT_EQ(2, fake_drive_service_->directory_load_count());
382 EXPECT_EQ(1, fake_drive_service_->blocked_resource_list_load_count());
385 TEST_F(FileSystemTest, GetExistingDocument) {
386 const base::FilePath kFilePath(
387 FILE_PATH_LITERAL("drive/root/Document 1 excludeDir-test.gdoc"));
388 scoped_ptr<ResourceEntry> entry = GetResourceEntryByPathSync(kFilePath);
390 EXPECT_EQ("document:5_document_resource_id", entry->resource_id());
393 TEST_F(FileSystemTest, GetNonExistingFile) {
394 const base::FilePath kFilePath(
395 FILE_PATH_LITERAL("drive/root/nonexisting.file"));
396 scoped_ptr<ResourceEntry> entry = GetResourceEntryByPathSync(kFilePath);
400 TEST_F(FileSystemTest, GetExistingDirectory) {
401 const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/Directory 1"));
402 scoped_ptr<ResourceEntry> entry = GetResourceEntryByPathSync(kFilePath);
404 ASSERT_EQ("folder:1_folder_resource_id", entry->resource_id());
406 // The changestamp should be propagated to the directory.
407 EXPECT_EQ(fake_drive_service_->largest_changestamp(),
408 entry->directory_specific_info().changestamp());
411 TEST_F(FileSystemTest, GetInSubSubdir) {
412 const base::FilePath kFilePath(
413 FILE_PATH_LITERAL("drive/root/Directory 1/Sub Directory Folder/"
414 "Sub Sub Directory Folder"));
415 scoped_ptr<ResourceEntry> entry = GetResourceEntryByPathSync(kFilePath);
417 ASSERT_EQ("folder:sub_sub_directory_folder_id", entry->resource_id());
420 TEST_F(FileSystemTest, GetOrphanFile) {
421 ASSERT_TRUE(LoadFullResourceList());
423 // Entry without parents are placed under "drive/other".
424 const base::FilePath kFilePath(
425 FILE_PATH_LITERAL("drive/other/Orphan File 1.txt"));
426 scoped_ptr<ResourceEntry> entry = GetResourceEntryByPathSync(kFilePath);
428 EXPECT_EQ("file:1_orphanfile_resource_id", entry->resource_id());
431 TEST_F(FileSystemTest, ReadDirectoryByPath_Root) {
432 // ReadDirectoryByPath() should kick off the resource list loading.
433 scoped_ptr<ResourceEntryVector> entries(
434 ReadDirectoryByPathSync(base::FilePath::FromUTF8Unsafe("drive")));
435 // The root directory should be read correctly.
436 ASSERT_TRUE(entries);
437 ASSERT_EQ(2U, entries->size());
439 // The found two directories should be /drive/root and /drive/other.
440 bool found_other = false;
441 bool found_my_drive = false;
442 for (size_t i = 0; i < entries->size(); ++i) {
443 const base::FilePath title =
444 base::FilePath::FromUTF8Unsafe((*entries)[i].title());
445 if (title == base::FilePath(util::kDriveOtherDirName)) {
447 } else if (title == base::FilePath(util::kDriveMyDriveRootDirName)) {
448 found_my_drive = true;
452 EXPECT_TRUE(found_other);
453 EXPECT_TRUE(found_my_drive);
455 ASSERT_EQ(1u, mock_directory_observer_->changed_directories().size());
456 EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("drive")),
457 mock_directory_observer_->changed_directories()[0]);
460 TEST_F(FileSystemTest, ReadDirectoryByPath_NonRootDirectory) {
461 // ReadDirectoryByPath() should kick off the resource list loading.
462 scoped_ptr<ResourceEntryVector> entries(
463 ReadDirectoryByPathSync(
464 base::FilePath::FromUTF8Unsafe("drive/root/Directory 1")));
465 // The non root directory should also be read correctly.
466 // There was a bug (crbug.com/181487), which broke this behavior.
467 // Make sure this is fixed.
468 ASSERT_TRUE(entries);
469 EXPECT_EQ(3U, entries->size());
472 TEST_F(FileSystemTest, LoadFileSystemFromUpToDateCache) {
473 ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_SERVER_TIMESTAMP));
475 // Kicks loading of cached file system and query for server update.
476 EXPECT_TRUE(ReadDirectoryByPathSync(util::GetDriveMyDriveRootPath()));
478 // SetUpTestFileSystem and "account_metadata.json" have the same
479 // changestamp (i.e. the local metadata is up-to-date), so no request for
480 // new resource list (i.e., call to GetResourceList) should happen.
481 EXPECT_EQ(1, fake_drive_service_->about_resource_load_count());
482 EXPECT_EQ(0, fake_drive_service_->resource_list_load_count());
484 // Since the file system has verified that it holds the latest snapshot,
485 // it should change its state to "loaded", which admits periodic refresh.
486 // To test it, call CheckForUpdates and verify it does try to check updates.
487 file_system_->CheckForUpdates();
488 test_util::RunBlockingPoolTask();
489 EXPECT_EQ(2, fake_drive_service_->about_resource_load_count());
492 TEST_F(FileSystemTest, LoadFileSystemFromCacheWhileOffline) {
493 ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_OLD_TIMESTAMP));
495 // Make GetResourceList fail for simulating offline situation. This will
496 // leave the file system "loaded from cache, but not synced with server"
498 fake_drive_service_->set_offline(true);
501 EXPECT_TRUE(ReadDirectoryByPathSync(util::GetDriveGrandRootPath()));
502 // Loading of about resource should not happen as it's offline.
503 EXPECT_EQ(0, fake_drive_service_->about_resource_load_count());
506 EXPECT_TRUE(ReadDirectoryByPathSync(util::GetDriveMyDriveRootPath()));
507 EXPECT_EQ(0, fake_drive_service_->about_resource_load_count());
509 // Tests that cached data can be loaded even if the server is not reachable.
510 EXPECT_TRUE(EntryExists(base::FilePath(
511 FILE_PATH_LITERAL("drive/root/File1"))));
512 EXPECT_TRUE(EntryExists(base::FilePath(
513 FILE_PATH_LITERAL("drive/root/Dir1"))));
514 EXPECT_TRUE(EntryExists(base::FilePath(
515 FILE_PATH_LITERAL("drive/root/Dir1/File2"))));
516 EXPECT_TRUE(EntryExists(base::FilePath(
517 FILE_PATH_LITERAL("drive/root/Dir1/SubDir2"))));
518 EXPECT_TRUE(EntryExists(base::FilePath(
519 FILE_PATH_LITERAL("drive/root/Dir1/SubDir2/File3"))));
521 // Since the file system has at least succeeded to load cached snapshot,
522 // the file system should be able to start periodic refresh.
523 // To test it, call CheckForUpdates and verify it does try to check
524 // updates, which will cause directory changes.
525 fake_drive_service_->set_offline(false);
527 file_system_->CheckForUpdates();
529 test_util::RunBlockingPoolTask();
530 EXPECT_EQ(1, fake_drive_service_->about_resource_load_count());
531 EXPECT_EQ(1, fake_drive_service_->change_list_load_count());
533 ASSERT_LE(1u, mock_directory_observer_->changed_directories().size());
536 TEST_F(FileSystemTest, ReadDirectoryWhileRefreshing) {
537 // Enter the "refreshing" state so the fast fetch will be performed.
538 ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_OLD_TIMESTAMP));
539 file_system_->CheckForUpdates();
541 // The list of resources in "drive/root/Dir1" should be fetched.
542 EXPECT_TRUE(ReadDirectoryByPathSync(base::FilePath(
543 FILE_PATH_LITERAL("drive/root/Dir1"))));
544 EXPECT_EQ(1, fake_drive_service_->directory_load_count());
546 ASSERT_LE(1u, mock_directory_observer_->changed_directories().size());
549 TEST_F(FileSystemTest, GetResourceEntryExistingWhileRefreshing) {
550 // Enter the "refreshing" state.
551 ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_OLD_TIMESTAMP));
552 file_system_->CheckForUpdates();
554 // If an entry is already found in local metadata, no directory fetch happens.
555 EXPECT_TRUE(GetResourceEntryByPathSync(base::FilePath(
556 FILE_PATH_LITERAL("drive/root/Dir1/File2"))));
557 EXPECT_EQ(0, fake_drive_service_->directory_load_count());
560 TEST_F(FileSystemTest, GetResourceEntryNonExistentWhileRefreshing) {
561 // Enter the "refreshing" state so the fast fetch will be performed.
562 ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_OLD_TIMESTAMP));
563 file_system_->CheckForUpdates();
565 // If an entry is not found, parent directory's resource list is fetched.
566 EXPECT_FALSE(GetResourceEntryByPathSync(base::FilePath(
567 FILE_PATH_LITERAL("drive/root/Dir1/NonExistentFile"))));
568 EXPECT_EQ(1, fake_drive_service_->directory_load_count());
570 ASSERT_LE(1u, mock_directory_observer_->changed_directories().size());
573 TEST_F(FileSystemTest, CreateDirectoryByImplicitLoad) {
574 // Intentionally *not* calling LoadFullResourceList(), for testing that
575 // CreateDirectory ensures the resource list is loaded before it runs.
577 base::FilePath existing_directory(
578 FILE_PATH_LITERAL("drive/root/Directory 1"));
579 FileError error = FILE_ERROR_FAILED;
580 file_system_->CreateDirectory(
582 true, // is_exclusive
583 false, // is_recursive
584 google_apis::test_util::CreateCopyResultCallback(&error));
585 test_util::RunBlockingPoolTask();
587 // It should fail because is_exclusive is set to true.
588 EXPECT_EQ(FILE_ERROR_EXISTS, error);
591 TEST_F(FileSystemTest, PinAndUnpin) {
592 ASSERT_TRUE(LoadFullResourceList());
594 base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
596 // Get the file info.
597 scoped_ptr<ResourceEntry> entry(GetResourceEntryByPathSync(file_path));
601 FileError error = FILE_ERROR_FAILED;
602 file_system_->Pin(file_path,
603 google_apis::test_util::CreateCopyResultCallback(&error));
604 test_util::RunBlockingPoolTask();
605 EXPECT_EQ(FILE_ERROR_OK, error);
607 FileCacheEntry cache_entry;
608 EXPECT_TRUE(cache_->GetCacheEntry(entry->local_id(), &cache_entry));
609 EXPECT_TRUE(cache_entry.is_pinned());
610 EXPECT_TRUE(cache_entry.is_present());
613 error = FILE_ERROR_FAILED;
614 file_system_->Unpin(file_path,
615 google_apis::test_util::CreateCopyResultCallback(&error));
616 test_util::RunBlockingPoolTask();
617 EXPECT_EQ(FILE_ERROR_OK, error);
619 EXPECT_TRUE(cache_->GetCacheEntry(entry->local_id(), &cache_entry));
620 EXPECT_FALSE(cache_entry.is_pinned());
622 // Pinned file gets synced and it results in entry state changes.
623 ASSERT_EQ(1u, mock_directory_observer_->changed_directories().size());
624 EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("drive/root")),
625 mock_directory_observer_->changed_directories()[0]);
628 TEST_F(FileSystemTest, PinAndUnpin_NotSynced) {
629 ASSERT_TRUE(LoadFullResourceList());
631 base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
633 // Get the file info.
634 scoped_ptr<ResourceEntry> entry(GetResourceEntryByPathSync(file_path));
637 // Unpin the file just after pinning. File fetch should be cancelled.
638 FileError error_pin = FILE_ERROR_FAILED;
641 google_apis::test_util::CreateCopyResultCallback(&error_pin));
643 FileError error_unpin = FILE_ERROR_FAILED;
646 google_apis::test_util::CreateCopyResultCallback(&error_unpin));
648 test_util::RunBlockingPoolTask();
649 EXPECT_EQ(FILE_ERROR_OK, error_pin);
650 EXPECT_EQ(FILE_ERROR_OK, error_unpin);
652 // No cache file available because the sync was cancelled by Unpin().
653 FileCacheEntry cache_entry;
654 EXPECT_FALSE(cache_->GetCacheEntry(entry->local_id(), &cache_entry));
657 TEST_F(FileSystemTest, GetAvailableSpace) {
658 FileError error = FILE_ERROR_OK;
661 file_system_->GetAvailableSpace(
662 google_apis::test_util::CreateCopyResultCallback(
663 &error, &bytes_total, &bytes_used));
664 test_util::RunBlockingPoolTask();
665 EXPECT_EQ(GG_LONGLONG(6789012345), bytes_used);
666 EXPECT_EQ(GG_LONGLONG(9876543210), bytes_total);
669 TEST_F(FileSystemTest, MarkCacheFileAsMountedAndUnmounted) {
670 ASSERT_TRUE(LoadFullResourceList());
672 base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
673 scoped_ptr<ResourceEntry> entry(GetResourceEntryByPathSync(file_in_root));
677 ASSERT_EQ(FILE_ERROR_OK, cache_->Store(
679 entry->file_specific_info().md5(),
680 google_apis::test_util::GetTestFilePath("gdata/root_feed.json"),
681 internal::FileCache::FILE_OPERATION_COPY));
683 // Test for mounting.
684 FileError error = FILE_ERROR_FAILED;
685 base::FilePath file_path;
686 file_system_->MarkCacheFileAsMounted(
688 google_apis::test_util::CreateCopyResultCallback(&error, &file_path));
689 test_util::RunBlockingPoolTask();
690 EXPECT_EQ(FILE_ERROR_OK, error);
692 // Cannot remove a cache entry while it's being mounted.
693 EXPECT_EQ(FILE_ERROR_IN_USE, cache_->Remove(entry->local_id()));
695 // Test for unmounting.
696 error = FILE_ERROR_FAILED;
697 file_system_->MarkCacheFileAsUnmounted(
699 google_apis::test_util::CreateCopyResultCallback(&error));
700 test_util::RunBlockingPoolTask();
701 EXPECT_EQ(FILE_ERROR_OK, error);
703 // Now able to remove the cache entry.
704 EXPECT_EQ(FILE_ERROR_OK, cache_->Remove(entry->local_id()));
707 TEST_F(FileSystemTest, GetShareUrl) {
708 ASSERT_TRUE(LoadFullResourceList());
710 const base::FilePath kFileInRoot(FILE_PATH_LITERAL("drive/root/File 1.txt"));
711 const GURL kEmbedOrigin("chrome-extension://test-id");
713 // Try to fetch the URL for the sharing dialog.
714 FileError error = FILE_ERROR_FAILED;
716 file_system_->GetShareUrl(
719 google_apis::test_util::CreateCopyResultCallback(&error, &share_url));
720 test_util::RunBlockingPoolTask();
722 // Verify the share url to the sharing dialog.
723 EXPECT_EQ(FILE_ERROR_OK, error);
724 EXPECT_EQ(GURL("https://file_link_share/"), share_url);
727 TEST_F(FileSystemTest, GetShareUrlNotAvailable) {
728 ASSERT_TRUE(LoadFullResourceList());
730 const base::FilePath kFileInRoot(
731 FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt"));
732 const GURL kEmbedOrigin("chrome-extension://test-id");
734 // Try to fetch the URL for the sharing dialog.
735 FileError error = FILE_ERROR_FAILED;
738 file_system_->GetShareUrl(
741 google_apis::test_util::CreateCopyResultCallback(&error, &share_url));
742 test_util::RunBlockingPoolTask();
744 // Verify the error and the share url, which should be empty.
745 EXPECT_EQ(FILE_ERROR_FAILED, error);
746 EXPECT_TRUE(share_url.is_empty());