blob: 8d63337a0a28f7458a5dd7aa1e7318a53fc1080b [file] [log] [blame]
// 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