blob: decc20b126f82cc4fa0e1c6269ee3c76e7e0cf9d [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/drive/chromeos/file_system.h"
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include <string>
#include <vector>
#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/macros.h"
#include "base/test/test_mock_time_task_runner.h"
#include "components/drive/chromeos/drive_change_list_loader.h"
#include "components/drive/chromeos/drive_test_util.h"
#include "components/drive/chromeos/fake_free_disk_space_getter.h"
#include "components/drive/chromeos/file_system_observer.h"
#include "components/drive/chromeos/sync_client.h"
#include "components/drive/drive.pb.h"
#include "components/drive/drive_api_util.h"
#include "components/drive/event_logger.h"
#include "components/drive/file_change.h"
#include "components/drive/file_system_core_util.h"
#include "components/drive/job_scheduler.h"
#include "components/drive/service/fake_drive_service.h"
#include "components/drive/service/test_util.h"
#include "components/prefs/testing_pref_service.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "google_apis/drive/drive_api_parser.h"
#include "google_apis/drive/test_util.h"
#include "services/network/test/test_network_connection_tracker.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace drive {
namespace {
// Counts the number of invocation, and if it increased up to |expected_counter|
// quits the current message loop by calling |quit|.
void AsyncInitializationCallback(int* counter,
int expected_counter,
const base::Closure& quit,
FileError error,
std::unique_ptr<ResourceEntry> entry) {
if (error != FILE_ERROR_OK || !entry) {
// If we hit an error case, quit the message loop immediately.
// Then the expectation in the test case can find it because the actual
// value of |counter| is different from the expected one.
quit.Run();
return;
}
(*counter)++;
if (*counter >= expected_counter)
quit.Run();
}
bool CompareHashAndFilePath(const HashAndFilePath& a,
const HashAndFilePath& b) {
const int result = a.hash.compare(b.hash);
if (result < 0)
return true;
if (result > 0)
return false;
return a.path.AsUTF8Unsafe().compare(b.path.AsUTF8Unsafe()) < 0;
}
// This class is used to record directory changes and examine them later.
class MockDirectoryChangeObserver : public FileSystemObserver {
public:
MockDirectoryChangeObserver() = default;
~MockDirectoryChangeObserver() override = default;
// FileSystemObserver overrides.
void OnDirectoryChanged(const base::FilePath& directory_path) override {
changed_directories_.push_back(directory_path);
}
void OnFileChanged(const FileChange& new_file_change) override {
changed_files_.Apply(new_file_change);
}
void OnTeamDrivesUpdated(
const std::set<std::string>& added_team_drive_ids,
const std::set<std::string>& removed_team_drive_ids) override {
added_team_drive_ids_ = added_team_drive_ids;
removed_team_drive_ids_ = removed_team_drive_ids;
}
const std::vector<base::FilePath>& changed_directories() const {
return changed_directories_;
}
const FileChange& changed_files() const { return changed_files_; }
const std::set<std::string>& added_team_drive_ids() const {
return added_team_drive_ids_;
}
const std::set<std::string>& removed_team_drive_ids() const {
return removed_team_drive_ids_;
}
private:
std::vector<base::FilePath> changed_directories_;
FileChange changed_files_;
std::set<std::string> added_team_drive_ids_;
std::set<std::string> removed_team_drive_ids_;
DISALLOW_COPY_AND_ASSIGN(MockDirectoryChangeObserver);
};
struct DestroyHelper {
// FileSystemTest needs to be default constructible, so we provide a default
// constructor here.
DestroyHelper() = default;
explicit DestroyHelper(
scoped_refptr<base::TestMockTimeTaskRunner> task_runner)
: task_runner_(task_runner) {}
template <typename T>
void operator()(T* object) const {
DCHECK(task_runner_);
if (object) {
object->Destroy();
task_runner_->RunUntilIdle();
}
}
scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
};
} // namespace
class FileSystemTest : public testing::Test {
protected:
void SetUp() override {
task_runner_ = base::MakeRefCounted<base::TestMockTimeTaskRunner>(
base::TestMockTimeTaskRunner::Type::kBoundToThread);
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
pref_service_ = std::make_unique<TestingPrefServiceSimple>();
test_util::RegisterDrivePrefs(pref_service_->registry());
logger_ = std::make_unique<EventLogger>();
fake_drive_service_ = std::make_unique<FakeDriveService>();
test_util::SetUpTestEntries(fake_drive_service_.get());
fake_free_disk_space_getter_ = std::make_unique<FakeFreeDiskSpaceGetter>();
network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType(
network::mojom::ConnectionType::CONNECTION_WIFI);
scheduler_ = std::make_unique<JobScheduler>(
pref_service_.get(), logger_.get(), fake_drive_service_.get(),
network::TestNetworkConnectionTracker::GetInstance(),
task_runner_.get(), nullptr);
mock_directory_observer_ = std::make_unique<MockDirectoryChangeObserver>();
SetUpResourceMetadataAndFileSystem();
}
void SetUpResourceMetadataAndFileSystem() {
const base::FilePath metadata_dir = temp_dir_.GetPath().AppendASCII("meta");
ASSERT_TRUE(base::CreateDirectory(metadata_dir));
metadata_storage_ =
std::unique_ptr<internal::ResourceMetadataStorage, DestroyHelper>(
new internal::ResourceMetadataStorage(metadata_dir,
task_runner_.get()),
DestroyHelper(task_runner_.get()));
ASSERT_TRUE(metadata_storage_->Initialize());
const base::FilePath cache_dir = temp_dir_.GetPath().AppendASCII("files");
ASSERT_TRUE(base::CreateDirectory(cache_dir));
cache_ = std::unique_ptr<internal::FileCache, DestroyHelper>(
new internal::FileCache(metadata_storage_.get(), cache_dir,
task_runner_.get(),
fake_free_disk_space_getter_.get()),
DestroyHelper(task_runner_.get()));
ASSERT_TRUE(cache_->Initialize());
resource_metadata_ =
std::unique_ptr<internal::ResourceMetadata, DestroyHelper>(
new internal::ResourceMetadata(metadata_storage_.get(),
cache_.get(), task_runner_.get()),
DestroyHelper(task_runner_.get()));
ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->Initialize());
const base::FilePath temp_file_dir = temp_dir_.GetPath().AppendASCII("tmp");
ASSERT_TRUE(base::CreateDirectory(temp_file_dir));
file_system_ = std::make_unique<FileSystem>(
logger_.get(), cache_.get(), scheduler_.get(), resource_metadata_.get(),
task_runner_.get(), temp_file_dir, task_runner_->GetMockClock());
file_system_->AddObserver(mock_directory_observer_.get());
// Disable delaying so that the sync starts immediately.
file_system_->sync_client_for_testing()->set_delay_for_testing(
base::TimeDelta::FromSeconds(0));
file_system_->team_drive_operation_queue_for_testing()
->DisableQueueForTesting();
}
// Loads the full resource list via FakeDriveService.
bool LoadFullResourceList() {
FileError error = FILE_ERROR_FAILED;
file_system_->change_list_loader_for_testing()->LoadIfNeeded(
google_apis::test_util::CreateCopyResultCallback(&error));
task_runner_->RunUntilIdle();
return error == FILE_ERROR_OK;
}
// Gets resource entry by path synchronously.
std::unique_ptr<ResourceEntry> GetResourceEntrySync(
const base::FilePath& file_path) {
FileError error = FILE_ERROR_FAILED;
std::unique_ptr<ResourceEntry> entry;
file_system_->GetResourceEntry(
file_path,
google_apis::test_util::CreateCopyResultCallback(&error, &entry));
task_runner_->RunUntilIdle();
return entry;
}
// Gets directory info by path synchronously.
std::unique_ptr<ResourceEntryVector> ReadDirectorySync(
const base::FilePath& file_path) {
FileError error = FILE_ERROR_FAILED;
std::unique_ptr<ResourceEntryVector> entries(new ResourceEntryVector);
file_system_->ReadDirectory(
file_path,
base::Bind(&AccumulateReadDirectoryResult, entries.get()),
google_apis::test_util::CreateCopyResultCallback(&error));
task_runner_->RunUntilIdle();
if (error != FILE_ERROR_OK)
entries.reset();
return entries;
}
// Used to implement ReadDirectorySync().
static void AccumulateReadDirectoryResult(
ResourceEntryVector* out_entries,
std::unique_ptr<ResourceEntryVector> entries) {
ASSERT_TRUE(entries);
out_entries->insert(out_entries->end(), entries->begin(), entries->end());
}
// Returns true if an entry exists at |file_path|.
bool EntryExists(const base::FilePath& file_path) {
return GetResourceEntrySync(file_path) != nullptr;
}
// Flag for specifying the timestamp of the test filesystem cache.
enum SetUpTestFileSystemParam {
USE_OLD_TIMESTAMP,
USE_SERVER_TIMESTAMP,
};
// Sets up a filesystem with directories: drive/root, drive/root/Dir1,
// drive/root/Dir1/SubDir2 and files drive/root/File1, drive/root/Dir1/File2,
// drive/root/Dir1/SubDir2/File3. If |use_up_to_date_timestamp| is true, sets
// the start_page_token to that of FakeDriveService, indicating the cache is
// holding the latest file system info.
void SetUpTestFileSystem(SetUpTestFileSystemParam param) {
// Destroy the existing resource metadata to close DB.
resource_metadata_.reset();
const base::FilePath metadata_dir = temp_dir_.GetPath().AppendASCII("meta");
ASSERT_TRUE(base::CreateDirectory(metadata_dir));
std::unique_ptr<internal::ResourceMetadataStorage, DestroyHelper>
metadata_storage(new internal::ResourceMetadataStorage(
metadata_dir, task_runner_.get()),
DestroyHelper(task_runner_.get()));
const base::FilePath cache_dir = temp_dir_.GetPath().AppendASCII("files");
std::unique_ptr<internal::FileCache, DestroyHelper> cache(
new internal::FileCache(metadata_storage.get(), cache_dir,
task_runner_.get(),
fake_free_disk_space_getter_.get()),
DestroyHelper(task_runner_.get()));
std::unique_ptr<internal::ResourceMetadata, DestroyHelper>
resource_metadata(
new internal::ResourceMetadata(metadata_storage_.get(), cache.get(),
task_runner_.get()),
DestroyHelper(task_runner_.get()));
ASSERT_EQ(FILE_ERROR_OK, resource_metadata->Initialize());
const std::string start_page_token =
param == USE_SERVER_TIMESTAMP
? fake_drive_service_->start_page_token().start_page_token()
: "2";
ASSERT_EQ(FILE_ERROR_OK,
resource_metadata->SetStartPageToken(start_page_token));
// drive/root
ResourceEntry root;
ASSERT_EQ(FILE_ERROR_OK, resource_metadata->GetResourceEntryByPath(
util::GetDriveMyDriveRootPath(), &root));
root.set_resource_id(fake_drive_service_->GetRootResourceId());
ASSERT_EQ(FILE_ERROR_OK, resource_metadata->RefreshEntry(root));
std::string local_id;
// drive/root/File1
ResourceEntry file1;
file1.set_title("File1");
file1.set_resource_id("resource_id:File1");
file1.set_parent_local_id(root.local_id());
file1.mutable_file_specific_info()->set_md5("md5#1");
file1.mutable_file_info()->set_is_directory(false);
file1.mutable_file_info()->set_size(1048576);
ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(file1, &local_id));
// drive/root/Dir1
ResourceEntry dir1;
dir1.set_title("Dir1");
dir1.set_resource_id("resource_id:Dir1");
dir1.set_parent_local_id(root.local_id());
dir1.mutable_file_info()->set_is_directory(true);
ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(dir1, &local_id));
const std::string dir1_local_id = local_id;
// drive/root/Dir1/File2
ResourceEntry file2;
file2.set_title("File2");
file2.set_resource_id("resource_id:File2");
file2.set_parent_local_id(dir1_local_id);
file2.mutable_file_specific_info()->set_md5("md5#2");
file2.mutable_file_info()->set_is_directory(false);
file2.mutable_file_info()->set_size(555);
ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(file2, &local_id));
// drive/root/Dir1/SubDir2
ResourceEntry dir2;
dir2.set_title("SubDir2");
dir2.set_resource_id("resource_id:SubDir2");
dir2.set_parent_local_id(dir1_local_id);
dir2.mutable_file_info()->set_is_directory(true);
ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(dir2, &local_id));
const std::string dir2_local_id = local_id;
// drive/root/Dir1/SubDir2/File3
ResourceEntry file3;
file3.set_title("File3");
file3.set_resource_id("resource_id:File3");
file3.set_parent_local_id(dir2_local_id);
file3.mutable_file_specific_info()->set_md5("md5#2");
file3.mutable_file_info()->set_is_directory(false);
file3.mutable_file_info()->set_size(12345);
ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(file3, &local_id));
// drive/team_drive
ResourceEntry team_drive_root;
ASSERT_EQ(FILE_ERROR_OK,
resource_metadata->GetResourceEntryByPath(
util::GetDriveTeamDrivesRootPath(), &team_drive_root));
// drive/team_drive/team_drive_1
ResourceEntry td_dir;
td_dir.set_title("team_drive_1");
td_dir.set_resource_id("td_id_1");
td_dir.set_parent_local_id(team_drive_root.local_id());
td_dir.mutable_file_info()->set_is_directory(true);
ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(td_dir, &local_id));
// Recreate resource metadata.
SetUpResourceMetadataAndFileSystem();
}
// Sets up two team drives, team_drive_a and team_drive_b and creates the
// following:
// - Directories:
// -- team_drive_a/dir1
// -- team_drive_a/dir1/nested_1
// -- team_drive_b/dir2
//
// - Files:
// -- team_drive_a/dir1/file1
// -- team_drive_a/dir1/nested_1/file1
// -- team_drive_b/dir2/file2
bool SetupTeamDrives() {
fake_drive_service_->AddTeamDrive("td_id_1", "team_drive_1", "");
fake_drive_service_->AddTeamDrive("td_id_2", "team_drive_2", "");
fake_drive_service_->AddTeamDrive("td_id_2_2", "team_drive_2", "");
google_apis::DriveApiErrorCode error = google_apis::DRIVE_OTHER_ERROR;
std::unique_ptr<google_apis::FileResource> entry;
fake_drive_service_->AddNewFileWithResourceId(
"td_1_dir_1_resource_id", util::kDriveFolderMimeType, std::string(),
"td_id_1", "dir1",
false, // shared_with_me
google_apis::test_util::CreateCopyResultCallback(&error, &entry));
base::RunLoop().RunUntilIdle();
if (error != google_apis::HTTP_CREATED)
return false;
fake_drive_service_->AddNewFileWithResourceId(
"td_1_dir_nested_1_resource_id", util::kDriveFolderMimeType,
std::string(), "td_1_dir_1_resource_id", "nested_1",
false, // shared_with_me
google_apis::test_util::CreateCopyResultCallback(&error, &entry));
base::RunLoop().RunUntilIdle();
if (error != google_apis::HTTP_CREATED)
return false;
fake_drive_service_->AddNewFileWithResourceId(
"td_2_dir_2_resource_id", util::kDriveFolderMimeType, std::string(),
"td_id_2", "dir2",
false, // shared_with_me
google_apis::test_util::CreateCopyResultCallback(&error, &entry));
base::RunLoop().RunUntilIdle();
if (error != google_apis::HTTP_CREATED)
return false;
fake_drive_service_->AddNewFileWithResourceId(
"dir1_file_1_resource_id", "audio/mpeg", "dir 1 file 1 content.",
"td_1_dir_1_resource_id", "File 1.txt",
false, // shared_with_me
google_apis::test_util::CreateCopyResultCallback(&error, &entry));
base::RunLoop().RunUntilIdle();
if (error != google_apis::HTTP_CREATED)
return false;
fake_drive_service_->AddNewFileWithResourceId(
"nested_1_file_1_resource_id", "audio/mpeg", "nested 1 file 1 content.",
"td_1_dir_nested_1_resource_id", "Nested File 1.txt",
false, // shared_with_me
google_apis::test_util::CreateCopyResultCallback(&error, &entry));
base::RunLoop().RunUntilIdle();
if (error != google_apis::HTTP_CREATED)
return false;
fake_drive_service_->AddNewFileWithResourceId(
"dir_2_file_1_resource_id", "audio/mpeg", "dir2 file1 content.",
"td_2_dir_2_resource_id", "File 2.txt",
false, // shared_with_me
google_apis::test_util::CreateCopyResultCallback(&error, &entry));
base::RunLoop().RunUntilIdle();
if (error != google_apis::HTTP_CREATED)
return false;
fake_drive_service_->AddNewFileWithResourceId(
"td_2_2_dir_1_resource_id", util::kDriveFolderMimeType, std::string(),
"td_id_2_2", "dir1",
false, // shared_with_me
google_apis::test_util::CreateCopyResultCallback(&error, &entry));
base::RunLoop().RunUntilIdle();
if (error != google_apis::HTTP_CREATED)
return false;
return true;
}
scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
base::ScopedTempDir temp_dir_;
// We don't use TestingProfile::GetPrefs() in favor of having less
// dependencies to Profile in general.
std::unique_ptr<TestingPrefServiceSimple> pref_service_;
std::unique_ptr<EventLogger> logger_;
std::unique_ptr<FakeDriveService> fake_drive_service_;
std::unique_ptr<FakeFreeDiskSpaceGetter> fake_free_disk_space_getter_;
std::unique_ptr<JobScheduler> scheduler_;
std::unique_ptr<MockDirectoryChangeObserver> mock_directory_observer_;
std::unique_ptr<internal::ResourceMetadataStorage, DestroyHelper>
metadata_storage_;
std::unique_ptr<internal::FileCache, DestroyHelper> cache_;
std::unique_ptr<internal::ResourceMetadata, DestroyHelper> resource_metadata_;
std::unique_ptr<FileSystem> file_system_;
};
TEST_F(FileSystemTest, SearchByHashes) {
ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_SERVER_TIMESTAMP));
std::set<std::string> hashes;
FileError error;
std::vector<HashAndFilePath> results;
hashes.insert("md5#1");
file_system_->SearchByHashes(
hashes,
google_apis::test_util::CreateCopyResultCallback(&error, &results));
task_runner_->RunUntilIdle();
EXPECT_EQ(FILE_ERROR_OK, error);
ASSERT_EQ(1u, results.size());
EXPECT_EQ(FILE_PATH_LITERAL("drive/root/File1"), results[0].path.value());
hashes.clear();
hashes.insert("md5#2");
file_system_->SearchByHashes(
hashes,
google_apis::test_util::CreateCopyResultCallback(&error, &results));
task_runner_->RunUntilIdle();
EXPECT_EQ(FILE_ERROR_OK, error);
ASSERT_EQ(2u, results.size());
std::sort(results.begin(), results.end(), &CompareHashAndFilePath);
EXPECT_EQ(FILE_PATH_LITERAL("drive/root/Dir1/File2"),
results[0].path.value());
EXPECT_EQ(FILE_PATH_LITERAL("drive/root/Dir1/SubDir2/File3"),
results[1].path.value());
hashes.clear();
hashes.insert("md5#1");
hashes.insert("md5#2");
file_system_->SearchByHashes(
hashes,
google_apis::test_util::CreateCopyResultCallback(&error, &results));
task_runner_->RunUntilIdle();
EXPECT_EQ(FILE_ERROR_OK, error);
ASSERT_EQ(3u, results.size());
std::sort(results.begin(), results.end(), &CompareHashAndFilePath);
EXPECT_EQ(FILE_PATH_LITERAL("drive/root/File1"), results[0].path.value());
EXPECT_EQ(FILE_PATH_LITERAL("drive/root/Dir1/File2"),
results[1].path.value());
EXPECT_EQ(FILE_PATH_LITERAL("drive/root/Dir1/SubDir2/File3"),
results[2].path.value());
}
TEST_F(FileSystemTest, Copy) {
base::FilePath src_file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
base::FilePath dest_file_path(FILE_PATH_LITERAL("drive/root/Copied.txt"));
EXPECT_TRUE(GetResourceEntrySync(src_file_path));
EXPECT_FALSE(GetResourceEntrySync(dest_file_path));
FileError error = FILE_ERROR_FAILED;
file_system_->Copy(src_file_path,
dest_file_path,
false, // preserve_last_modified,
google_apis::test_util::CreateCopyResultCallback(&error));
task_runner_->RunUntilIdle();
EXPECT_EQ(FILE_ERROR_OK, error);
// Entry is added on the server.
std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(dest_file_path);
ASSERT_TRUE(entry);
google_apis::DriveApiErrorCode status = google_apis::DRIVE_OTHER_ERROR;
std::unique_ptr<google_apis::FileResource> server_entry;
fake_drive_service_->GetFileResource(
entry->resource_id(),
google_apis::test_util::CreateCopyResultCallback(&status, &server_entry));
task_runner_->RunUntilIdle();
EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
ASSERT_TRUE(server_entry);
EXPECT_EQ(entry->title(), server_entry->title());
EXPECT_FALSE(server_entry->IsDirectory());
}
TEST_F(FileSystemTest, Move) {
base::FilePath src_file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
base::FilePath dest_file_path(
FILE_PATH_LITERAL("drive/root/Directory 1/Moved.txt"));
EXPECT_TRUE(GetResourceEntrySync(src_file_path));
EXPECT_FALSE(GetResourceEntrySync(dest_file_path));
std::unique_ptr<ResourceEntry> parent =
GetResourceEntrySync(dest_file_path.DirName());
ASSERT_TRUE(parent);
FileError error = FILE_ERROR_FAILED;
file_system_->Move(src_file_path,
dest_file_path,
google_apis::test_util::CreateCopyResultCallback(&error));
task_runner_->RunUntilIdle();
EXPECT_EQ(FILE_ERROR_OK, error);
// Entry is moved on the server.
std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(dest_file_path);
ASSERT_TRUE(entry);
google_apis::DriveApiErrorCode status = google_apis::DRIVE_OTHER_ERROR;
std::unique_ptr<google_apis::FileResource> server_entry;
fake_drive_service_->GetFileResource(
entry->resource_id(),
google_apis::test_util::CreateCopyResultCallback(&status, &server_entry));
task_runner_->RunUntilIdle();
EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
ASSERT_TRUE(server_entry);
EXPECT_EQ(entry->title(), server_entry->title());
ASSERT_FALSE(server_entry->parents().empty());
EXPECT_EQ(parent->resource_id(), server_entry->parents()[0].file_id());
}
TEST_F(FileSystemTest, Remove) {
base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(file_path);
ASSERT_TRUE(entry);
FileError error = FILE_ERROR_FAILED;
file_system_->Remove(
file_path,
false, // is_resursive
google_apis::test_util::CreateCopyResultCallback(&error));
task_runner_->RunUntilIdle();
EXPECT_EQ(FILE_ERROR_OK, error);
// Entry is removed on the server.
google_apis::DriveApiErrorCode status = google_apis::DRIVE_OTHER_ERROR;
std::unique_ptr<google_apis::FileResource> server_entry;
fake_drive_service_->GetFileResource(
entry->resource_id(),
google_apis::test_util::CreateCopyResultCallback(&status, &server_entry));
task_runner_->RunUntilIdle();
EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
ASSERT_TRUE(server_entry);
EXPECT_TRUE(server_entry->labels().is_trashed());
}
TEST_F(FileSystemTest, CreateDirectory) {
base::FilePath directory_path(FILE_PATH_LITERAL("drive/root/New Directory"));
EXPECT_FALSE(GetResourceEntrySync(directory_path));
FileError error = FILE_ERROR_FAILED;
file_system_->CreateDirectory(
directory_path,
true, // is_exclusive
false, // is_recursive
google_apis::test_util::CreateCopyResultCallback(&error));
task_runner_->RunUntilIdle();
EXPECT_EQ(FILE_ERROR_OK, error);
// Directory is created on the server.
std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(directory_path);
ASSERT_TRUE(entry);
google_apis::DriveApiErrorCode status = google_apis::DRIVE_OTHER_ERROR;
std::unique_ptr<google_apis::FileResource> server_entry;
fake_drive_service_->GetFileResource(
entry->resource_id(),
google_apis::test_util::CreateCopyResultCallback(&status, &server_entry));
task_runner_->RunUntilIdle();
EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
ASSERT_TRUE(server_entry);
EXPECT_EQ(entry->title(), server_entry->title());
EXPECT_TRUE(server_entry->IsDirectory());
}
TEST_F(FileSystemTest, CreateFile) {
base::FilePath file_path(FILE_PATH_LITERAL("drive/root/New File.txt"));
EXPECT_FALSE(GetResourceEntrySync(file_path));
FileError error = FILE_ERROR_FAILED;
file_system_->CreateFile(
file_path,
true, // is_exclusive
"text/plain",
google_apis::test_util::CreateCopyResultCallback(&error));
task_runner_->RunUntilIdle();
EXPECT_EQ(FILE_ERROR_OK, error);
// File is created on the server.
std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(file_path);
ASSERT_TRUE(entry);
google_apis::DriveApiErrorCode status = google_apis::DRIVE_OTHER_ERROR;
std::unique_ptr<google_apis::FileResource> server_entry;
fake_drive_service_->GetFileResource(
entry->resource_id(),
google_apis::test_util::CreateCopyResultCallback(&status, &server_entry));
task_runner_->RunUntilIdle();
EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
ASSERT_TRUE(server_entry);
EXPECT_EQ(entry->title(), server_entry->title());
EXPECT_FALSE(server_entry->IsDirectory());
}
TEST_F(FileSystemTest, TouchFile) {
base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(file_path);
ASSERT_TRUE(entry);
base::Time last_accessed =
base::Time::FromInternalValue(entry->file_info().last_accessed()) +
base::TimeDelta::FromSeconds(1);
base::Time last_modified =
base::Time::FromInternalValue(entry->file_info().last_modified()) +
base::TimeDelta::FromSeconds(1);
FileError error = FILE_ERROR_FAILED;
file_system_->TouchFile(
file_path,
last_accessed,
last_modified,
google_apis::test_util::CreateCopyResultCallback(&error));
task_runner_->RunUntilIdle();
EXPECT_EQ(FILE_ERROR_OK, error);
// File is touched on the server.
google_apis::DriveApiErrorCode status = google_apis::DRIVE_OTHER_ERROR;
std::unique_ptr<google_apis::FileResource> server_entry;
fake_drive_service_->GetFileResource(
entry->resource_id(),
google_apis::test_util::CreateCopyResultCallback(&status, &server_entry));
task_runner_->RunUntilIdle();
EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
ASSERT_TRUE(server_entry);
EXPECT_EQ(last_accessed, server_entry->last_viewed_by_me_date());
EXPECT_EQ(last_modified, server_entry->modified_date());
EXPECT_EQ(last_modified, server_entry->modified_by_me_date());
}
TEST_F(FileSystemTest, TruncateFile) {
base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(file_path);
ASSERT_TRUE(entry);
const int64_t kLength = entry->file_info().size() + 100;
FileError error = FILE_ERROR_FAILED;
file_system_->TruncateFile(
file_path,
kLength,
google_apis::test_util::CreateCopyResultCallback(&error));
task_runner_->RunUntilIdle();
EXPECT_EQ(FILE_ERROR_OK, error);
// File is touched on the server.
google_apis::DriveApiErrorCode status = google_apis::DRIVE_OTHER_ERROR;
std::unique_ptr<google_apis::FileResource> server_entry;
fake_drive_service_->GetFileResource(
entry->resource_id(),
google_apis::test_util::CreateCopyResultCallback(&status, &server_entry));
task_runner_->RunUntilIdle();
EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
ASSERT_TRUE(server_entry);
EXPECT_EQ(kLength, server_entry->file_size());
}
TEST_F(FileSystemTest, DuplicatedAsyncInitialization) {
base::RunLoop loop;
int counter = 0;
file_system_->GetResourceEntry(
base::FilePath(FILE_PATH_LITERAL("drive/root")),
base::BindOnce(&AsyncInitializationCallback, &counter, 2,
loop.QuitClosure()));
file_system_->GetResourceEntry(
base::FilePath(FILE_PATH_LITERAL("drive/root")),
base::BindOnce(&AsyncInitializationCallback, &counter, 2,
loop.QuitClosure()));
loop.Run(); // Wait to get our result
EXPECT_EQ(2, counter);
EXPECT_EQ(1, fake_drive_service_->file_list_load_count());
}
TEST_F(FileSystemTest, GetGrandRootEntry) {
const base::FilePath kFilePath(FILE_PATH_LITERAL("drive"));
std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
ASSERT_TRUE(entry);
EXPECT_EQ(util::kDriveGrandRootLocalId, entry->local_id());
}
TEST_F(FileSystemTest, GetOtherDirEntry) {
const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/other"));
std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
ASSERT_TRUE(entry);
EXPECT_EQ(util::kDriveOtherDirLocalId, entry->local_id());
}
TEST_F(FileSystemTest, GetMyDriveRoot) {
const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root"));
std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
ASSERT_TRUE(entry);
EXPECT_EQ(fake_drive_service_->GetRootResourceId(), entry->resource_id());
// After "fast fetch" is done, full resource list is fetched.
EXPECT_EQ(1, fake_drive_service_->file_list_load_count());
}
TEST_F(FileSystemTest, GetTeamDriveRoot) {
const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/team_drives"));
std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
ASSERT_TRUE(entry);
EXPECT_EQ(util::kDriveTeamDrivesDirLocalId, entry->local_id());
// After "fast fetch" is done, full resource list is fetched.
EXPECT_EQ(1, fake_drive_service_->file_list_load_count());
}
TEST_F(FileSystemTest, GetExistingFile) {
// Simulate the situation that full feed fetching takes very long time,
// to test the recursive "fast fetch" feature is properly working.
fake_drive_service_->set_never_return_all_file_list(true);
const base::FilePath kFilePath(
FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt"));
std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
ASSERT_TRUE(entry);
EXPECT_EQ("subdirectory_file_1_id", entry->resource_id());
EXPECT_EQ(1, fake_drive_service_->about_resource_load_count());
EXPECT_EQ(2, fake_drive_service_->directory_load_count());
EXPECT_EQ(1, fake_drive_service_->blocked_file_list_load_count());
}
TEST_F(FileSystemTest, GetExistingDocument) {
const base::FilePath kFilePath(
FILE_PATH_LITERAL("drive/root/Document 1 excludeDir-test.gdoc"));
std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
ASSERT_TRUE(entry);
EXPECT_EQ("5_document_resource_id", entry->resource_id());
}
TEST_F(FileSystemTest, GetNonExistingFile) {
const base::FilePath kFilePath(
FILE_PATH_LITERAL("drive/root/nonexisting.file"));
std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
EXPECT_FALSE(entry);
}
TEST_F(FileSystemTest, GetInSubSubdir) {
const base::FilePath kFilePath(
FILE_PATH_LITERAL("drive/root/Directory 1/Sub Directory Folder/"
"Sub Sub Directory Folder"));
std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
ASSERT_TRUE(entry);
ASSERT_EQ("sub_sub_directory_folder_id", entry->resource_id());
}
TEST_F(FileSystemTest, GetOrphanFile) {
ASSERT_TRUE(LoadFullResourceList());
// Entry without parents are placed under "drive/other".
const base::FilePath kFilePath(
FILE_PATH_LITERAL("drive/other/Orphan File 1.txt"));
std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
ASSERT_TRUE(entry);
EXPECT_EQ("1_orphanfile_resource_id", entry->resource_id());
}
TEST_F(FileSystemTest, ReadDirectory_Root) {
// ReadDirectory() should kick off the resource list loading.
std::unique_ptr<ResourceEntryVector> entries(
ReadDirectorySync(base::FilePath::FromUTF8Unsafe("drive")));
// The root directory should be read correctly.
ASSERT_TRUE(entries);
ASSERT_EQ(5U, entries->size());
// The found three directories should be /drive/root, /drive/other,
// /drive/trash and /drive/team_drives.
std::set<base::FilePath> found;
for (size_t i = 0; i < entries->size(); ++i)
found.insert(base::FilePath::FromUTF8Unsafe((*entries)[i].title()));
EXPECT_EQ(5U, found.size());
EXPECT_EQ(1U, found.count(base::FilePath::FromUTF8Unsafe(
util::kDriveMyDriveRootDirName)));
EXPECT_EQ(1U, found.count(
base::FilePath::FromUTF8Unsafe(util::kDriveOtherDirName)));
EXPECT_EQ(1U, found.count(
base::FilePath::FromUTF8Unsafe(util::kDriveTrashDirName)));
EXPECT_EQ(1U, found.count(base::FilePath::FromUTF8Unsafe(
util::kDriveTeamDrivesDirName)));
EXPECT_EQ(1U, found.count(base::FilePath::FromUTF8Unsafe(
util::kDriveComputersDirName)));
}
TEST_F(FileSystemTest, ReadDirectory_TeamDrivesRoot) {
ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_SERVER_TIMESTAMP));
ASSERT_TRUE(SetupTeamDrives());
// The first load trigger the loading of team drives.
ReadDirectorySync(base::FilePath::FromUTF8Unsafe("."));
// After the first load team drive data should be available for reading.
std::unique_ptr<ResourceEntryVector> entries(
ReadDirectorySync(base::FilePath::FromUTF8Unsafe("drive/team_drives")));
// The root directory should be read correctly.
ASSERT_TRUE(entries);
ASSERT_EQ(3U, entries->size());
std::multiset<base::FilePath> found;
for (size_t i = 0; i < entries->size(); ++i) {
found.insert(base::FilePath::FromUTF8Unsafe((*entries)[i].title()));
}
EXPECT_EQ(3U, found.size());
EXPECT_EQ(1U, found.count(base::FilePath::FromUTF8Unsafe("team_drive_1")));
EXPECT_EQ(2U, found.count(base::FilePath::FromUTF8Unsafe("team_drive_2")));
EXPECT_EQ(1, fake_drive_service_->team_drive_list_load_count());
EXPECT_EQ(3, fake_drive_service_->file_list_load_count());
// We should be able to read from drive/team_drives/team_drive_1
std::unique_ptr<ResourceEntryVector> team_drive_1_entries(ReadDirectorySync(
base::FilePath::FromUTF8Unsafe("drive/team_drives/team_drive_1")));
ASSERT_TRUE(team_drive_1_entries);
ASSERT_EQ(1U, team_drive_1_entries->size());
std::set<base::FilePath> team_drive_1_found;
for (size_t i = 0; i < team_drive_1_entries->size(); ++i) {
team_drive_1_found.insert(
base::FilePath::FromUTF8Unsafe((*team_drive_1_entries)[i].title()));
}
EXPECT_EQ(1U, team_drive_1_found.size());
EXPECT_EQ(1U,
team_drive_1_found.count(base::FilePath::FromUTF8Unsafe("dir1")));
}
TEST_F(FileSystemTest, ReadDirectory_TeamDriveFolder) {
ASSERT_TRUE(SetupTeamDrives());
// The first load trigger the loading of team drives.
ReadDirectorySync(base::FilePath::FromUTF8Unsafe("."));
// Add a new entry to drive/team_drives/team_drive_1
// Create a file in the test directory.
std::unique_ptr<google_apis::FileResource> entry;
{
google_apis::DriveApiErrorCode error = google_apis::DRIVE_OTHER_ERROR;
fake_drive_service_->AddNewFile(
"text/plain", "(dummy data)", "td_id_1", "TestFile",
false, // shared_with_me
google_apis::test_util::CreateCopyResultCallback(&error, &entry));
base::RunLoop().RunUntilIdle();
ASSERT_EQ(google_apis::HTTP_CREATED, error);
}
// Notify the update to the file system.
file_system_->CheckForUpdates();
base::RunLoop().RunUntilIdle();
std::unique_ptr<ResourceEntryVector> entries(ReadDirectorySync(
base::FilePath::FromUTF8Unsafe("drive/team_drives/team_drive_1")));
// The root directory should be read correctly.
ASSERT_TRUE(entries);
std::set<base::FilePath> found;
for (size_t i = 0; i < entries->size(); ++i) {
found.insert(base::FilePath::FromUTF8Unsafe((*entries)[i].title()));
}
EXPECT_EQ(2U, found.size());
EXPECT_EQ(1U, found.count(base::FilePath::FromUTF8Unsafe("dir1")));
EXPECT_EQ(1U, found.count(base::FilePath::FromUTF8Unsafe("TestFile")));
}
TEST_F(FileSystemTest, AddTeamDriveInChangeList) {
ASSERT_TRUE(SetupTeamDrives());
// The first load trigger the loading of team drives.
ReadDirectorySync(base::FilePath::FromUTF8Unsafe("."));
// Add a new team drive to the fake file system.
{
fake_drive_service_->AddTeamDrive("td_id_3", "team_drive_3");
base::RunLoop().RunUntilIdle();
}
// Notify the update to the file system, which will add the team drive
file_system_->CheckForUpdates();
base::RunLoop().RunUntilIdle();
std::unique_ptr<ResourceEntryVector> entries(
ReadDirectorySync(base::FilePath::FromUTF8Unsafe("drive/team_drives/")));
// The root directory should be read correctly.
ASSERT_TRUE(entries);
std::multiset<base::FilePath> found;
for (size_t i = 0; i < entries->size(); ++i) {
found.insert(base::FilePath::FromUTF8Unsafe((*entries)[i].title()));
}
EXPECT_EQ(4U, found.size());
EXPECT_EQ(1U, found.count(base::FilePath::FromUTF8Unsafe("team_drive_3")));
// Add a new entry to drive/team_drives/team_drive_3
// Create a file in the test directory.
std::unique_ptr<google_apis::FileResource> entry;
{
google_apis::DriveApiErrorCode error = google_apis::DRIVE_OTHER_ERROR;
fake_drive_service_->AddNewFile(
"text/plain", "(dummy data)", "td_id_3", "TestFile",
false, // shared_with_me
google_apis::test_util::CreateCopyResultCallback(&error, &entry));
base::RunLoop().RunUntilIdle();
ASSERT_EQ(google_apis::HTTP_CREATED, error);
}
// Notify the update to the file system.
file_system_->CheckForUpdates();
base::RunLoop().RunUntilIdle();
entries = ReadDirectorySync(
base::FilePath::FromUTF8Unsafe("drive/team_drives/team_drive_3"));
// The root directory should be read correctly.
ASSERT_TRUE(entries);
found.clear();
for (size_t i = 0; i < entries->size(); ++i) {
found.insert(base::FilePath::FromUTF8Unsafe((*entries)[i].title()));
}
EXPECT_EQ(1U, found.size());
EXPECT_EQ(1U, found.count(base::FilePath::FromUTF8Unsafe("TestFile")));
}
TEST_F(FileSystemTest, ReadDirectory_NonRootDirectory) {
// ReadDirectory() should kick off the resource list loading.
std::unique_ptr<ResourceEntryVector> entries(ReadDirectorySync(
base::FilePath::FromUTF8Unsafe("drive/root/Directory 1")));
// The non root directory should also be read correctly.
// There was a bug (crbug.com/181487), which broke this behavior.
// Make sure this is fixed.
ASSERT_TRUE(entries);
EXPECT_EQ(3U, entries->size());
}
TEST_F(FileSystemTest, LoadFileSystemFromUpToDateCache) {
ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_SERVER_TIMESTAMP));
// Kicks loading of cached file system and query for server update.
EXPECT_TRUE(ReadDirectorySync(util::GetDriveMyDriveRootPath()));
// SetUpTestFileSystem and FakeDriveService have the same
// start_page_token (i.e. the local metadata is up to date), so no request for
// new resource list (i.e., call to GetResourceList) should happen.
EXPECT_EQ(0, fake_drive_service_->file_list_load_count());
// Since the file system has verified that it holds the latest snapshot,
// it should change its state to "loaded", which admits periodic refresh.
// To test it, call CheckForUpdates and verify it does try to check updates.
const int start_page_toke_load_count_before =
fake_drive_service_->start_page_token_load_count();
file_system_->CheckForUpdates();
task_runner_->RunUntilIdle();
EXPECT_LT(start_page_toke_load_count_before,
fake_drive_service_->start_page_token_load_count());
}
TEST_F(FileSystemTest, LoadFileSystemFromCacheWhileOffline) {
ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_OLD_TIMESTAMP));
// Make GetResourceList fail for simulating offline situation. This will
// leave the file system "loaded from cache, but not synced with server"
// state.
fake_drive_service_->set_offline(true);
// Load the root.
EXPECT_TRUE(ReadDirectorySync(util::GetDriveGrandRootPath()));
// Loading of start page token should not happen as it's offline.
EXPECT_EQ(0, fake_drive_service_->start_page_token_load_count());
// Load "My Drive".
EXPECT_TRUE(ReadDirectorySync(util::GetDriveMyDriveRootPath()));
EXPECT_EQ(0, fake_drive_service_->start_page_token_load_count());
// Tests that cached data can be loaded even if the server is not reachable.
EXPECT_TRUE(EntryExists(base::FilePath(
FILE_PATH_LITERAL("drive/root/File1"))));
EXPECT_TRUE(EntryExists(base::FilePath(
FILE_PATH_LITERAL("drive/root/Dir1"))));
EXPECT_TRUE(EntryExists(base::FilePath(
FILE_PATH_LITERAL("drive/root/Dir1/File2"))));
EXPECT_TRUE(EntryExists(base::FilePath(
FILE_PATH_LITERAL("drive/root/Dir1/SubDir2"))));
EXPECT_TRUE(EntryExists(base::FilePath(
FILE_PATH_LITERAL("drive/root/Dir1/SubDir2/File3"))));
// Since the file system has at least succeeded to load cached snapshot,
// the file system should be able to start periodic refresh.
// To test it, call CheckForUpdates and verify it does try to check
// updates, which will cause directory changes.
fake_drive_service_->set_offline(false);
file_system_->CheckForUpdates();
task_runner_->RunUntilIdle();
EXPECT_EQ(1, fake_drive_service_->start_page_token_load_count());
EXPECT_EQ(1, fake_drive_service_->change_list_load_count());
ASSERT_LE(0u, mock_directory_observer_->changed_directories().size());
ASSERT_LE(1u, mock_directory_observer_->changed_files().size());
}
TEST_F(FileSystemTest, ReadDirectoryWhileRefreshing) {
// Use old timestamp so the fast fetch will be performed.
ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_OLD_TIMESTAMP));
// The list of resources in "drive/root/Dir1" should be fetched.
EXPECT_TRUE(ReadDirectorySync(base::FilePath(
FILE_PATH_LITERAL("drive/root/Dir1"))));
EXPECT_EQ(1, fake_drive_service_->directory_load_count());
ASSERT_LE(1u, mock_directory_observer_->changed_directories().size());
}
TEST_F(FileSystemTest, GetResourceEntryNonExistentWhileRefreshing) {
// Use old timestamp so the fast fetch will be performed.
ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_OLD_TIMESTAMP));
// If an entry is not found, parent directory's resource list is fetched.
EXPECT_FALSE(GetResourceEntrySync(base::FilePath(
FILE_PATH_LITERAL("drive/root/Dir1/NonExistentFile"))));
EXPECT_EQ(1, fake_drive_service_->directory_load_count());
ASSERT_LE(1u, mock_directory_observer_->changed_directories().size());
}
TEST_F(FileSystemTest, CreateDirectoryByImplicitLoad) {
// Intentionally *not* calling LoadFullResourceList(), for testing that
// CreateDirectory ensures the resource list is loaded before it runs.
base::FilePath existing_directory(
FILE_PATH_LITERAL("drive/root/Directory 1"));
FileError error = FILE_ERROR_FAILED;
file_system_->CreateDirectory(
existing_directory,
true, // is_exclusive
false, // is_recursive
google_apis::test_util::CreateCopyResultCallback(&error));
task_runner_->RunUntilIdle();
// It should fail because is_exclusive is set to true.
EXPECT_EQ(FILE_ERROR_EXISTS, error);
}
TEST_F(FileSystemTest, CreateDirectoryRecursively) {
// Intentionally *not* calling LoadFullResourceList(), for testing that
// CreateDirectory ensures the resource list is loaded before it runs.
base::FilePath new_directory(
FILE_PATH_LITERAL("drive/root/Directory 1/a/b/c/d"));
FileError error = FILE_ERROR_FAILED;
file_system_->CreateDirectory(
new_directory,
true, // is_exclusive
true, // is_recursive
google_apis::test_util::CreateCopyResultCallback(&error));
task_runner_->RunUntilIdle();
EXPECT_EQ(FILE_ERROR_OK, error);
std::unique_ptr<ResourceEntry> entry(GetResourceEntrySync(new_directory));
ASSERT_TRUE(entry);
EXPECT_TRUE(entry->file_info().is_directory());
}
TEST_F(FileSystemTest, ReadDirectoryAfterUpdateWhileLoading) {
// Simulate the situation that full feed fetching takes very long time,
// to test the recursive "fast fetch" feature is properly working.
fake_drive_service_->set_never_return_all_file_list(true);
// On the fake server, create the test directory.
std::unique_ptr<google_apis::FileResource> parent;
{
google_apis::DriveApiErrorCode error = google_apis::DRIVE_OTHER_ERROR;
fake_drive_service_->AddNewDirectory(
fake_drive_service_->GetRootResourceId(), "UpdateWhileLoadingTestDir",
AddNewDirectoryOptions(),
google_apis::test_util::CreateCopyResultCallback(&error, &parent));
base::RunLoop().RunUntilIdle();
ASSERT_EQ(google_apis::HTTP_CREATED, error);
}
// Fetch the directory. Currently it is empty.
std::unique_ptr<ResourceEntryVector> before =
ReadDirectorySync(base::FilePath(
FILE_PATH_LITERAL("drive/root/UpdateWhileLoadingTestDir")));
ASSERT_TRUE(before);
EXPECT_EQ(0u, before->size());
// Create a file in the test directory.
std::unique_ptr<google_apis::FileResource> entry;
{
google_apis::DriveApiErrorCode error = google_apis::DRIVE_OTHER_ERROR;
fake_drive_service_->AddNewFile(
"text/plain",
"(dummy data)",
parent->file_id(),
"TestFile",
false, // shared_with_me
google_apis::test_util::CreateCopyResultCallback(&error, &entry));
base::RunLoop().RunUntilIdle();
ASSERT_EQ(google_apis::HTTP_CREATED, error);
}
// Notify the update to the file system.
file_system_->CheckForUpdates();
// Fast forward the clock, so that a new read of the directory is started.
task_runner_->FastForwardBy(base::TimeDelta::FromMinutes(1));
// Read the directory once again. Although the full feed fetching is not yet
// finished, the "fast fetch" of the directory works and the refreshed content
// is returned.
std::unique_ptr<ResourceEntryVector> after = ReadDirectorySync(base::FilePath(
FILE_PATH_LITERAL("drive/root/UpdateWhileLoadingTestDir")));
ASSERT_TRUE(after);
EXPECT_EQ(1u, after->size());
}
TEST_F(FileSystemTest, PinAndUnpin) {
ASSERT_TRUE(LoadFullResourceList());
base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
// Get the file info.
std::unique_ptr<ResourceEntry> entry(GetResourceEntrySync(file_path));
ASSERT_TRUE(entry);
// Pin the file.
FileError error = FILE_ERROR_FAILED;
file_system_->Pin(file_path,
google_apis::test_util::CreateCopyResultCallback(&error));
task_runner_->RunUntilIdle();
EXPECT_EQ(FILE_ERROR_OK, error);
entry = GetResourceEntrySync(file_path);
ASSERT_TRUE(entry);
EXPECT_TRUE(entry->file_specific_info().cache_state().is_pinned());
EXPECT_TRUE(entry->file_specific_info().cache_state().is_present());
// Unpin the file.
error = FILE_ERROR_FAILED;
file_system_->Unpin(file_path,
google_apis::test_util::CreateCopyResultCallback(&error));
task_runner_->RunUntilIdle();
EXPECT_EQ(FILE_ERROR_OK, error);
entry = GetResourceEntrySync(file_path);
ASSERT_TRUE(entry);
EXPECT_FALSE(entry->file_specific_info().cache_state().is_pinned());
// Pinned file gets synced and it results in entry state changes.
ASSERT_EQ(0u, mock_directory_observer_->changed_directories().size());
ASSERT_EQ(1u, mock_directory_observer_->changed_files().size());
EXPECT_EQ(1u,
mock_directory_observer_->changed_files().CountDirectory(
base::FilePath(FILE_PATH_LITERAL("drive/root"))));
}
TEST_F(FileSystemTest, PinAndUnpin_NotSynced) {
ASSERT_TRUE(LoadFullResourceList());
base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
// Get the file info.
std::unique_ptr<ResourceEntry> entry(GetResourceEntrySync(file_path));
ASSERT_TRUE(entry);
// Unpin the file just after pinning. File fetch should be cancelled.
FileError error_pin = FILE_ERROR_FAILED;
file_system_->Pin(
file_path,
google_apis::test_util::CreateCopyResultCallback(&error_pin));
FileError error_unpin = FILE_ERROR_FAILED;
file_system_->Unpin(
file_path,
google_apis::test_util::CreateCopyResultCallback(&error_unpin));
task_runner_->RunUntilIdle();
EXPECT_EQ(FILE_ERROR_OK, error_pin);
EXPECT_EQ(FILE_ERROR_OK, error_unpin);
// No cache file available because the sync was cancelled by Unpin().
entry = GetResourceEntrySync(file_path);
ASSERT_TRUE(entry);
EXPECT_FALSE(entry->file_specific_info().cache_state().is_present());
}
TEST_F(FileSystemTest, GetAvailableSpace) {
FileError error = FILE_ERROR_OK;
int64_t bytes_total;
int64_t bytes_used;
file_system_->GetAvailableSpace(
google_apis::test_util::CreateCopyResultCallback(
&error, &bytes_total, &bytes_used));
task_runner_->RunUntilIdle();
EXPECT_EQ(6789012345LL, bytes_used);
EXPECT_EQ(9876543210LL, bytes_total);
}
TEST_F(FileSystemTest, MarkCacheFileAsMountedAndUnmounted) {
ASSERT_TRUE(LoadFullResourceList());
base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
// Make the file cached.
FileError error = FILE_ERROR_FAILED;
base::FilePath file_path;
std::unique_ptr<ResourceEntry> entry;
file_system_->GetFile(
file_in_root,
google_apis::test_util::CreateCopyResultCallback(
&error, &file_path, &entry));
task_runner_->RunUntilIdle();
EXPECT_EQ(FILE_ERROR_OK, error);
// Test for mounting.
error = FILE_ERROR_FAILED;
file_path.clear();
file_system_->MarkCacheFileAsMounted(
file_in_root,
google_apis::test_util::CreateCopyResultCallback(&error, &file_path));
task_runner_->RunUntilIdle();
EXPECT_EQ(FILE_ERROR_OK, error);
error = FILE_ERROR_FAILED;
bool is_marked_as_mounted = false;
file_system_->IsCacheFileMarkedAsMounted(
file_in_root, google_apis::test_util::CreateCopyResultCallback(
&error, &is_marked_as_mounted));
task_runner_->RunUntilIdle();
EXPECT_EQ(FILE_ERROR_OK, error);
EXPECT_TRUE(is_marked_as_mounted);
// Cannot remove a cache entry while it's being mounted.
EXPECT_EQ(FILE_ERROR_IN_USE, cache_->Remove(entry->local_id()));
// Test for unmounting.
error = FILE_ERROR_FAILED;
file_system_->MarkCacheFileAsUnmounted(
file_path,
google_apis::test_util::CreateCopyResultCallback(&error));
task_runner_->RunUntilIdle();
EXPECT_EQ(FILE_ERROR_OK, error);
error = FILE_ERROR_FAILED;
is_marked_as_mounted = true;
file_system_->IsCacheFileMarkedAsMounted(
file_in_root, google_apis::test_util::CreateCopyResultCallback(
&error, &is_marked_as_mounted));
task_runner_->RunUntilIdle();
EXPECT_EQ(FILE_ERROR_OK, error);
EXPECT_FALSE(is_marked_as_mounted);
// Now able to remove the cache entry.
EXPECT_EQ(FILE_ERROR_OK, cache_->Remove(entry->local_id()));
}
TEST_F(FileSystemTest, FreeDiskSpaceIfNeededFor) {
ASSERT_TRUE(LoadFullResourceList());
base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
// Make the file cached.
FileError error = FILE_ERROR_FAILED;
base::FilePath file_path;
std::unique_ptr<ResourceEntry> entry;
file_system_->GetFile(file_in_root,
google_apis::test_util::CreateCopyResultCallback(
&error, &file_path, &entry));
task_runner_->RunUntilIdle();
EXPECT_EQ(FILE_ERROR_OK, error);
ASSERT_TRUE(entry);
EXPECT_TRUE(entry->file_specific_info().cache_state().is_present());
bool available;
file_system_->FreeDiskSpaceIfNeededFor(
512LL << 40,
google_apis::test_util::CreateCopyResultCallback(&available));
task_runner_->RunUntilIdle();
ASSERT_FALSE(available);
entry = GetResourceEntrySync(file_in_root);
ASSERT_TRUE(entry);
EXPECT_FALSE(entry->file_specific_info().cache_state().is_present());
}
TEST_F(FileSystemTest, DebugMetadata) {
ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_SERVER_TIMESTAMP));
ASSERT_TRUE(SetupTeamDrives());
// The first load will trigger the loading of team drives.
ReadDirectorySync(base::FilePath::FromUTF8Unsafe("."));
base::Time now = base::Time::Now();
file_system_->CheckForUpdates();
base::RunLoop().RunUntilIdle();
FileSystemMetadata default_corpus_metadata;
std::map<std::string, FileSystemMetadata> team_drive_metadata;
file_system_->GetMetadata(google_apis::test_util::CreateCopyResultCallback(
&default_corpus_metadata, &team_drive_metadata));
base::RunLoop().RunUntilIdle();
EXPECT_LE(now, default_corpus_metadata.last_update_check_time);
EXPECT_FALSE(default_corpus_metadata.refreshing);
EXPECT_EQ(FILE_ERROR_OK, default_corpus_metadata.last_update_check_error);
EXPECT_EQ("654340", default_corpus_metadata.start_page_token);
EXPECT_EQ(3UL, team_drive_metadata.size());
EXPECT_FALSE(team_drive_metadata["td_id_1"].refreshing);
EXPECT_EQ(util::GetDriveTeamDrivesRootPath().Append("team_drive_1").value(),
team_drive_metadata["td_id_1"].path);
EXPECT_LE(now, team_drive_metadata["td_id_1"].last_update_check_time);
EXPECT_EQ("654345", team_drive_metadata["td_id_1"].start_page_token);
EXPECT_EQ(FILE_ERROR_OK,
team_drive_metadata["td_id_1"].last_update_check_error);
EXPECT_FALSE(team_drive_metadata["td_id_2"].refreshing);
EXPECT_EQ(util::GetDriveTeamDrivesRootPath().Append("team_drive_2").value(),
team_drive_metadata["td_id_2"].path);
EXPECT_LE(now, team_drive_metadata["td_id_2"].last_update_check_time);
EXPECT_EQ("654346", team_drive_metadata["td_id_2"].start_page_token);
EXPECT_EQ(FILE_ERROR_OK,
team_drive_metadata["td_id_2"].last_update_check_error);
EXPECT_FALSE(team_drive_metadata["td_id_2_2"].refreshing);
EXPECT_EQ(util::GetDriveTeamDrivesRootPath().Append("team_drive_2").value(),
team_drive_metadata["td_id_2_2"].path);
EXPECT_LE(now, team_drive_metadata["td_id_2_2"].last_update_check_time);
EXPECT_EQ("654347", team_drive_metadata["td_id_2_2"].start_page_token);
EXPECT_EQ(FILE_ERROR_OK,
team_drive_metadata["td_id_2_2"].last_update_check_error);
}
TEST_F(FileSystemTest, TeamDrivesChangesObserved) {
ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_SERVER_TIMESTAMP));
ASSERT_TRUE(SetupTeamDrives());
// The first load will trigger the loading of team drives.
ReadDirectorySync(base::FilePath::FromUTF8Unsafe("."));
// This is the initial set of team drives.
EXPECT_EQ(3UL, mock_directory_observer_->added_team_drive_ids().size());
EXPECT_TRUE(mock_directory_observer_->removed_team_drive_ids().empty());
fake_drive_service_->AddTeamDrive("td_id_3", "team_drive_3");
// TODO(slangley): Add support for removing a team drive in fake file service.
base::RunLoop().RunUntilIdle();
// Notify the update to the file system, which will add the team drive
file_system_->CheckForUpdates();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1UL, mock_directory_observer_->added_team_drive_ids().size());
EXPECT_EQ(1UL,
mock_directory_observer_->added_team_drive_ids().count("td_id_3"));
EXPECT_TRUE(mock_directory_observer_->removed_team_drive_ids().empty());
}
TEST_F(FileSystemTest, CheckUpdatesWithIds) {
ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_SERVER_TIMESTAMP));
ASSERT_TRUE(SetupTeamDrives());
// The first load will trigger the loading of team drives.
ReadDirectorySync(base::FilePath::FromUTF8Unsafe("."));
// Check a non existent team drive id, no other sources should be updated.
file_system_->CheckForUpdates({"non_existant_team_drive_id"});
base::RunLoop().RunUntilIdle();
FileSystemMetadata default_corpus_metadata;
std::map<std::string, FileSystemMetadata> team_drive_metadata;
file_system_->GetMetadata(google_apis::test_util::CreateCopyResultCallback(
&default_corpus_metadata, &team_drive_metadata));
base::RunLoop().RunUntilIdle();
const base::Time default_time;
EXPECT_EQ(default_time, default_corpus_metadata.last_update_check_time);
EXPECT_EQ(default_time,
team_drive_metadata["td_id_1"].last_update_check_time);
EXPECT_EQ(default_time,
team_drive_metadata["td_id_2"].last_update_check_time);
EXPECT_EQ(default_time,
team_drive_metadata["td_id_2_2"].last_update_check_time);
base::Time now = base::Time::Now();
// Update just the default corpus.
file_system_->CheckForUpdates({""});
base::RunLoop().RunUntilIdle();
file_system_->GetMetadata(google_apis::test_util::CreateCopyResultCallback(
&default_corpus_metadata, &team_drive_metadata));
base::RunLoop().RunUntilIdle();
EXPECT_LE(now, default_corpus_metadata.last_update_check_time);
EXPECT_EQ(default_time,
team_drive_metadata["td_id_1"].last_update_check_time);
EXPECT_EQ(default_time,
team_drive_metadata["td_id_2"].last_update_check_time);
EXPECT_EQ(default_time,
team_drive_metadata["td_id_2_2"].last_update_check_time);
// Update two team drives.
now = base::Time::Now();
file_system_->CheckForUpdates({"td_id_1", "td_id_2"});
base::RunLoop().RunUntilIdle();
file_system_->GetMetadata(google_apis::test_util::CreateCopyResultCallback(
&default_corpus_metadata, &team_drive_metadata));
base::RunLoop().RunUntilIdle();
EXPECT_GE(now, default_corpus_metadata.last_update_check_time);
EXPECT_LE(now, team_drive_metadata["td_id_1"].last_update_check_time);
EXPECT_LE(now, team_drive_metadata["td_id_2"].last_update_check_time);
EXPECT_EQ(default_time,
team_drive_metadata["td_id_2_2"].last_update_check_time);
// Update everything.
now = base::Time::Now();
file_system_->CheckForUpdates({"", "td_id_1", "td_id_2", "td_id_2_2"});
base::RunLoop().RunUntilIdle();
file_system_->GetMetadata(google_apis::test_util::CreateCopyResultCallback(
&default_corpus_metadata, &team_drive_metadata));
base::RunLoop().RunUntilIdle();
EXPECT_LE(now, default_corpus_metadata.last_update_check_time);
EXPECT_LE(now, team_drive_metadata["td_id_1"].last_update_check_time);
EXPECT_LE(now, team_drive_metadata["td_id_2"].last_update_check_time);
EXPECT_LE(now, team_drive_metadata["td_id_2_2"].last_update_check_time);
}
TEST_F(FileSystemTest, RemoveNonExistingTeamDrive) {
ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_SERVER_TIMESTAMP));
ASSERT_TRUE(SetupTeamDrives());
// The first load will trigger the loading of team drives.
ReadDirectorySync(base::FilePath::FromUTF8Unsafe("."));
// Create a file change with a delete team drive, ensure file_system_ does not
// crash.
const base::FilePath path =
util::GetDriveTeamDrivesRootPath().Append("team_drive_2");
std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(path);
ASSERT_TRUE(entry);
drive::FileChange change;
change.Update(path, *entry, FileChange::CHANGE_TYPE_DELETE);
// First time should be removed.
file_system_->OnTeamDrivesChanged(change);
std::set<std::string> expected_changes = {"td_id_2"};
EXPECT_EQ(expected_changes,
mock_directory_observer_->removed_team_drive_ids());
// Second time should be no changes, and no crash.
file_system_->OnTeamDrivesChanged(change);
expected_changes = {};
EXPECT_EQ(expected_changes,
mock_directory_observer_->removed_team_drive_ids());
}
} // namespace drive