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/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 "content/public/test/test_browser_thread_bundle.h"
30 #include "google_apis/drive/drive_api_parser.h"
31 #include "google_apis/drive/test_util.h"
32 #include "testing/gtest/include/gtest/gtest.h"
37 // Counts the number of invocation, and if it increased up to |expected_counter|
38 // quits the current message loop by calling |quit|.
39 void AsyncInitializationCallback(
40 int* counter, int expected_counter, const base::Closure& quit,
41 FileError error, scoped_ptr<ResourceEntry> entry) {
42 if (error != FILE_ERROR_OK || !entry) {
43 // If we hit an error case, quit the message loop immediately.
44 // Then the expectation in the test case can find it because the actual
45 // value of |counter| is different from the expected one.
51 if (*counter >= expected_counter)
55 // This class is used to record directory changes and examine them later.
56 class MockDirectoryChangeObserver : public FileSystemObserver {
58 MockDirectoryChangeObserver() {}
59 virtual ~MockDirectoryChangeObserver() {}
61 // FileSystemObserver overrides.
62 virtual void OnDirectoryChanged(
63 const base::FilePath& directory_path) OVERRIDE {
64 changed_directories_.push_back(directory_path);
67 const std::vector<base::FilePath>& changed_directories() const {
68 return changed_directories_;
72 std::vector<base::FilePath> changed_directories_;
73 DISALLOW_COPY_AND_ASSIGN(MockDirectoryChangeObserver);
78 class FileSystemTest : public testing::Test {
80 virtual void SetUp() OVERRIDE {
81 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
82 pref_service_.reset(new TestingPrefServiceSimple);
83 test_util::RegisterDrivePrefs(pref_service_->registry());
85 logger_.reset(new EventLogger);
86 fake_drive_service_.reset(new FakeDriveService);
87 fake_drive_service_->LoadResourceListForWapi(
88 "gdata/root_feed.json");
89 fake_drive_service_->LoadAccountMetadataForWapi(
90 "gdata/account_metadata.json");
92 fake_free_disk_space_getter_.reset(new FakeFreeDiskSpaceGetter);
94 scheduler_.reset(new JobScheduler(pref_service_.get(),
96 fake_drive_service_.get(),
97 base::MessageLoopProxy::current().get()));
99 mock_directory_observer_.reset(new MockDirectoryChangeObserver);
101 SetUpResourceMetadataAndFileSystem();
104 void SetUpResourceMetadataAndFileSystem() {
105 const base::FilePath metadata_dir = temp_dir_.path().AppendASCII("meta");
106 ASSERT_TRUE(base::CreateDirectory(metadata_dir));
107 metadata_storage_.reset(new internal::ResourceMetadataStorage(
108 metadata_dir, base::MessageLoopProxy::current().get()));
109 ASSERT_TRUE(metadata_storage_->Initialize());
111 const base::FilePath cache_dir = temp_dir_.path().AppendASCII("files");
112 ASSERT_TRUE(base::CreateDirectory(cache_dir));
113 cache_.reset(new internal::FileCache(
114 metadata_storage_.get(),
116 base::MessageLoopProxy::current().get(),
117 fake_free_disk_space_getter_.get()));
118 ASSERT_TRUE(cache_->Initialize());
120 resource_metadata_.reset(new internal::ResourceMetadata(
121 metadata_storage_.get(), base::MessageLoopProxy::current()));
122 ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->Initialize());
124 const base::FilePath temp_file_dir = temp_dir_.path().AppendASCII("tmp");
125 ASSERT_TRUE(base::CreateDirectory(temp_file_dir));
126 file_system_.reset(new FileSystem(
130 fake_drive_service_.get(),
132 resource_metadata_.get(),
133 base::MessageLoopProxy::current().get(),
135 file_system_->AddObserver(mock_directory_observer_.get());
137 // Disable delaying so that the sync starts immediately.
138 file_system_->sync_client_for_testing()->set_delay_for_testing(
139 base::TimeDelta::FromSeconds(0));
142 // Loads the full resource list via FakeDriveService.
143 bool LoadFullResourceList() {
144 FileError error = FILE_ERROR_FAILED;
145 file_system_->change_list_loader_for_testing()->LoadIfNeeded(
146 google_apis::test_util::CreateCopyResultCallback(&error));
147 test_util::RunBlockingPoolTask();
148 return error == FILE_ERROR_OK;
151 // Gets resource entry by path synchronously.
152 scoped_ptr<ResourceEntry> GetResourceEntrySync(
153 const base::FilePath& file_path) {
154 FileError error = FILE_ERROR_FAILED;
155 scoped_ptr<ResourceEntry> entry;
156 file_system_->GetResourceEntry(
158 google_apis::test_util::CreateCopyResultCallback(&error, &entry));
159 test_util::RunBlockingPoolTask();
164 // Gets directory info by path synchronously.
165 scoped_ptr<ResourceEntryVector> ReadDirectorySync(
166 const base::FilePath& file_path) {
167 FileError error = FILE_ERROR_FAILED;
168 scoped_ptr<ResourceEntryVector> entries(new ResourceEntryVector);
169 bool last_has_more = true;
170 file_system_->ReadDirectory(
172 base::Bind(&AccumulateReadDirectoryResult,
173 &error, entries.get(), &last_has_more));
174 test_util::RunBlockingPoolTask();
175 if (error != FILE_ERROR_OK)
177 return entries.Pass();
180 // Used to implement ReadDirectorySync().
181 static void AccumulateReadDirectoryResult(
182 FileError* out_error,
183 ResourceEntryVector* out_entries,
186 scoped_ptr<ResourceEntryVector> entries,
188 EXPECT_TRUE(*last_has_more);
190 *last_has_more = has_more;
191 if (error == FILE_ERROR_OK) {
192 ASSERT_TRUE(entries);
193 out_entries->insert(out_entries->end(), entries->begin(), entries->end());
195 EXPECT_FALSE(has_more);
199 // Returns true if an entry exists at |file_path|.
200 bool EntryExists(const base::FilePath& file_path) {
201 return GetResourceEntrySync(file_path);
204 // Flag for specifying the timestamp of the test filesystem cache.
205 enum SetUpTestFileSystemParam {
207 USE_SERVER_TIMESTAMP,
210 // Sets up a filesystem with directories: drive/root, drive/root/Dir1,
211 // drive/root/Dir1/SubDir2 and files drive/root/File1, drive/root/Dir1/File2,
212 // drive/root/Dir1/SubDir2/File3. If |use_up_to_date_timestamp| is true, sets
213 // the changestamp to 654321, equal to that of "account_metadata.json" test
214 // data, indicating the cache is holding the latest file system info.
215 void SetUpTestFileSystem(SetUpTestFileSystemParam param) {
216 // Destroy the existing resource metadata to close DB.
217 resource_metadata_.reset();
219 const base::FilePath metadata_dir = temp_dir_.path().AppendASCII("meta");
220 ASSERT_TRUE(base::CreateDirectory(metadata_dir));
221 scoped_ptr<internal::ResourceMetadataStorage,
222 test_util::DestroyHelperForTests> metadata_storage(
223 new internal::ResourceMetadataStorage(
224 metadata_dir, base::MessageLoopProxy::current().get()));
226 scoped_ptr<internal::ResourceMetadata, test_util::DestroyHelperForTests>
227 resource_metadata(new internal::ResourceMetadata(
228 metadata_storage_.get(), base::MessageLoopProxy::current()));
230 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->Initialize());
232 const int64 changestamp = param == USE_SERVER_TIMESTAMP ? 654321 : 1;
233 ASSERT_EQ(FILE_ERROR_OK,
234 resource_metadata->SetLargestChangestamp(changestamp));
238 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->GetResourceEntryByPath(
239 util::GetDriveMyDriveRootPath(), &root));
240 root.set_resource_id(fake_drive_service_->GetRootResourceId());
241 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->RefreshEntry(root));
243 std::string local_id;
247 file1.set_title("File1");
248 file1.set_resource_id("resource_id:File1");
249 file1.set_parent_local_id(root.local_id());
250 file1.mutable_file_specific_info()->set_md5("md5");
251 file1.mutable_file_info()->set_is_directory(false);
252 file1.mutable_file_info()->set_size(1048576);
253 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(file1, &local_id));
257 dir1.set_title("Dir1");
258 dir1.set_resource_id("resource_id:Dir1");
259 dir1.set_parent_local_id(root.local_id());
260 dir1.mutable_file_info()->set_is_directory(true);
261 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(dir1, &local_id));
262 const std::string dir1_local_id = local_id;
264 // drive/root/Dir1/File2
266 file2.set_title("File2");
267 file2.set_resource_id("resource_id:File2");
268 file2.set_parent_local_id(dir1_local_id);
269 file2.mutable_file_specific_info()->set_md5("md5");
270 file2.mutable_file_info()->set_is_directory(false);
271 file2.mutable_file_info()->set_size(555);
272 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(file2, &local_id));
274 // drive/root/Dir1/SubDir2
276 dir2.set_title("SubDir2");
277 dir2.set_resource_id("resource_id:SubDir2");
278 dir2.set_parent_local_id(dir1_local_id);
279 dir2.mutable_file_info()->set_is_directory(true);
280 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(dir2, &local_id));
281 const std::string dir2_local_id = local_id;
283 // drive/root/Dir1/SubDir2/File3
285 file3.set_title("File3");
286 file3.set_resource_id("resource_id:File3");
287 file3.set_parent_local_id(dir2_local_id);
288 file3.mutable_file_specific_info()->set_md5("md5");
289 file3.mutable_file_info()->set_is_directory(false);
290 file3.mutable_file_info()->set_size(12345);
291 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(file3, &local_id));
293 // Recreate resource metadata.
294 SetUpResourceMetadataAndFileSystem();
297 content::TestBrowserThreadBundle thread_bundle_;
298 base::ScopedTempDir temp_dir_;
299 // We don't use TestingProfile::GetPrefs() in favor of having less
300 // dependencies to Profile in general.
301 scoped_ptr<TestingPrefServiceSimple> pref_service_;
303 scoped_ptr<EventLogger> logger_;
304 scoped_ptr<FakeDriveService> fake_drive_service_;
305 scoped_ptr<FakeFreeDiskSpaceGetter> fake_free_disk_space_getter_;
306 scoped_ptr<JobScheduler> scheduler_;
307 scoped_ptr<MockDirectoryChangeObserver> mock_directory_observer_;
309 scoped_ptr<internal::ResourceMetadataStorage,
310 test_util::DestroyHelperForTests> metadata_storage_;
311 scoped_ptr<internal::FileCache, test_util::DestroyHelperForTests> cache_;
312 scoped_ptr<internal::ResourceMetadata, test_util::DestroyHelperForTests>
314 scoped_ptr<FileSystem> file_system_;
317 TEST_F(FileSystemTest, Copy) {
318 base::FilePath src_file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
319 base::FilePath dest_file_path(FILE_PATH_LITERAL("drive/root/Copied.txt"));
320 EXPECT_TRUE(GetResourceEntrySync(src_file_path));
321 EXPECT_FALSE(GetResourceEntrySync(dest_file_path));
323 FileError error = FILE_ERROR_FAILED;
324 file_system_->Copy(src_file_path,
326 false, // preserve_last_modified,
327 google_apis::test_util::CreateCopyResultCallback(&error));
328 test_util::RunBlockingPoolTask();
329 EXPECT_EQ(FILE_ERROR_OK, error);
331 // Entry is added on the server.
332 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(dest_file_path);
335 google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR;
336 scoped_ptr<google_apis::ResourceEntry> resource_entry;
337 fake_drive_service_->GetResourceEntry(
338 entry->resource_id(),
339 google_apis::test_util::CreateCopyResultCallback(&status,
341 test_util::RunBlockingPoolTask();
342 EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
343 ASSERT_TRUE(resource_entry);
344 EXPECT_EQ(entry->title(), resource_entry->title());
345 EXPECT_TRUE(resource_entry->is_file());
348 TEST_F(FileSystemTest, Move) {
349 base::FilePath src_file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
350 base::FilePath dest_file_path(
351 FILE_PATH_LITERAL("drive/root/Directory 1/Moved.txt"));
352 EXPECT_TRUE(GetResourceEntrySync(src_file_path));
353 EXPECT_FALSE(GetResourceEntrySync(dest_file_path));
354 scoped_ptr<ResourceEntry> parent =
355 GetResourceEntrySync(dest_file_path.DirName());
358 FileError error = FILE_ERROR_FAILED;
359 file_system_->Move(src_file_path,
361 google_apis::test_util::CreateCopyResultCallback(&error));
362 test_util::RunBlockingPoolTask();
363 EXPECT_EQ(FILE_ERROR_OK, error);
365 // Entry is moved on the server.
366 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(dest_file_path);
369 google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR;
370 scoped_ptr<google_apis::ResourceEntry> resource_entry;
371 fake_drive_service_->GetResourceEntry(
372 entry->resource_id(),
373 google_apis::test_util::CreateCopyResultCallback(&status,
375 test_util::RunBlockingPoolTask();
376 EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
377 ASSERT_TRUE(resource_entry);
378 EXPECT_EQ(entry->title(), resource_entry->title());
380 const google_apis::Link* parent_link =
381 resource_entry->GetLinkByType(google_apis::Link::LINK_PARENT);
382 ASSERT_TRUE(parent_link);
383 EXPECT_EQ(parent->resource_id(),
384 util::ExtractResourceIdFromUrl(parent_link->href()));
387 TEST_F(FileSystemTest, Remove) {
388 base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
389 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(file_path);
392 FileError error = FILE_ERROR_FAILED;
393 file_system_->Remove(
395 false, // is_resursive
396 google_apis::test_util::CreateCopyResultCallback(&error));
397 test_util::RunBlockingPoolTask();
398 EXPECT_EQ(FILE_ERROR_OK, error);
400 // Entry is removed on the server.
401 google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR;
402 scoped_ptr<google_apis::ResourceEntry> resource_entry;
403 fake_drive_service_->GetResourceEntry(
404 entry->resource_id(),
405 google_apis::test_util::CreateCopyResultCallback(&status,
407 test_util::RunBlockingPoolTask();
408 EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
409 ASSERT_TRUE(resource_entry);
410 EXPECT_TRUE(resource_entry->deleted());
413 TEST_F(FileSystemTest, CreateDirectory) {
414 base::FilePath directory_path(FILE_PATH_LITERAL("drive/root/New Directory"));
415 EXPECT_FALSE(GetResourceEntrySync(directory_path));
417 FileError error = FILE_ERROR_FAILED;
418 file_system_->CreateDirectory(
420 true, // is_exclusive
421 false, // is_recursive
422 google_apis::test_util::CreateCopyResultCallback(&error));
423 test_util::RunBlockingPoolTask();
424 EXPECT_EQ(FILE_ERROR_OK, error);
426 // Directory is created on the server.
427 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(directory_path);
430 google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR;
431 scoped_ptr<google_apis::ResourceEntry> resource_entry;
432 fake_drive_service_->GetResourceEntry(
433 entry->resource_id(),
434 google_apis::test_util::CreateCopyResultCallback(&status,
436 test_util::RunBlockingPoolTask();
437 EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
438 ASSERT_TRUE(resource_entry);
439 EXPECT_EQ(entry->title(), resource_entry->title());
440 EXPECT_TRUE(resource_entry->is_folder());
443 TEST_F(FileSystemTest, CreateFile) {
444 base::FilePath file_path(FILE_PATH_LITERAL("drive/root/New File.txt"));
445 EXPECT_FALSE(GetResourceEntrySync(file_path));
447 FileError error = FILE_ERROR_FAILED;
448 file_system_->CreateFile(
450 true, // is_exclusive
452 google_apis::test_util::CreateCopyResultCallback(&error));
453 test_util::RunBlockingPoolTask();
454 EXPECT_EQ(FILE_ERROR_OK, error);
456 // File is created on the server.
457 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(file_path);
460 google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR;
461 scoped_ptr<google_apis::ResourceEntry> resource_entry;
462 fake_drive_service_->GetResourceEntry(
463 entry->resource_id(),
464 google_apis::test_util::CreateCopyResultCallback(&status,
466 test_util::RunBlockingPoolTask();
467 EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
468 ASSERT_TRUE(resource_entry);
469 EXPECT_EQ(entry->title(), resource_entry->title());
470 EXPECT_TRUE(resource_entry->is_file());
473 TEST_F(FileSystemTest, TouchFile) {
474 base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
475 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(file_path);
478 base::Time last_accessed =
479 base::Time::FromInternalValue(entry->file_info().last_accessed()) +
480 base::TimeDelta::FromSeconds(1);
481 base::Time last_modified =
482 base::Time::FromInternalValue(entry->file_info().last_modified()) +
483 base::TimeDelta::FromSeconds(1);
485 FileError error = FILE_ERROR_FAILED;
486 file_system_->TouchFile(
490 google_apis::test_util::CreateCopyResultCallback(&error));
491 test_util::RunBlockingPoolTask();
492 EXPECT_EQ(FILE_ERROR_OK, error);
494 // File is touched on the server.
495 google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR;
496 scoped_ptr<google_apis::ResourceEntry> resource_entry;
497 fake_drive_service_->GetResourceEntry(
498 entry->resource_id(),
499 google_apis::test_util::CreateCopyResultCallback(&status,
501 test_util::RunBlockingPoolTask();
502 EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
503 ASSERT_TRUE(resource_entry);
504 EXPECT_EQ(last_accessed, resource_entry->last_viewed_time());
505 EXPECT_EQ(last_modified, resource_entry->updated_time());
508 TEST_F(FileSystemTest, TruncateFile) {
509 base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
510 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(file_path);
513 const int64 kLength = entry->file_info().size() + 100;
515 FileError error = FILE_ERROR_FAILED;
516 file_system_->TruncateFile(
519 google_apis::test_util::CreateCopyResultCallback(&error));
520 test_util::RunBlockingPoolTask();
521 EXPECT_EQ(FILE_ERROR_OK, error);
523 // File is touched on the server.
524 google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR;
525 scoped_ptr<google_apis::ResourceEntry> resource_entry;
526 fake_drive_service_->GetResourceEntry(
527 entry->resource_id(),
528 google_apis::test_util::CreateCopyResultCallback(&status,
530 test_util::RunBlockingPoolTask();
531 EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
532 ASSERT_TRUE(resource_entry);
533 EXPECT_EQ(kLength, resource_entry->file_size());
536 TEST_F(FileSystemTest, DuplicatedAsyncInitialization) {
540 const GetResourceEntryCallback& callback = base::Bind(
541 &AsyncInitializationCallback, &counter, 2, loop.QuitClosure());
543 file_system_->GetResourceEntry(
544 base::FilePath(FILE_PATH_LITERAL("drive/root")), callback);
545 file_system_->GetResourceEntry(
546 base::FilePath(FILE_PATH_LITERAL("drive/root")), callback);
547 loop.Run(); // Wait to get our result
548 EXPECT_EQ(2, counter);
550 EXPECT_EQ(1, fake_drive_service_->resource_list_load_count());
553 TEST_F(FileSystemTest, GetGrandRootEntry) {
554 const base::FilePath kFilePath(FILE_PATH_LITERAL("drive"));
555 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
557 EXPECT_EQ(util::kDriveGrandRootLocalId, entry->local_id());
560 TEST_F(FileSystemTest, GetOtherDirEntry) {
561 const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/other"));
562 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
564 EXPECT_EQ(util::kDriveOtherDirLocalId, entry->local_id());
567 TEST_F(FileSystemTest, GetMyDriveRoot) {
568 const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root"));
569 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
571 EXPECT_EQ(fake_drive_service_->GetRootResourceId(), entry->resource_id());
573 // After "fast fetch" is done, full resource list is fetched.
574 EXPECT_EQ(1, fake_drive_service_->resource_list_load_count());
577 TEST_F(FileSystemTest, GetExistingFile) {
578 // Simulate the situation that full feed fetching takes very long time,
579 // to test the recursive "fast fetch" feature is properly working.
580 fake_drive_service_->set_never_return_all_resource_list(true);
582 const base::FilePath kFilePath(
583 FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt"));
584 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
586 EXPECT_EQ("file:subdirectory_file_1_id", entry->resource_id());
588 EXPECT_EQ(1, fake_drive_service_->about_resource_load_count());
589 EXPECT_EQ(2, fake_drive_service_->directory_load_count());
590 EXPECT_EQ(1, fake_drive_service_->blocked_resource_list_load_count());
593 TEST_F(FileSystemTest, GetExistingDocument) {
594 const base::FilePath kFilePath(
595 FILE_PATH_LITERAL("drive/root/Document 1 excludeDir-test.gdoc"));
596 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
598 EXPECT_EQ("document:5_document_resource_id", entry->resource_id());
601 TEST_F(FileSystemTest, GetNonExistingFile) {
602 const base::FilePath kFilePath(
603 FILE_PATH_LITERAL("drive/root/nonexisting.file"));
604 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
608 TEST_F(FileSystemTest, GetInSubSubdir) {
609 const base::FilePath kFilePath(
610 FILE_PATH_LITERAL("drive/root/Directory 1/Sub Directory Folder/"
611 "Sub Sub Directory Folder"));
612 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
614 ASSERT_EQ("folder:sub_sub_directory_folder_id", entry->resource_id());
617 TEST_F(FileSystemTest, GetOrphanFile) {
618 ASSERT_TRUE(LoadFullResourceList());
620 // Entry without parents are placed under "drive/other".
621 const base::FilePath kFilePath(
622 FILE_PATH_LITERAL("drive/other/Orphan File 1.txt"));
623 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
625 EXPECT_EQ("file:1_orphanfile_resource_id", entry->resource_id());
628 TEST_F(FileSystemTest, ReadDirectory_Root) {
629 // ReadDirectory() should kick off the resource list loading.
630 scoped_ptr<ResourceEntryVector> entries(
631 ReadDirectorySync(base::FilePath::FromUTF8Unsafe("drive")));
632 // The root directory should be read correctly.
633 ASSERT_TRUE(entries);
634 ASSERT_EQ(3U, entries->size());
636 // The found three directories should be /drive/root, /drive/other and
638 std::set<base::FilePath> found;
639 for (size_t i = 0; i < entries->size(); ++i)
640 found.insert(base::FilePath::FromUTF8Unsafe((*entries)[i].title()));
641 EXPECT_EQ(3U, found.size());
642 EXPECT_EQ(1U, found.count(base::FilePath(util::kDriveMyDriveRootDirName)));
643 EXPECT_EQ(1U, found.count(base::FilePath(util::kDriveOtherDirName)));
644 EXPECT_EQ(1U, found.count(base::FilePath(util::kDriveTrashDirName)));
647 TEST_F(FileSystemTest, ReadDirectory_NonRootDirectory) {
648 // ReadDirectory() should kick off the resource list loading.
649 scoped_ptr<ResourceEntryVector> entries(
651 base::FilePath::FromUTF8Unsafe("drive/root/Directory 1")));
652 // The non root directory should also be read correctly.
653 // There was a bug (crbug.com/181487), which broke this behavior.
654 // Make sure this is fixed.
655 ASSERT_TRUE(entries);
656 EXPECT_EQ(3U, entries->size());
659 TEST_F(FileSystemTest, LoadFileSystemFromUpToDateCache) {
660 ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_SERVER_TIMESTAMP));
662 // Kicks loading of cached file system and query for server update.
663 EXPECT_TRUE(ReadDirectorySync(util::GetDriveMyDriveRootPath()));
665 // SetUpTestFileSystem and "account_metadata.json" have the same
666 // changestamp (i.e. the local metadata is up-to-date), so no request for
667 // new resource list (i.e., call to GetResourceList) should happen.
668 EXPECT_EQ(0, fake_drive_service_->resource_list_load_count());
670 // Since the file system has verified that it holds the latest snapshot,
671 // it should change its state to "loaded", which admits periodic refresh.
672 // To test it, call CheckForUpdates and verify it does try to check updates.
673 const int about_resource_load_count_before =
674 fake_drive_service_->about_resource_load_count();
675 file_system_->CheckForUpdates();
676 test_util::RunBlockingPoolTask();
677 EXPECT_LT(about_resource_load_count_before,
678 fake_drive_service_->about_resource_load_count());
681 TEST_F(FileSystemTest, LoadFileSystemFromCacheWhileOffline) {
682 ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_OLD_TIMESTAMP));
684 // Make GetResourceList fail for simulating offline situation. This will
685 // leave the file system "loaded from cache, but not synced with server"
687 fake_drive_service_->set_offline(true);
690 EXPECT_TRUE(ReadDirectorySync(util::GetDriveGrandRootPath()));
691 // Loading of about resource should not happen as it's offline.
692 EXPECT_EQ(0, fake_drive_service_->about_resource_load_count());
695 EXPECT_TRUE(ReadDirectorySync(util::GetDriveMyDriveRootPath()));
696 EXPECT_EQ(0, fake_drive_service_->about_resource_load_count());
698 // Tests that cached data can be loaded even if the server is not reachable.
699 EXPECT_TRUE(EntryExists(base::FilePath(
700 FILE_PATH_LITERAL("drive/root/File1"))));
701 EXPECT_TRUE(EntryExists(base::FilePath(
702 FILE_PATH_LITERAL("drive/root/Dir1"))));
703 EXPECT_TRUE(EntryExists(base::FilePath(
704 FILE_PATH_LITERAL("drive/root/Dir1/File2"))));
705 EXPECT_TRUE(EntryExists(base::FilePath(
706 FILE_PATH_LITERAL("drive/root/Dir1/SubDir2"))));
707 EXPECT_TRUE(EntryExists(base::FilePath(
708 FILE_PATH_LITERAL("drive/root/Dir1/SubDir2/File3"))));
710 // Since the file system has at least succeeded to load cached snapshot,
711 // the file system should be able to start periodic refresh.
712 // To test it, call CheckForUpdates and verify it does try to check
713 // updates, which will cause directory changes.
714 fake_drive_service_->set_offline(false);
716 file_system_->CheckForUpdates();
718 test_util::RunBlockingPoolTask();
719 EXPECT_EQ(1, fake_drive_service_->about_resource_load_count());
720 EXPECT_EQ(1, fake_drive_service_->change_list_load_count());
722 ASSERT_LE(1u, mock_directory_observer_->changed_directories().size());
725 TEST_F(FileSystemTest, ReadDirectoryWhileRefreshing) {
726 // Use old timestamp so the fast fetch will be performed.
727 ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_OLD_TIMESTAMP));
729 // The list of resources in "drive/root/Dir1" should be fetched.
730 EXPECT_TRUE(ReadDirectorySync(base::FilePath(
731 FILE_PATH_LITERAL("drive/root/Dir1"))));
732 EXPECT_EQ(1, fake_drive_service_->directory_load_count());
734 ASSERT_LE(1u, mock_directory_observer_->changed_directories().size());
737 TEST_F(FileSystemTest, GetResourceEntryNonExistentWhileRefreshing) {
738 // Use old timestamp so the fast fetch will be performed.
739 ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_OLD_TIMESTAMP));
741 // If an entry is not found, parent directory's resource list is fetched.
742 EXPECT_FALSE(GetResourceEntrySync(base::FilePath(
743 FILE_PATH_LITERAL("drive/root/Dir1/NonExistentFile"))));
744 EXPECT_EQ(1, fake_drive_service_->directory_load_count());
746 ASSERT_LE(1u, mock_directory_observer_->changed_directories().size());
749 TEST_F(FileSystemTest, CreateDirectoryByImplicitLoad) {
750 // Intentionally *not* calling LoadFullResourceList(), for testing that
751 // CreateDirectory ensures the resource list is loaded before it runs.
753 base::FilePath existing_directory(
754 FILE_PATH_LITERAL("drive/root/Directory 1"));
755 FileError error = FILE_ERROR_FAILED;
756 file_system_->CreateDirectory(
758 true, // is_exclusive
759 false, // is_recursive
760 google_apis::test_util::CreateCopyResultCallback(&error));
761 test_util::RunBlockingPoolTask();
763 // It should fail because is_exclusive is set to true.
764 EXPECT_EQ(FILE_ERROR_EXISTS, error);
767 TEST_F(FileSystemTest, CreateDirectoryRecursively) {
768 // Intentionally *not* calling LoadFullResourceList(), for testing that
769 // CreateDirectory ensures the resource list is loaded before it runs.
771 base::FilePath new_directory(
772 FILE_PATH_LITERAL("drive/root/Directory 1/a/b/c/d"));
773 FileError error = FILE_ERROR_FAILED;
774 file_system_->CreateDirectory(
776 true, // is_exclusive
777 true, // is_recursive
778 google_apis::test_util::CreateCopyResultCallback(&error));
779 test_util::RunBlockingPoolTask();
781 EXPECT_EQ(FILE_ERROR_OK, error);
783 scoped_ptr<ResourceEntry> entry(GetResourceEntrySync(new_directory));
785 EXPECT_TRUE(entry->file_info().is_directory());
788 TEST_F(FileSystemTest, PinAndUnpin) {
789 ASSERT_TRUE(LoadFullResourceList());
791 base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
793 // Get the file info.
794 scoped_ptr<ResourceEntry> entry(GetResourceEntrySync(file_path));
798 FileError error = FILE_ERROR_FAILED;
799 file_system_->Pin(file_path,
800 google_apis::test_util::CreateCopyResultCallback(&error));
801 test_util::RunBlockingPoolTask();
802 EXPECT_EQ(FILE_ERROR_OK, error);
804 FileCacheEntry cache_entry;
805 EXPECT_TRUE(cache_->GetCacheEntry(entry->local_id(), &cache_entry));
806 EXPECT_TRUE(cache_entry.is_pinned());
807 EXPECT_TRUE(cache_entry.is_present());
810 error = FILE_ERROR_FAILED;
811 file_system_->Unpin(file_path,
812 google_apis::test_util::CreateCopyResultCallback(&error));
813 test_util::RunBlockingPoolTask();
814 EXPECT_EQ(FILE_ERROR_OK, error);
816 EXPECT_TRUE(cache_->GetCacheEntry(entry->local_id(), &cache_entry));
817 EXPECT_FALSE(cache_entry.is_pinned());
819 // Pinned file gets synced and it results in entry state changes.
820 ASSERT_EQ(1u, mock_directory_observer_->changed_directories().size());
821 EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("drive/root")),
822 mock_directory_observer_->changed_directories()[0]);
825 TEST_F(FileSystemTest, PinAndUnpin_NotSynced) {
826 ASSERT_TRUE(LoadFullResourceList());
828 base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
830 // Get the file info.
831 scoped_ptr<ResourceEntry> entry(GetResourceEntrySync(file_path));
834 // Unpin the file just after pinning. File fetch should be cancelled.
835 FileError error_pin = FILE_ERROR_FAILED;
838 google_apis::test_util::CreateCopyResultCallback(&error_pin));
840 FileError error_unpin = FILE_ERROR_FAILED;
843 google_apis::test_util::CreateCopyResultCallback(&error_unpin));
845 test_util::RunBlockingPoolTask();
846 EXPECT_EQ(FILE_ERROR_OK, error_pin);
847 EXPECT_EQ(FILE_ERROR_OK, error_unpin);
849 // No cache file available because the sync was cancelled by Unpin().
850 FileCacheEntry cache_entry;
851 EXPECT_FALSE(cache_->GetCacheEntry(entry->local_id(), &cache_entry));
854 TEST_F(FileSystemTest, GetAvailableSpace) {
855 FileError error = FILE_ERROR_OK;
858 file_system_->GetAvailableSpace(
859 google_apis::test_util::CreateCopyResultCallback(
860 &error, &bytes_total, &bytes_used));
861 test_util::RunBlockingPoolTask();
862 EXPECT_EQ(GG_LONGLONG(6789012345), bytes_used);
863 EXPECT_EQ(GG_LONGLONG(9876543210), bytes_total);
866 TEST_F(FileSystemTest, MarkCacheFileAsMountedAndUnmounted) {
867 ASSERT_TRUE(LoadFullResourceList());
869 base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
870 scoped_ptr<ResourceEntry> entry(GetResourceEntrySync(file_in_root));
874 ASSERT_EQ(FILE_ERROR_OK, cache_->Store(
876 entry->file_specific_info().md5(),
877 google_apis::test_util::GetTestFilePath("gdata/root_feed.json"),
878 internal::FileCache::FILE_OPERATION_COPY));
880 // Test for mounting.
881 FileError error = FILE_ERROR_FAILED;
882 base::FilePath file_path;
883 file_system_->MarkCacheFileAsMounted(
885 google_apis::test_util::CreateCopyResultCallback(&error, &file_path));
886 test_util::RunBlockingPoolTask();
887 EXPECT_EQ(FILE_ERROR_OK, error);
889 // Cannot remove a cache entry while it's being mounted.
890 EXPECT_EQ(FILE_ERROR_IN_USE, cache_->Remove(entry->local_id()));
892 // Test for unmounting.
893 error = FILE_ERROR_FAILED;
894 file_system_->MarkCacheFileAsUnmounted(
896 google_apis::test_util::CreateCopyResultCallback(&error));
897 test_util::RunBlockingPoolTask();
898 EXPECT_EQ(FILE_ERROR_OK, error);
900 // Now able to remove the cache entry.
901 EXPECT_EQ(FILE_ERROR_OK, cache_->Remove(entry->local_id()));
904 TEST_F(FileSystemTest, GetShareUrl) {
905 ASSERT_TRUE(LoadFullResourceList());
907 const base::FilePath kFileInRoot(FILE_PATH_LITERAL("drive/root/File 1.txt"));
908 const GURL kEmbedOrigin("chrome-extension://test-id");
910 // Try to fetch the URL for the sharing dialog.
911 FileError error = FILE_ERROR_FAILED;
913 file_system_->GetShareUrl(
916 google_apis::test_util::CreateCopyResultCallback(&error, &share_url));
917 test_util::RunBlockingPoolTask();
919 // Verify the share url to the sharing dialog.
920 EXPECT_EQ(FILE_ERROR_OK, error);
921 EXPECT_EQ(GURL("https://file_link_share/"), share_url);
924 TEST_F(FileSystemTest, GetShareUrlNotAvailable) {
925 ASSERT_TRUE(LoadFullResourceList());
927 const base::FilePath kFileInRoot(
928 FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt"));
929 const GURL kEmbedOrigin("chrome-extension://test-id");
931 // Try to fetch the URL for the sharing dialog.
932 FileError error = FILE_ERROR_FAILED;
935 file_system_->GetShareUrl(
938 google_apis::test_util::CreateCopyResultCallback(&error, &share_url));
939 test_util::RunBlockingPoolTask();
941 // Verify the error and the share url, which should be empty.
942 EXPECT_EQ(FILE_ERROR_FAILED, error);
943 EXPECT_TRUE(share_url.is_empty());