Commit 73abd712 authored by Pavel Yatsuk's avatar Pavel Yatsuk Committed by Commit Bot

[Sync] Register BookmarkModelTypeController with sync engine

This CL adds functionality to BookmarkModelTypeController to check for
dependencies (BookmarkModel and HistoryService) and register it with sync
engine. It passes the first half of configuration stage up until receiving
remote updates.

BUG=516866
R=skym@chromium.org

Change-Id: Ifd9c421395e0d8f93c24a0966dd18313fa3d0c1d
Reviewed-on: https://chromium-review.googlesource.com/636345Reviewed-by: default avatarSky Malice <skym@chromium.org>
Commit-Queue: Pavel Yatsuk <pavely@chromium.org>
Cr-Commit-Position: refs/heads/master@{#497669}
parent 76003da7
......@@ -206,7 +206,8 @@ void ProfileSyncComponentsFactoryImpl::RegisterCommonDataTypes(
if (!disabled_types.Has(syncer::BOOKMARKS)) {
if (FeatureList::IsEnabled(switches::kSyncUSSBookmarks)) {
sync_service->RegisterDataTypeController(
std::make_unique<sync_bookmarks::BookmarkModelTypeController>());
std::make_unique<sync_bookmarks::BookmarkModelTypeController>(
sync_client_));
} else {
sync_service->RegisterDataTypeController(
std::make_unique<BookmarkDataTypeController>(error_callback,
......
......@@ -34,6 +34,7 @@ source_set("unit_tests") {
sources = [
"bookmark_data_type_controller_unittest.cc",
"bookmark_model_type_controller_unittest.cc",
"bookmark_model_type_processor_unittest.cc",
]
......@@ -46,6 +47,7 @@ source_set("unit_tests") {
"//components/prefs:test_support",
"//components/sync",
"//components/sync:test_support_driver",
"//components/sync:test_support_engine",
"//components/sync:test_support_model",
"//testing/gmock",
"//testing/gtest",
......
......@@ -4,68 +4,166 @@
#include "components/sync_bookmarks/bookmark_model_type_controller.h"
#include <utility>
#include "base/threading/thread_task_runner_handle.h"
#include "components/bookmarks/browser/bookmark_model.h"
#include "components/history/core/browser/history_service.h"
#include "components/sync/driver/sync_client.h"
#include "components/sync/driver/sync_service.h"
#include "components/sync/engine/model_type_configurer.h"
#include "components/sync/engine/model_type_processor_proxy.h"
#include "components/sync/model/sync_error.h"
#include "components/sync/protocol/model_type_state.pb.h"
#include "components/sync/protocol/sync.pb.h"
#include "components/sync/syncable/directory.h"
#include "components/sync/syncable/user_share.h"
#include "components/sync_bookmarks/bookmark_model_type_processor.h"
using syncer::SyncError;
namespace sync_bookmarks {
BookmarkModelTypeController::BookmarkModelTypeController()
: DataTypeController(syncer::BOOKMARKS) {}
BookmarkModelTypeController::BookmarkModelTypeController(
syncer::SyncClient* sync_client)
: DataTypeController(syncer::BOOKMARKS),
sync_client_(sync_client),
state_(NOT_RUNNING) {}
BookmarkModelTypeController::~BookmarkModelTypeController() = default;
bool BookmarkModelTypeController::ShouldLoadModelBeforeConfigure() const {
NOTIMPLEMENTED();
return false;
DCHECK(CalledOnValidThread());
return true;
}
void BookmarkModelTypeController::BeforeLoadModels(
syncer::ModelTypeConfigurer* configurer) {
NOTIMPLEMENTED();
DCHECK(CalledOnValidThread());
}
void BookmarkModelTypeController::LoadModels(
const ModelLoadCallback& model_load_callback) {
NOTIMPLEMENTED();
DCHECK(CalledOnValidThread());
if (state() != NOT_RUNNING) {
model_load_callback.Run(type(),
SyncError(FROM_HERE, SyncError::DATATYPE_ERROR,
"Model already running", type()));
return;
}
state_ = MODEL_STARTING;
if (DependenciesLoaded()) {
state_ = MODEL_LOADED;
model_load_callback.Run(type(), SyncError());
} else {
// TODO(pavely): Subscribe for BookmarkModel and HistoryService
// notifications.
NOTIMPLEMENTED();
}
}
void BookmarkModelTypeController::RegisterWithBackend(
base::Callback<void(bool)> set_downloaded,
syncer::ModelTypeConfigurer* configurer) {
NOTIMPLEMENTED();
DCHECK(CalledOnValidThread());
DCHECK(configurer);
std::unique_ptr<syncer::ActivationContext> activation_context =
PrepareActivationContext();
set_downloaded.Run(activation_context->model_type_state.initial_sync_done());
configurer->ActivateNonBlockingDataType(type(),
std::move(activation_context));
}
void BookmarkModelTypeController::StartAssociating(
const StartCallback& start_callback) {
NOTIMPLEMENTED();
DCHECK(CalledOnValidThread());
DCHECK(!start_callback.is_null());
DCHECK_EQ(MODEL_LOADED, state_);
state_ = RUNNING;
// There is no association, just call back promptly.
syncer::SyncMergeResult merge_result(type());
start_callback.Run(OK, merge_result, merge_result);
}
void BookmarkModelTypeController::ActivateDataType(
syncer::ModelTypeConfigurer* configurer) {
DCHECK(CalledOnValidThread());
NOTIMPLEMENTED();
}
void BookmarkModelTypeController::DeactivateDataType(
syncer::ModelTypeConfigurer* configurer) {
DCHECK(CalledOnValidThread());
NOTIMPLEMENTED();
}
void BookmarkModelTypeController::Stop() {
DCHECK(CalledOnValidThread());
NOTIMPLEMENTED();
}
syncer::DataTypeController::State BookmarkModelTypeController::state() const {
NOTIMPLEMENTED();
return NOT_RUNNING;
DCHECK(CalledOnValidThread());
return state_;
}
void BookmarkModelTypeController::GetAllNodes(
const AllNodesCallback& callback) {
DCHECK(CalledOnValidThread());
NOTIMPLEMENTED();
}
void BookmarkModelTypeController::GetStatusCounters(
const StatusCountersCallback& callback) {
DCHECK(CalledOnValidThread());
NOTIMPLEMENTED();
}
void BookmarkModelTypeController::RecordMemoryUsageHistogram() {
DCHECK(CalledOnValidThread());
NOTIMPLEMENTED();
}
bool BookmarkModelTypeController::DependenciesLoaded() {
DCHECK(CalledOnValidThread());
bookmarks::BookmarkModel* bookmark_model = sync_client_->GetBookmarkModel();
if (!bookmark_model || !bookmark_model->loaded())
return false;
history::HistoryService* history_service = sync_client_->GetHistoryService();
if (!history_service || !history_service->BackendLoaded())
return false;
return true;
}
std::unique_ptr<syncer::ActivationContext>
BookmarkModelTypeController::PrepareActivationContext() {
DCHECK(!model_type_processor_);
syncer::UserShare* user_share =
sync_client_->GetSyncService()->GetUserShare();
syncer::syncable::Directory* directory = user_share->directory.get();
std::unique_ptr<syncer::ActivationContext> activation_context =
std::make_unique<syncer::ActivationContext>();
directory->GetDownloadProgress(
type(), activation_context->model_type_state.mutable_progress_marker());
activation_context->model_type_state.set_initial_sync_done(
directory->InitialSyncEndedForType(type()));
// TODO(pavely): Populate model_type_state.type_context.
model_type_processor_ = std::make_unique<BookmarkModelTypeProcessor>();
activation_context->type_processor =
std::make_unique<syncer::ModelTypeProcessorProxy>(
model_type_processor_->GetWeakPtr(),
base::ThreadTaskRunnerHandle::Get());
return activation_context;
}
} // namespace sync_bookmarks
......@@ -5,16 +5,26 @@
#ifndef COMPONENTS_SYNC_BOOKMARKS_BOOKMARK_MODEL_TYPE_CONTROLLER_H_
#define COMPONENTS_SYNC_BOOKMARKS_BOOKMARK_MODEL_TYPE_CONTROLLER_H_
#include <memory>
#include "base/macros.h"
#include "components/sync/driver/data_type_controller.h"
#include "components/sync/engine/activation_context.h"
namespace syncer {
class SyncClient;
} // namespace syncer
namespace sync_bookmarks {
class BookmarkModelTypeProcessor;
// A class that manages the startup and shutdown of bookmark sync implemented
// through USS APIs.
class BookmarkModelTypeController : public syncer::DataTypeController {
public:
BookmarkModelTypeController();
explicit BookmarkModelTypeController(syncer::SyncClient* sync_client);
~BookmarkModelTypeController() override;
// syncer::DataTypeController implementation.
bool ShouldLoadModelBeforeConfigure() const override;
......@@ -32,6 +42,25 @@ class BookmarkModelTypeController : public syncer::DataTypeController {
void RecordMemoryUsageHistogram() override;
private:
friend class BookmarkModelTypeControllerTest;
// Returns true if both BookmarkModel and HistoryService are loaded.
bool DependenciesLoaded();
// Reads ModelTypeState from storage and creates BookmarkModelTypeProcessor.
std::unique_ptr<syncer::ActivationContext> PrepareActivationContext();
// SyncClient provides access to BookmarkModel, HistoryService and
// SyncService.
syncer::SyncClient* sync_client_;
// State of this datatype controller.
State state_;
// BookmarkModelTypeProcessor handles communications between sync engine and
// BookmarkModel/HistoryService.
std::unique_ptr<BookmarkModelTypeProcessor> model_type_processor_;
DISALLOW_COPY_AND_ASSIGN(BookmarkModelTypeController);
};
......
// Copyright 2017 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/sync_bookmarks/bookmark_model_type_controller.h"
#include <memory>
#include <utility>
#include "base/bind.h"
#include "base/message_loop/message_loop.h"
#include "components/bookmarks/browser/bookmark_model.h"
#include "components/bookmarks/test/test_bookmark_client.h"
#include "components/history/core/browser/history_service.h"
#include "components/sync/base/model_type.h"
#include "components/sync/driver/data_type_controller.h"
#include "components/sync/driver/data_type_controller_mock.h"
#include "components/sync/driver/fake_sync_client.h"
#include "components/sync/driver/fake_sync_service.h"
#include "components/sync/engine/model_type_configurer.h"
#include "components/sync/model/sync_error.h"
#include "components/sync/model/sync_merge_result.h"
#include "components/sync/syncable/directory.h"
#include "components/sync/syncable/test_user_share.h"
#include "components/sync/test/engine/test_syncable_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
using syncer::DataTypeController;
using syncer::ModelType;
using syncer::SyncService;
using syncer::UserShare;
using testing::_;
namespace sync_bookmarks {
namespace {
// Fake specializations for BookmarModelTypeController's external dependencies.
class TestHistoryService : public history::HistoryService {
public:
bool BackendLoaded() override { return true; }
};
class TestSyncClient : public syncer::FakeSyncClient {
public:
TestSyncClient(bookmarks::BookmarkModel* bookmark_model,
history::HistoryService* history_service,
SyncService* sync_service)
: bookmark_model_(bookmark_model),
history_service_(history_service),
sync_service_(sync_service) {}
bookmarks::BookmarkModel* GetBookmarkModel() override {
return bookmark_model_;
}
history::HistoryService* GetHistoryService() override {
return history_service_;
}
SyncService* GetSyncService() override { return sync_service_; }
private:
bookmarks::BookmarkModel* bookmark_model_;
history::HistoryService* history_service_;
SyncService* sync_service_;
};
class TestSyncService : public syncer::FakeSyncService {
public:
explicit TestSyncService(UserShare* user_share) : user_share_(user_share) {}
UserShare* GetUserShare() const override { return user_share_; }
private:
UserShare* user_share_;
};
class TestModelTypeConfigurer : public syncer::ModelTypeConfigurer {
public:
TestModelTypeConfigurer() {}
~TestModelTypeConfigurer() override {}
void ConfigureDataTypes(ConfigureParams params) override {}
void RegisterDirectoryDataType(ModelType type,
syncer::ModelSafeGroup group) override {}
void UnregisterDirectoryDataType(ModelType type) override {}
void ActivateDirectoryDataType(
ModelType type,
syncer::ModelSafeGroup group,
syncer::ChangeProcessor* change_processor) override {}
void DeactivateDirectoryDataType(ModelType type) override {}
void ActivateNonBlockingDataType(
ModelType type,
std::unique_ptr<syncer::ActivationContext> activation_context) override {
activation_context_ = std::move(activation_context);
}
void DeactivateNonBlockingDataType(ModelType type) override {}
syncer::ActivationContext* activation_context() {
return activation_context_.get();
}
private:
// ActivationContext captured in ActivateNonBlockingDataType call.
std::unique_ptr<syncer::ActivationContext> activation_context_;
};
} // namespace
class BookmarkModelTypeControllerTest : public testing::Test {
public:
void SetUp() override {
bookmark_model_ = bookmarks::TestBookmarkClient::CreateModel();
history_service_ = std::make_unique<TestHistoryService>();
test_user_share_.SetUp();
sync_service_ =
std::make_unique<TestSyncService>(test_user_share_.user_share());
sync_client_ = std::make_unique<TestSyncClient>(
bookmark_model_.get(), history_service_.get(), sync_service_.get());
controller_ =
std::make_unique<BookmarkModelTypeController>(sync_client_.get());
}
void TearDown() override { test_user_share_.TearDown(); }
protected:
BookmarkModelTypeController* controller() { return controller_.get(); }
syncer::UserShare* user_share() { return test_user_share_.user_share(); }
syncer::ModelLoadCallbackMock& model_load_callback() {
return model_load_callback_;
}
syncer::StartCallbackMock& start_callback() { return start_callback_; }
syncer::ActivationContext* activation_context() {
return model_type_configurer_.activation_context();
}
void LoadModels() {
controller()->LoadModels(
base::Bind(&syncer::ModelLoadCallbackMock::Run,
base::Unretained(&model_load_callback_)));
}
static void CaptureBoolean(bool* value_dest, bool value) {
*value_dest = value;
}
void CallRegisterWithBackend(bool* initial_sync_done) {
controller()->RegisterWithBackend(
base::Bind(&BookmarkModelTypeControllerTest::CaptureBoolean,
initial_sync_done),
&model_type_configurer_);
}
void StartAssociating() {
controller()->StartAssociating(base::Bind(
&syncer::StartCallbackMock::Run, base::Unretained(&start_callback_)));
}
private:
base::MessageLoop message_loop_;
std::unique_ptr<bookmarks::BookmarkModel> bookmark_model_;
std::unique_ptr<history::HistoryService> history_service_;
syncer::TestUserShare test_user_share_;
std::unique_ptr<SyncService> sync_service_;
std::unique_ptr<TestSyncClient> sync_client_;
TestModelTypeConfigurer model_type_configurer_;
syncer::ModelLoadCallbackMock model_load_callback_;
syncer::StartCallbackMock start_callback_;
std::unique_ptr<BookmarkModelTypeController> controller_;
};
// Tests model type and initial state of bookmarks controller.
TEST_F(BookmarkModelTypeControllerTest, InitialState) {
EXPECT_EQ(syncer::BOOKMARKS, controller()->type());
EXPECT_EQ(DataTypeController::NOT_RUNNING, controller()->state());
EXPECT_TRUE(controller()->ShouldLoadModelBeforeConfigure());
}
// Tests that call to LoadModels triggers ModelLoadCallback and advances DTC
// state.
TEST_F(BookmarkModelTypeControllerTest, LoadModels) {
EXPECT_CALL(model_load_callback(), Run(_, _));
LoadModels();
EXPECT_EQ(DataTypeController::MODEL_LOADED, controller()->state());
}
// Tests that registering with backend from clean state reports that initial
// sync is not done and progress marker is empty.
TEST_F(BookmarkModelTypeControllerTest, RegisterWithBackend_CleanState) {
LoadModels();
bool initial_sync_done = false;
CallRegisterWithBackend(&initial_sync_done);
EXPECT_FALSE(initial_sync_done);
EXPECT_FALSE(activation_context()->model_type_state.initial_sync_done());
EXPECT_TRUE(
activation_context()->model_type_state.progress_marker().token().empty());
EXPECT_NE(nullptr, activation_context()->type_processor);
}
// Tests that registering with backend from valid state returns non-empty
// progress marker.
TEST_F(BookmarkModelTypeControllerTest, RegisterWithBackend) {
syncer::TestUserShare::CreateRoot(syncer::BOOKMARKS, user_share());
sync_pb::DataTypeProgressMarker progress_marker =
syncer::syncable::BuildProgress(syncer::BOOKMARKS);
user_share()->directory->SetDownloadProgress(syncer::BOOKMARKS,
progress_marker);
LoadModels();
bool initial_sync_done = false;
CallRegisterWithBackend(&initial_sync_done);
EXPECT_TRUE(initial_sync_done);
EXPECT_TRUE(activation_context()->model_type_state.initial_sync_done());
EXPECT_EQ(progress_marker.SerializeAsString(),
activation_context()
->model_type_state.progress_marker()
.SerializeAsString());
EXPECT_NE(nullptr, activation_context()->type_processor);
}
// Tests that call to StartAssociating triggers StartCallback and adjusts DTC
// state.
TEST_F(BookmarkModelTypeControllerTest, StartAssociating) {
LoadModels();
EXPECT_CALL(start_callback(), Run(_, _, _));
StartAssociating();
EXPECT_EQ(DataTypeController::RUNNING, controller()->state());
}
} // namespace sync_bookmarks
......@@ -4,40 +4,58 @@
#include "components/sync_bookmarks/bookmark_model_type_processor.h"
#include <utility>
#include "base/callback.h"
#include "components/sync/base/model_type.h"
#include "components/sync/engine/commit_queue.h"
namespace sync_bookmarks {
BookmarkModelTypeProcessor::BookmarkModelTypeProcessor() = default;
BookmarkModelTypeProcessor::BookmarkModelTypeProcessor()
: weak_ptr_factory_(this) {}
BookmarkModelTypeProcessor::~BookmarkModelTypeProcessor() = default;
void BookmarkModelTypeProcessor::ConnectSync(
std::unique_ptr<syncer::CommitQueue> worker) {
NOTIMPLEMENTED();
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!worker_);
worker_ = std::move(worker);
}
void BookmarkModelTypeProcessor::DisconnectSync() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
NOTIMPLEMENTED();
}
void BookmarkModelTypeProcessor::GetLocalChanges(
size_t max_entries,
const GetLocalChangesCallback& callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
syncer::CommitRequestDataList local_changes;
callback.Run(std::move(local_changes));
NOTIMPLEMENTED();
}
void BookmarkModelTypeProcessor::OnCommitCompleted(
const sync_pb::ModelTypeState& type_state,
const syncer::CommitResponseDataList& response_list) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
NOTIMPLEMENTED();
}
void BookmarkModelTypeProcessor::OnUpdateReceived(
const sync_pb::ModelTypeState& model_type_state,
const syncer::UpdateResponseDataList& updates) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
NOTIMPLEMENTED();
}
base::WeakPtr<syncer::ModelTypeProcessor>
BookmarkModelTypeProcessor::GetWeakPtr() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return weak_ptr_factory_.GetWeakPtr();
}
} // namespace sync_bookmarks
......@@ -8,6 +8,8 @@
#include <memory>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "components/sync/engine/model_type_processor.h"
namespace sync_bookmarks {
......@@ -28,7 +30,15 @@ class BookmarkModelTypeProcessor : public syncer::ModelTypeProcessor {
void OnUpdateReceived(const sync_pb::ModelTypeState& type_state,
const syncer::UpdateResponseDataList& updates) override;
base::WeakPtr<syncer::ModelTypeProcessor> GetWeakPtr();
private:
SEQUENCE_CHECKER(sequence_checker_);
std::unique_ptr<syncer::CommitQueue> worker_;
base::WeakPtrFactory<BookmarkModelTypeProcessor> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(BookmarkModelTypeProcessor);
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment