blob: 7fec59b094348a12b245dd474d3ef0489fc8ea5b [file] [log] [blame]
// Copyright 2014 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 "chrome/browser/sync_file_system/drive_backend/sync_worker.h"
#include "base/files/scoped_temp_dir.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/thread_task_runner_handle.h"
#include "chrome/browser/drive/drive_uploader.h"
#include "chrome/browser/drive/fake_drive_service.h"
#include "chrome/browser/extensions/test_extension_service.h"
#include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
#include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h"
#include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h"
#include "chrome/browser/sync_file_system/drive_backend/sync_task.h"
#include "chrome/browser/sync_file_system/drive_backend/sync_task_manager.h"
#include "chrome/browser/sync_file_system/sync_file_system_test_util.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_builder.h"
#include "extensions/common/extension_set.h"
#include "extensions/common/value_builder.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/leveldatabase/src/helpers/memenv/memenv.h"
#include "third_party/leveldatabase/src/include/leveldb/env.h"
namespace sync_file_system {
namespace drive_backend {
namespace {
const char kAppID[] = "app_id";
void EmptyTask(SyncStatusCode status, const SyncStatusCallback& callback) {
base::MessageLoop::current()->PostTask(
FROM_HERE, base::Bind(callback, status));
}
} // namespace
class MockSyncTask : public ExclusiveTask {
public:
explicit MockSyncTask(bool used_network) {
set_used_network(used_network);
}
virtual ~MockSyncTask() {}
virtual void RunExclusive(const SyncStatusCallback& callback) OVERRIDE {
callback.Run(SYNC_STATUS_OK);
}
private:
DISALLOW_COPY_AND_ASSIGN(MockSyncTask);
};
class MockExtensionService : public TestExtensionService {
public:
MockExtensionService() {}
virtual ~MockExtensionService() {}
virtual const extensions::ExtensionSet* extensions() const OVERRIDE {
return &extensions_;
}
virtual void AddExtension(const extensions::Extension* extension) OVERRIDE {
extensions_.Insert(make_scoped_refptr(extension));
}
virtual const extensions::Extension* GetInstalledExtension(
const std::string& extension_id) const OVERRIDE {
return extensions_.GetByID(extension_id);
}
virtual bool IsExtensionEnabled(
const std::string& extension_id) const OVERRIDE {
return extensions_.Contains(extension_id) &&
!disabled_extensions_.Contains(extension_id);
}
void UninstallExtension(const std::string& extension_id) {
extensions_.Remove(extension_id);
disabled_extensions_.Remove(extension_id);
}
void DisableExtension(const std::string& extension_id) {
if (!IsExtensionEnabled(extension_id))
return;
const extensions::Extension* extension = extensions_.GetByID(extension_id);
disabled_extensions_.Insert(make_scoped_refptr(extension));
}
private:
extensions::ExtensionSet extensions_;
extensions::ExtensionSet disabled_extensions_;
DISALLOW_COPY_AND_ASSIGN(MockExtensionService);
};
class SyncWorkerTest : public testing::Test,
public base::SupportsWeakPtr<SyncWorkerTest> {
public:
SyncWorkerTest() {}
virtual ~SyncWorkerTest() {}
virtual void SetUp() OVERRIDE {
ASSERT_TRUE(profile_dir_.CreateUniqueTempDir());
in_memory_env_.reset(leveldb::NewMemEnv(leveldb::Env::Default()));
extension_service_.reset(new MockExtensionService);
scoped_ptr<drive::DriveServiceInterface>
fake_drive_service(new drive::FakeDriveService);
scoped_ptr<SyncEngineContext>
sync_engine_context(new SyncEngineContext(
fake_drive_service.Pass(),
scoped_ptr<drive::DriveUploaderInterface>(),
NULL /* task_logger */,
base::ThreadTaskRunnerHandle::Get() /* ui_task_runner */,
base::ThreadTaskRunnerHandle::Get() /* worker_task_runner */));
sync_worker_.reset(new SyncWorker(
profile_dir_.path(),
extension_service_->AsWeakPtr(),
in_memory_env_.get()));
sync_worker_->Initialize(sync_engine_context.Pass());
sync_worker_->SetSyncEnabled(true);
base::RunLoop().RunUntilIdle();
}
virtual void TearDown() OVERRIDE {
sync_worker_.reset();
extension_service_.reset();
base::RunLoop().RunUntilIdle();
}
MockExtensionService* extension_service() { return extension_service_.get(); }
SyncWorker* sync_worker() { return sync_worker_.get(); }
void UpdateRegisteredApps() {
sync_worker_->UpdateRegisteredApps();
}
SyncTaskManager* GetSyncTaskManager() {
return sync_worker_->task_manager_.get();
}
void CheckServiceState(SyncStatusCode expected_sync_status,
RemoteServiceState expected_service_status,
SyncStatusCode sync_status) {
EXPECT_EQ(expected_sync_status, sync_status);
EXPECT_EQ(expected_service_status, sync_worker_->GetCurrentState());
}
MetadataDatabase* metadata_database() {
return sync_worker_->GetMetadataDatabase();
}
private:
content::TestBrowserThreadBundle browser_threads_;
base::ScopedTempDir profile_dir_;
scoped_ptr<leveldb::Env> in_memory_env_;
scoped_ptr<MockExtensionService> extension_service_;
scoped_ptr<SyncWorker> sync_worker_;
DISALLOW_COPY_AND_ASSIGN(SyncWorkerTest);
};
TEST_F(SyncWorkerTest, EnableOrigin) {
FileTracker tracker;
SyncStatusCode sync_status = SYNC_STATUS_UNKNOWN;
GURL origin = extensions::Extension::GetBaseURLFromExtensionId(kAppID);
sync_worker()->RegisterOrigin(origin, CreateResultReceiver(&sync_status));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(SYNC_STATUS_OK, sync_status);
ASSERT_TRUE(metadata_database()->FindAppRootTracker(kAppID, &tracker));
EXPECT_EQ(TRACKER_KIND_APP_ROOT, tracker.tracker_kind());
sync_worker()->DisableOrigin(origin, CreateResultReceiver(&sync_status));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(SYNC_STATUS_OK, sync_status);
ASSERT_TRUE(metadata_database()->FindAppRootTracker(kAppID, &tracker));
EXPECT_EQ(TRACKER_KIND_DISABLED_APP_ROOT, tracker.tracker_kind());
sync_worker()->EnableOrigin(origin, CreateResultReceiver(&sync_status));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(SYNC_STATUS_OK, sync_status);
ASSERT_TRUE(metadata_database()->FindAppRootTracker(kAppID, &tracker));
EXPECT_EQ(TRACKER_KIND_APP_ROOT, tracker.tracker_kind());
sync_worker()->UninstallOrigin(
origin,
RemoteFileSyncService::UNINSTALL_AND_KEEP_REMOTE,
CreateResultReceiver(&sync_status));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(SYNC_STATUS_OK, sync_status);
ASSERT_FALSE(metadata_database()->FindAppRootTracker(kAppID, &tracker));
}
TEST_F(SyncWorkerTest, UpdateRegisteredApps) {
SyncStatusCode sync_status = SYNC_STATUS_UNKNOWN;
for (int i = 0; i < 3; i++) {
scoped_refptr<const extensions::Extension> extension =
extensions::ExtensionBuilder()
.SetManifest(extensions::DictionaryBuilder()
.Set("name", "foo")
.Set("version", "1.0")
.Set("manifest_version", 2))
.SetID(base::StringPrintf("app_%d", i))
.Build();
extension_service()->AddExtension(extension.get());
GURL origin = extensions::Extension::GetBaseURLFromExtensionId(
extension->id());
sync_status = SYNC_STATUS_UNKNOWN;
sync_worker()->RegisterOrigin(origin, CreateResultReceiver(&sync_status));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(SYNC_STATUS_OK, sync_status);
}
FileTracker tracker;
ASSERT_TRUE(metadata_database()->FindAppRootTracker("app_0", &tracker));
EXPECT_EQ(TRACKER_KIND_APP_ROOT, tracker.tracker_kind());
ASSERT_TRUE(metadata_database()->FindAppRootTracker("app_1", &tracker));
EXPECT_EQ(TRACKER_KIND_APP_ROOT, tracker.tracker_kind());
ASSERT_TRUE(metadata_database()->FindAppRootTracker("app_2", &tracker));
EXPECT_EQ(TRACKER_KIND_APP_ROOT, tracker.tracker_kind());
extension_service()->DisableExtension("app_1");
extension_service()->UninstallExtension("app_2");
ASSERT_FALSE(extension_service()->GetInstalledExtension("app_2"));
UpdateRegisteredApps();
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(metadata_database()->FindAppRootTracker("app_0", &tracker));
EXPECT_EQ(TRACKER_KIND_APP_ROOT, tracker.tracker_kind());
ASSERT_TRUE(metadata_database()->FindAppRootTracker("app_1", &tracker));
EXPECT_EQ(TRACKER_KIND_DISABLED_APP_ROOT, tracker.tracker_kind());
ASSERT_FALSE(metadata_database()->FindAppRootTracker("app_2", &tracker));
}
TEST_F(SyncWorkerTest, GetOriginStatusMap) {
FileTracker tracker;
SyncStatusCode sync_status = SYNC_STATUS_UNKNOWN;
GURL origin = extensions::Extension::GetBaseURLFromExtensionId(kAppID);
sync_worker()->RegisterOrigin(GURL("chrome-extension://app_0"),
CreateResultReceiver(&sync_status));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(SYNC_STATUS_OK, sync_status);
sync_worker()->RegisterOrigin(GURL("chrome-extension://app_1"),
CreateResultReceiver(&sync_status));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(SYNC_STATUS_OK, sync_status);
scoped_ptr<RemoteFileSyncService::OriginStatusMap> status_map;
sync_worker()->GetOriginStatusMap(CreateResultReceiver(&status_map));
base::RunLoop().RunUntilIdle();
ASSERT_EQ(2u, status_map->size());
EXPECT_EQ("Enabled", (*status_map)[GURL("chrome-extension://app_0")]);
EXPECT_EQ("Enabled", (*status_map)[GURL("chrome-extension://app_1")]);
sync_worker()->DisableOrigin(GURL("chrome-extension://app_1"),
CreateResultReceiver(&sync_status));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(SYNC_STATUS_OK, sync_status);
sync_worker()->GetOriginStatusMap(CreateResultReceiver(&status_map));
base::RunLoop().RunUntilIdle();
ASSERT_EQ(2u, status_map->size());
EXPECT_EQ("Enabled", (*status_map)[GURL("chrome-extension://app_0")]);
EXPECT_EQ("Disabled", (*status_map)[GURL("chrome-extension://app_1")]);
}
TEST_F(SyncWorkerTest, UpdateServiceState) {
EXPECT_EQ(REMOTE_SERVICE_OK, sync_worker()->GetCurrentState());
GetSyncTaskManager()->ScheduleTask(
FROM_HERE,
base::Bind(&EmptyTask, SYNC_STATUS_AUTHENTICATION_FAILED),
SyncTaskManager::PRIORITY_MED,
base::Bind(&SyncWorkerTest::CheckServiceState,
AsWeakPtr(),
SYNC_STATUS_AUTHENTICATION_FAILED,
REMOTE_SERVICE_AUTHENTICATION_REQUIRED));
GetSyncTaskManager()->ScheduleTask(
FROM_HERE,
base::Bind(&EmptyTask, SYNC_STATUS_ACCESS_FORBIDDEN),
SyncTaskManager::PRIORITY_MED,
base::Bind(&SyncWorkerTest::CheckServiceState,
AsWeakPtr(),
SYNC_STATUS_ACCESS_FORBIDDEN,
REMOTE_SERVICE_ACCESS_FORBIDDEN));
GetSyncTaskManager()->ScheduleTask(
FROM_HERE,
base::Bind(&EmptyTask, SYNC_STATUS_SERVICE_TEMPORARILY_UNAVAILABLE),
SyncTaskManager::PRIORITY_MED,
base::Bind(&SyncWorkerTest::CheckServiceState,
AsWeakPtr(),
SYNC_STATUS_SERVICE_TEMPORARILY_UNAVAILABLE,
REMOTE_SERVICE_TEMPORARY_UNAVAILABLE));
GetSyncTaskManager()->ScheduleTask(
FROM_HERE,
base::Bind(&EmptyTask, SYNC_STATUS_NETWORK_ERROR),
SyncTaskManager::PRIORITY_MED,
base::Bind(&SyncWorkerTest::CheckServiceState,
AsWeakPtr(),
SYNC_STATUS_NETWORK_ERROR,
REMOTE_SERVICE_TEMPORARY_UNAVAILABLE));
GetSyncTaskManager()->ScheduleTask(
FROM_HERE,
base::Bind(&EmptyTask, SYNC_STATUS_ABORT),
SyncTaskManager::PRIORITY_MED,
base::Bind(&SyncWorkerTest::CheckServiceState,
AsWeakPtr(),
SYNC_STATUS_ABORT,
REMOTE_SERVICE_TEMPORARY_UNAVAILABLE));
GetSyncTaskManager()->ScheduleTask(
FROM_HERE,
base::Bind(&EmptyTask, SYNC_STATUS_FAILED),
SyncTaskManager::PRIORITY_MED,
base::Bind(&SyncWorkerTest::CheckServiceState,
AsWeakPtr(),
SYNC_STATUS_FAILED,
REMOTE_SERVICE_TEMPORARY_UNAVAILABLE));
GetSyncTaskManager()->ScheduleTask(
FROM_HERE,
base::Bind(&EmptyTask, SYNC_DATABASE_ERROR_CORRUPTION),
SyncTaskManager::PRIORITY_MED,
base::Bind(&SyncWorkerTest::CheckServiceState,
AsWeakPtr(),
SYNC_DATABASE_ERROR_CORRUPTION,
REMOTE_SERVICE_DISABLED));
GetSyncTaskManager()->ScheduleTask(
FROM_HERE,
base::Bind(&EmptyTask, SYNC_DATABASE_ERROR_IO_ERROR),
SyncTaskManager::PRIORITY_MED,
base::Bind(&SyncWorkerTest::CheckServiceState,
AsWeakPtr(),
SYNC_DATABASE_ERROR_IO_ERROR,
REMOTE_SERVICE_DISABLED));
GetSyncTaskManager()->ScheduleTask(
FROM_HERE,
base::Bind(&EmptyTask, SYNC_DATABASE_ERROR_FAILED),
SyncTaskManager::PRIORITY_MED,
base::Bind(&SyncWorkerTest::CheckServiceState,
AsWeakPtr(),
SYNC_DATABASE_ERROR_FAILED,
REMOTE_SERVICE_DISABLED));
GetSyncTaskManager()->ScheduleSyncTask(
FROM_HERE,
scoped_ptr<SyncTask>(new MockSyncTask(false)),
SyncTaskManager::PRIORITY_MED,
base::Bind(&SyncWorkerTest::CheckServiceState,
AsWeakPtr(),
SYNC_STATUS_OK,
REMOTE_SERVICE_DISABLED));
GetSyncTaskManager()->ScheduleSyncTask(
FROM_HERE,
scoped_ptr<SyncTask>(new MockSyncTask(true)),
SyncTaskManager::PRIORITY_MED,
base::Bind(&SyncWorkerTest::CheckServiceState,
AsWeakPtr(),
SYNC_STATUS_OK,
REMOTE_SERVICE_OK));
base::RunLoop().RunUntilIdle();
}
} // namespace drive_backend
} // namespace sync_file_system