| Index: chrome/browser/sync_file_system/drive_backend/conflict_resolver_unittest.cc
|
| diff --git a/chrome/browser/sync_file_system/drive_backend/local_to_remote_syncer_unittest.cc b/chrome/browser/sync_file_system/drive_backend/conflict_resolver_unittest.cc
|
| similarity index 52%
|
| copy from chrome/browser/sync_file_system/drive_backend/local_to_remote_syncer_unittest.cc
|
| copy to chrome/browser/sync_file_system/drive_backend/conflict_resolver_unittest.cc
|
| index 962394d00a5686a341ea418f3c3e6fb0c1e9c307..d398fa92df25de4c9df49dfdbf50abb2e0b9794e 100644
|
| --- a/chrome/browser/sync_file_system/drive_backend/local_to_remote_syncer_unittest.cc
|
| +++ b/chrome/browser/sync_file_system/drive_backend/conflict_resolver_unittest.cc
|
| @@ -2,12 +2,11 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| -#include "chrome/browser/sync_file_system/drive_backend/local_to_remote_syncer.h"
|
| +#include "chrome/browser/sync_file_system/drive_backend/conflict_resolver.h"
|
|
|
| #include "base/bind.h"
|
| #include "base/callback.h"
|
| #include "base/files/scoped_temp_dir.h"
|
| -#include "base/logging.h"
|
| #include "base/run_loop.h"
|
| #include "chrome/browser/drive/drive_uploader.h"
|
| #include "chrome/browser/drive/fake_drive_service.h"
|
| @@ -16,6 +15,7 @@
|
| #include "chrome/browser/sync_file_system/drive_backend/drive_backend_test_util.h"
|
| #include "chrome/browser/sync_file_system/drive_backend/list_changes_task.h"
|
| #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
|
| +#include "chrome/browser/sync_file_system/drive_backend/remote_to_local_syncer.h"
|
| #include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h"
|
| #include "chrome/browser/sync_file_system/drive_backend/sync_engine_initializer.h"
|
| #include "chrome/browser/sync_file_system/drive_backend_v1/fake_drive_service_helper.h"
|
| @@ -29,22 +29,12 @@
|
| namespace sync_file_system {
|
| namespace drive_backend {
|
|
|
| -namespace {
|
| -
|
| -fileapi::FileSystemURL URL(const GURL& origin,
|
| - const std::string& path) {
|
| - return CreateSyncableFileSystemURL(
|
| - origin, base::FilePath::FromUTF8Unsafe(path));
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -class LocalToRemoteSyncerTest : public testing::Test,
|
| - public SyncEngineContext {
|
| +class ConflictResolverTest : public testing::Test,
|
| + public SyncEngineContext {
|
| public:
|
| - LocalToRemoteSyncerTest()
|
| + ConflictResolverTest()
|
| : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {}
|
| - virtual ~LocalToRemoteSyncerTest() {}
|
| + virtual ~ConflictResolverTest() {}
|
|
|
| virtual void SetUp() OVERRIDE {
|
| ASSERT_TRUE(database_dir_.CreateUniqueTempDir());
|
| @@ -94,6 +84,14 @@ class LocalToRemoteSyncerTest : public testing::Test,
|
| EXPECT_EQ(SYNC_STATUS_OK, status);
|
| }
|
|
|
| + SyncStatusCode RunRemoteSyncer() {
|
| + SyncStatusCode status = SYNC_STATUS_UNKNOWN;
|
| + scoped_ptr<RemoteToLocalSyncer> syncer(new RemoteToLocalSyncer(this));
|
| + syncer->Run(CreateResultReceiver(&status));
|
| + base::RunLoop().RunUntilIdle();
|
| + return status;
|
| + }
|
| +
|
| virtual drive::DriveServiceInterface* GetDriveService() OVERRIDE {
|
| return fake_drive_service_.get();
|
| }
|
| @@ -142,17 +140,28 @@ class LocalToRemoteSyncerTest : public testing::Test,
|
| return file_id;
|
| }
|
|
|
| - SyncStatusCode RunSyncer(FileChange file_change,
|
| - const fileapi::FileSystemURL& url) {
|
| + SyncStatusCode RunSyncer() {
|
| SyncStatusCode status = SYNC_STATUS_UNKNOWN;
|
| - base::FilePath local_path = base::FilePath::FromUTF8Unsafe("dummy");
|
| - scoped_ptr<LocalToRemoteSyncer> syncer(new LocalToRemoteSyncer(
|
| - this, file_change, local_path, url));
|
| + scoped_ptr<RemoteToLocalSyncer> syncer(new RemoteToLocalSyncer(this));
|
| syncer->Run(CreateResultReceiver(&status));
|
| base::RunLoop().RunUntilIdle();
|
| return status;
|
| }
|
|
|
| + void RunSyncerUntilIdle() {
|
| + SyncStatusCode status = SYNC_STATUS_UNKNOWN;
|
| + while (status != SYNC_STATUS_NO_CHANGE_TO_SYNC)
|
| + status = RunSyncer();
|
| + }
|
| +
|
| + SyncStatusCode RunConflictResolver() {
|
| + SyncStatusCode status = SYNC_STATUS_UNKNOWN;
|
| + ConflictResolver resolver(this);
|
| + resolver.Run(CreateResultReceiver(&status));
|
| + base::RunLoop().RunUntilIdle();
|
| + return status;
|
| + }
|
| +
|
| SyncStatusCode ListChanges() {
|
| ListChangesTask list_changes(this);
|
| SyncStatusCode status = SYNC_STATUS_UNKNOWN;
|
| @@ -171,35 +180,19 @@ class LocalToRemoteSyncerTest : public testing::Test,
|
| return entries.Pass();
|
| }
|
|
|
| - std::string GetFileIDForParentAndTitle(const std::string& parent_folder_id,
|
| - const std::string& title) {
|
| - ScopedVector<google_apis::ResourceEntry> entries =
|
| - GetResourceEntriesForParentAndTitle(parent_folder_id, title);
|
| - if (entries.size() != 1)
|
| - return std::string();
|
| - return entries[0]->resource_id();
|
| - }
|
| -
|
| - void VerifyTitleUniqueness(const std::string& parent_folder_id,
|
| - const std::string& title,
|
| - google_apis::DriveEntryKind kind) {
|
| + void VerifyConflictResolution(const std::string& parent_folder_id,
|
| + const std::string& title,
|
| + const std::string& primary_file_id,
|
| + google_apis::DriveEntryKind kind) {
|
| ScopedVector<google_apis::ResourceEntry> entries;
|
| EXPECT_EQ(google_apis::HTTP_SUCCESS,
|
| fake_drive_helper_->SearchByTitle(
|
| parent_folder_id, title, &entries));
|
| ASSERT_EQ(1u, entries.size());
|
| + EXPECT_EQ(primary_file_id, entries[0]->resource_id());
|
| EXPECT_EQ(kind, entries[0]->kind());
|
| }
|
|
|
| - void VerifyFileDeletion(const std::string& parent_folder_id,
|
| - const std::string& title) {
|
| - ScopedVector<google_apis::ResourceEntry> entries;
|
| - EXPECT_EQ(google_apis::HTTP_SUCCESS,
|
| - fake_drive_helper_->SearchByTitle(
|
| - parent_folder_id, title, &entries));
|
| - EXPECT_TRUE(entries.empty());
|
| - }
|
| -
|
| private:
|
| content::TestBrowserThreadBundle thread_bundle_;
|
| base::ScopedTempDir database_dir_;
|
| @@ -210,169 +203,99 @@ class LocalToRemoteSyncerTest : public testing::Test,
|
| scoped_ptr<MetadataDatabase> metadata_database_;
|
| scoped_ptr<FakeRemoteChangeProcessor> fake_remote_change_processor_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(LocalToRemoteSyncerTest);
|
| + DISALLOW_COPY_AND_ASSIGN(ConflictResolverTest);
|
| };
|
|
|
| -TEST_F(LocalToRemoteSyncerTest, CreateFile) {
|
| - const GURL kOrigin("chrome-extension://example");
|
| - const std::string sync_root = CreateSyncRoot();
|
| - const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
|
| - InitializeMetadataDatabase();
|
| - RegisterApp(kOrigin.host(), app_root);
|
| -
|
| - EXPECT_EQ(SYNC_STATUS_OK, RunSyncer(
|
| - FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
|
| - SYNC_FILE_TYPE_FILE),
|
| - URL(kOrigin, "file1")));
|
| - EXPECT_EQ(SYNC_STATUS_OK, RunSyncer(
|
| - FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
|
| - SYNC_FILE_TYPE_DIRECTORY),
|
| - URL(kOrigin, "folder")));
|
| - EXPECT_EQ(SYNC_STATUS_OK, RunSyncer(
|
| - FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
|
| - SYNC_FILE_TYPE_FILE),
|
| - URL(kOrigin, "folder/file2")));
|
| -
|
| - std::string folder_id = GetFileIDForParentAndTitle(app_root, "folder");
|
| - ASSERT_FALSE(folder_id.empty());
|
| -
|
| - VerifyTitleUniqueness(app_root, "file1", google_apis::ENTRY_KIND_FILE);
|
| - VerifyTitleUniqueness(app_root, "folder", google_apis::ENTRY_KIND_FOLDER);
|
| - VerifyTitleUniqueness(folder_id, "file2", google_apis::ENTRY_KIND_FILE);
|
| -}
|
| -
|
| -TEST_F(LocalToRemoteSyncerTest, CreateFileOnMissingPath) {
|
| +TEST_F(ConflictResolverTest, NoFileToBeResolved) {
|
| const GURL kOrigin("chrome-extension://example");
|
| const std::string sync_root = CreateSyncRoot();
|
| const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
|
| InitializeMetadataDatabase();
|
| RegisterApp(kOrigin.host(), app_root);
|
| + RunSyncerUntilIdle();
|
|
|
| - // Run the syncer 3 times to create missing folder1 and folder2.
|
| - EXPECT_EQ(SYNC_STATUS_RETRY, RunSyncer(
|
| - FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
|
| - SYNC_FILE_TYPE_FILE),
|
| - URL(kOrigin, "folder1/folder2/file")));
|
| - EXPECT_EQ(SYNC_STATUS_RETRY, RunSyncer(
|
| - FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
|
| - SYNC_FILE_TYPE_FILE),
|
| - URL(kOrigin, "folder1/folder2/file")));
|
| - EXPECT_EQ(SYNC_STATUS_OK, RunSyncer(
|
| - FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
|
| - SYNC_FILE_TYPE_FILE),
|
| - URL(kOrigin, "folder1/folder2/file")));
|
| -
|
| - std::string folder_id1 = GetFileIDForParentAndTitle(app_root, "folder1");
|
| - ASSERT_FALSE(folder_id1.empty());
|
| - std::string folder_id2 = GetFileIDForParentAndTitle(folder_id1, "folder2");
|
| - ASSERT_FALSE(folder_id2.empty());
|
| -
|
| - VerifyTitleUniqueness(app_root, "folder1", google_apis::ENTRY_KIND_FOLDER);
|
| - VerifyTitleUniqueness(folder_id1, "folder2", google_apis::ENTRY_KIND_FOLDER);
|
| - VerifyTitleUniqueness(folder_id2, "file", google_apis::ENTRY_KIND_FILE);
|
| + EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC, RunConflictResolver());
|
| }
|
|
|
| -TEST_F(LocalToRemoteSyncerTest, DeleteFile) {
|
| +TEST_F(ConflictResolverTest, ResolveConflict_Files) {
|
| const GURL kOrigin("chrome-extension://example");
|
| const std::string sync_root = CreateSyncRoot();
|
| const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
|
| InitializeMetadataDatabase();
|
| RegisterApp(kOrigin.host(), app_root);
|
| + RunSyncerUntilIdle();
|
|
|
| - EXPECT_EQ(SYNC_STATUS_OK, RunSyncer(
|
| - FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
|
| - SYNC_FILE_TYPE_FILE),
|
| - URL(kOrigin, "file")));
|
| - EXPECT_EQ(SYNC_STATUS_OK, RunSyncer(
|
| - FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
|
| - SYNC_FILE_TYPE_DIRECTORY),
|
| - URL(kOrigin, "folder")));
|
| -
|
| - VerifyTitleUniqueness(app_root, "file", google_apis::ENTRY_KIND_FILE);
|
| - VerifyTitleUniqueness(app_root, "folder", google_apis::ENTRY_KIND_FOLDER);
|
| -
|
| - EXPECT_EQ(SYNC_STATUS_OK, RunSyncer(
|
| - FileChange(FileChange::FILE_CHANGE_DELETE,
|
| - SYNC_FILE_TYPE_FILE),
|
| - URL(kOrigin, "file")));
|
| - EXPECT_EQ(SYNC_STATUS_OK, RunSyncer(
|
| - FileChange(FileChange::FILE_CHANGE_DELETE,
|
| - SYNC_FILE_TYPE_DIRECTORY),
|
| - URL(kOrigin, "folder")));
|
| -
|
| - VerifyFileDeletion(app_root, "file");
|
| - VerifyFileDeletion(app_root, "folder");
|
| -}
|
| -
|
| -TEST_F(LocalToRemoteSyncerTest, Conflict_CreateFileOnFolder) {
|
| - const GURL kOrigin("chrome-extension://example");
|
| - const std::string sync_root = CreateSyncRoot();
|
| - const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
|
| - InitializeMetadataDatabase();
|
| - RegisterApp(kOrigin.host(), app_root);
|
| -
|
| - CreateRemoteFolder(app_root, "foo");
|
| + const std::string kTitle = "foo";
|
| + const std::string primary = CreateRemoteFile(app_root, kTitle, "data1");
|
| + CreateRemoteFile(app_root, kTitle, "data2");
|
| + CreateRemoteFile(app_root, kTitle, "data3");
|
| + CreateRemoteFile(app_root, kTitle, "data4");
|
| EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
|
| - EXPECT_EQ(SYNC_STATUS_OK, RunSyncer(
|
| - FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
|
| - SYNC_FILE_TYPE_FILE),
|
| - URL(kOrigin, "foo")));
|
| + RunSyncerUntilIdle();
|
|
|
| - // There should exist both file and folder on remote.
|
| ScopedVector<google_apis::ResourceEntry> entries =
|
| - GetResourceEntriesForParentAndTitle(app_root, "foo");
|
| - ASSERT_EQ(2u, entries.size());
|
| - EXPECT_EQ(google_apis::ENTRY_KIND_FOLDER, entries[0]->kind());
|
| - EXPECT_EQ(google_apis::ENTRY_KIND_FILE, entries[1]->kind());
|
| + GetResourceEntriesForParentAndTitle(app_root, kTitle);
|
| + ASSERT_EQ(4u, entries.size());
|
| +
|
| + // Only primary file should survive.
|
| + EXPECT_EQ(SYNC_STATUS_OK, RunConflictResolver());
|
| + VerifyConflictResolution(app_root, kTitle, primary,
|
| + google_apis::ENTRY_KIND_FILE);
|
| }
|
|
|
| -TEST_F(LocalToRemoteSyncerTest, Conflict_CreateFolderOnFile) {
|
| +TEST_F(ConflictResolverTest, ResolveConflict_Folders) {
|
| const GURL kOrigin("chrome-extension://example");
|
| const std::string sync_root = CreateSyncRoot();
|
| const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
|
| InitializeMetadataDatabase();
|
| RegisterApp(kOrigin.host(), app_root);
|
| + RunSyncerUntilIdle();
|
|
|
| - CreateRemoteFile(app_root, "foo", "data");
|
| + const std::string kTitle = "foo";
|
| + const std::string primary = CreateRemoteFolder(app_root, kTitle);
|
| + CreateRemoteFolder(app_root, kTitle);
|
| + CreateRemoteFolder(app_root, kTitle);
|
| + CreateRemoteFolder(app_root, kTitle);
|
| EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
|
| + RunSyncerUntilIdle();
|
|
|
| - EXPECT_EQ(SYNC_STATUS_OK, RunSyncer(
|
| - FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
|
| - SYNC_FILE_TYPE_DIRECTORY),
|
| - URL(kOrigin, "foo")));
|
| -
|
| - // There should exist both file and folder on remote.
|
| ScopedVector<google_apis::ResourceEntry> entries =
|
| - GetResourceEntriesForParentAndTitle(app_root, "foo");
|
| - ASSERT_EQ(2u, entries.size());
|
| - EXPECT_EQ(google_apis::ENTRY_KIND_FILE, entries[0]->kind());
|
| - EXPECT_EQ(google_apis::ENTRY_KIND_FOLDER, entries[1]->kind());
|
| + GetResourceEntriesForParentAndTitle(app_root, kTitle);
|
| + ASSERT_EQ(4u, entries.size());
|
| +
|
| + // Only primary file should survive.
|
| + EXPECT_EQ(SYNC_STATUS_OK, RunConflictResolver());
|
| + VerifyConflictResolution(app_root, kTitle, primary,
|
| + google_apis::ENTRY_KIND_FOLDER);
|
| }
|
|
|
| -TEST_F(LocalToRemoteSyncerTest, Conflict_CreateFileOnFile) {
|
| +TEST_F(ConflictResolverTest, ResolveConflict_FilesAndFolders) {
|
| const GURL kOrigin("chrome-extension://example");
|
| const std::string sync_root = CreateSyncRoot();
|
| const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
|
| InitializeMetadataDatabase();
|
| RegisterApp(kOrigin.host(), app_root);
|
| + RunSyncerUntilIdle();
|
|
|
| - CreateRemoteFile(app_root, "foo", "data");
|
| + const std::string kTitle = "foo";
|
| + CreateRemoteFile(app_root, kTitle, "data");
|
| + const std::string primary = CreateRemoteFolder(app_root, kTitle);
|
| + CreateRemoteFile(app_root, kTitle, "data2");
|
| + CreateRemoteFolder(app_root, kTitle);
|
| EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
|
| + RunSyncerUntilIdle();
|
|
|
| - EXPECT_EQ(SYNC_STATUS_OK, RunSyncer(
|
| - FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
|
| - SYNC_FILE_TYPE_FILE),
|
| - URL(kOrigin, "foo")));
|
| -
|
| - // There should exist both files on remote.
|
| ScopedVector<google_apis::ResourceEntry> entries =
|
| - GetResourceEntriesForParentAndTitle(app_root, "foo");
|
| - ASSERT_EQ(2u, entries.size());
|
| - EXPECT_EQ(google_apis::ENTRY_KIND_FILE, entries[0]->kind());
|
| - EXPECT_EQ(google_apis::ENTRY_KIND_FILE, entries[1]->kind());
|
| + GetResourceEntriesForParentAndTitle(app_root, kTitle);
|
| + ASSERT_EQ(4u, entries.size());
|
| +
|
| + // Only primary file should survive.
|
| + EXPECT_EQ(SYNC_STATUS_OK, RunConflictResolver());
|
| + VerifyConflictResolution(app_root, kTitle, primary,
|
| + google_apis::ENTRY_KIND_FOLDER);
|
| }
|
|
|
| -// TODO(nhiroki): Add folder-folder conflict (reusing remote folder) case.
|
| +// TODO(nhiroki): Add multi-parent resolution cases.
|
|
|
| } // namespace drive_backend
|
| } // namespace sync_file_system
|
|
|