Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(180)

Unified Diff: components/sync/driver/model_type_controller_unittest.cc

Issue 2384153004: [Sync] Merge NBDTC and subclasses into ModelTypeController. (Closed)
Patch Set: Fix bad rebase. Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: components/sync/driver/model_type_controller_unittest.cc
diff --git a/components/sync/driver/model_type_controller_unittest.cc b/components/sync/driver/model_type_controller_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..2c3c55daa0a6d1c620be4335f3219ea9789123b3
--- /dev/null
+++ b/components/sync/driver/model_type_controller_unittest.cc
@@ -0,0 +1,401 @@
+// Copyright 2016 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/driver/model_type_controller.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/sequenced_task_runner.h"
+#include "base/test/test_simple_task_runner.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/sync/api/fake_model_type_change_processor.h"
+#include "components/sync/api/stub_model_type_service.h"
+#include "components/sync/core/activation_context.h"
+#include "components/sync/core/model_type_processor_proxy.h"
+#include "components/sync/core/shared_model_type_processor.h"
+#include "components/sync/core/test/fake_model_type_processor.h"
+#include "components/sync/driver/backend_data_type_configurer.h"
+#include "components/sync/driver/fake_sync_client.h"
+#include "components/sync/engine/commit_queue.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace syncer {
+
+namespace {
+
+const ModelType kTestModelType = AUTOFILL;
+
+// A change processor for testing that connects using a thread-jumping proxy,
+// tracks connected state, and counts DisableSync calls.
+class TestModelTypeProcessor : public FakeModelTypeChangeProcessor,
+ public FakeModelTypeProcessor {
+ public:
+ explicit TestModelTypeProcessor(int* disable_sync_call_count)
+ : disable_sync_call_count_(disable_sync_call_count),
+ weak_factory_(this) {}
+
+ // ModelTypeChangeProcessor implementation.
+ void OnSyncStarting(std::unique_ptr<DataTypeErrorHandler> error_handler,
+ const StartCallback& callback) override {
+ std::unique_ptr<ActivationContext> activation_context =
+ base::MakeUnique<ActivationContext>();
+ activation_context->type_processor =
+ base::MakeUnique<ModelTypeProcessorProxy>(
+ weak_factory_.GetWeakPtr(), base::ThreadTaskRunnerHandle::Get());
+ callback.Run(SyncError(), std::move(activation_context));
+ }
+ void DisableSync() override { (*disable_sync_call_count_)++; }
+
+ // ModelTypeProcessor implementation.
+ void ConnectSync(std::unique_ptr<CommitQueue> commit_queue) override {
+ is_connected_ = true;
+ }
+ void DisconnectSync() override { is_connected_ = false; }
+
+ bool is_connected() { return is_connected_; }
+
+ private:
+ bool is_connected_ = false;
+ int* disable_sync_call_count_;
+ base::WeakPtrFactory<TestModelTypeProcessor> weak_factory_;
+ DISALLOW_COPY_AND_ASSIGN(TestModelTypeProcessor);
+};
+
+// A BackendDataTypeConfigurer that just connects USS types.
+class TestBackendDataTypeConfigurer : public BackendDataTypeConfigurer {
+ public:
+ TestBackendDataTypeConfigurer() {}
+ ~TestBackendDataTypeConfigurer() override {}
+
+ ModelTypeSet ConfigureDataTypes(
+ ConfigureReason reason,
+ const DataTypeConfigStateMap& config_state_map,
+ const base::Callback<void(ModelTypeSet, ModelTypeSet)>& ready_task,
+ const base::Callback<void()>& retry_callback) override {
+ NOTREACHED() << "Not implemented.";
+ return ModelTypeSet();
+ }
+
+ void ActivateDirectoryDataType(ModelType type,
+ ModelSafeGroup group,
+ ChangeProcessor* change_processor) override {
+ NOTREACHED() << "Not implemented.";
+ }
+
+ void DeactivateDirectoryDataType(ModelType type) override {
+ NOTREACHED() << "Not implemented.";
+ }
+
+ void ActivateNonBlockingDataType(
+ ModelType type,
+ std::unique_ptr<ActivationContext> activation_context) override {
+ DCHECK_EQ(kTestModelType, type);
+ DCHECK(!processor_);
+ processor_ = std::move(activation_context->type_processor);
+ processor_->ConnectSync(nullptr);
+ }
+
+ void DeactivateNonBlockingDataType(ModelType type) override {
+ DCHECK_EQ(kTestModelType, type);
+ DCHECK(processor_);
+ processor_->DisconnectSync();
+ processor_.reset();
+ }
+
+ private:
+ std::unique_ptr<ModelTypeProcessor> processor_;
+};
+
+} // namespace
+
+class ModelTypeControllerTest : public testing::Test, public FakeSyncClient {
+ public:
+ ModelTypeControllerTest()
+ : model_thread_("modelthread"), sync_prefs_(GetPrefService()) {}
+
+ void SetUp() override {
+ model_thread_.Start();
+ InitializeModelTypeService();
+ controller_.reset(new ModelTypeController(
+ kTestModelType, base::Closure(), this, model_thread_.task_runner()));
+ }
+
+ void TearDown() override {
+ ClearModelTypeService();
+ PumpUIThread();
+ }
+
+ base::WeakPtr<ModelTypeService> GetModelTypeServiceForType(
+ ModelType type) override {
+ return service_->AsWeakPtr();
+ }
+
+ void LoadModels() {
+ controller_->LoadModels(base::Bind(&ModelTypeControllerTest::LoadModelsDone,
+ base::Unretained(this)));
+ }
+
+ void RegisterWithBackend() { controller_->RegisterWithBackend(&configurer_); }
+
+ void StartAssociating() {
+ controller_->StartAssociating(base::Bind(
+ &ModelTypeControllerTest::AssociationDone, base::Unretained(this)));
+ // The callback is expected to be promptly called.
+ EXPECT_TRUE(association_callback_called_);
+ }
+
+ void DeactivateDataTypeAndStop() {
+ controller_->DeactivateDataType(&configurer_);
+ controller_->Stop();
+ }
+
+ // These threads can ping-pong for a bit so we run the model thread twice.
+ void RunAllTasks() {
+ PumpModelThread();
+ PumpUIThread();
+ PumpModelThread();
+ }
+
+ // Runs any tasks posted on the model thread.
+ void PumpModelThread() {
+ base::RunLoop run_loop;
+ model_thread_.task_runner()->PostTaskAndReply(
+ FROM_HERE, base::Bind(&base::DoNothing), run_loop.QuitClosure());
+ run_loop.Run();
+ }
+
+ void ExpectProcessorConnected(bool is_connected) {
+ if (model_thread_.task_runner()->BelongsToCurrentThread()) {
+ DCHECK(processor_);
+ EXPECT_EQ(is_connected, processor_->is_connected());
+ } else {
+ model_thread_.task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&ModelTypeControllerTest::ExpectProcessorConnected,
+ base::Unretained(this), is_connected));
+ PumpModelThread();
+ }
+ }
+
+ void ExpectHasChangeProcessor(bool has_processor) {
+ if (model_thread_.task_runner()->BelongsToCurrentThread()) {
+ DCHECK(service_);
+ EXPECT_EQ(has_processor, !!service_->change_processor());
+ } else {
+ model_thread_.task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&ModelTypeControllerTest::ExpectHasChangeProcessor,
+ base::Unretained(this), has_processor));
+ PumpModelThread();
+ }
+ }
+
+ SyncPrefs* sync_prefs() { return &sync_prefs_; }
+ DataTypeController* controller() { return controller_.get(); }
+ int load_models_done_count() { return load_models_done_count_; }
+ int disable_sync_call_count() { return disable_sync_call_count_; }
+ SyncError load_models_last_error() { return load_models_last_error_; }
+
+ private:
+ // Runs any tasks posted on the UI thread.
+ void PumpUIThread() { base::RunLoop().RunUntilIdle(); }
+
+ void LoadModelsDone(ModelType type, const SyncError& error) {
+ load_models_done_count_++;
+ load_models_last_error_ = error;
+ }
+
+ void AssociationDone(DataTypeController::ConfigureResult result,
+ const SyncMergeResult& local_merge_result,
+ const SyncMergeResult& syncer_merge_result) {
+ EXPECT_FALSE(association_callback_called_);
+ EXPECT_EQ(DataTypeController::OK, result);
+ association_callback_called_ = true;
+ }
+
+ std::unique_ptr<ModelTypeChangeProcessor> CreateProcessor(
+ ModelType type,
+ ModelTypeService* service) {
+ std::unique_ptr<TestModelTypeProcessor> processor =
+ base::MakeUnique<TestModelTypeProcessor>(&disable_sync_call_count_);
+ processor_ = processor.get();
+ return std::move(processor);
+ }
+
+ void InitializeModelTypeService() {
+ if (model_thread_.task_runner()->BelongsToCurrentThread()) {
+ service_.reset(new StubModelTypeService(base::Bind(
+ &ModelTypeControllerTest::CreateProcessor, base::Unretained(this))));
+ } else {
+ model_thread_.task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&ModelTypeControllerTest::InitializeModelTypeService,
+ base::Unretained(this)));
+ PumpModelThread();
+ }
+ }
+
+ void ClearModelTypeService() {
+ if (model_thread_.task_runner()->BelongsToCurrentThread()) {
+ service_.reset();
+ } else {
+ model_thread_.task_runner()->PostTask(
+ FROM_HERE, base::Bind(&ModelTypeControllerTest::ClearModelTypeService,
+ base::Unretained(this)));
+ PumpModelThread();
+ }
+ }
+
+ int load_models_done_count_ = 0;
+ int disable_sync_call_count_ = 0;
+ bool association_callback_called_ = false;
+ SyncError load_models_last_error_;
+
+ base::MessageLoop message_loop_;
+ base::Thread model_thread_;
+ SyncPrefs sync_prefs_;
+ TestBackendDataTypeConfigurer configurer_;
+ std::unique_ptr<StubModelTypeService> service_;
+ std::unique_ptr<ModelTypeController> controller_;
+ TestModelTypeProcessor* processor_;
+};
+
+TEST_F(ModelTypeControllerTest, InitialState) {
+ EXPECT_EQ(kTestModelType, controller()->type());
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, controller()->state());
+}
+
+TEST_F(ModelTypeControllerTest, LoadModelsOnBackendThread) {
+ LoadModels();
+ EXPECT_EQ(DataTypeController::MODEL_STARTING, controller()->state());
+ RunAllTasks();
+ EXPECT_EQ(DataTypeController::MODEL_LOADED, controller()->state());
+ EXPECT_EQ(1, load_models_done_count());
+ EXPECT_FALSE(load_models_last_error().IsSet());
+ ExpectProcessorConnected(false);
+}
+
+TEST_F(ModelTypeControllerTest, LoadModelsTwice) {
+ LoadModels();
+ RunAllTasks();
+ LoadModels();
+ EXPECT_EQ(DataTypeController::MODEL_LOADED, controller()->state());
+ // The second LoadModels call should set the error.
+ EXPECT_TRUE(load_models_last_error().IsSet());
+}
+
+TEST_F(ModelTypeControllerTest, ActivateDataTypeOnBackendThread) {
+ LoadModels();
+ RunAllTasks();
+ EXPECT_EQ(DataTypeController::MODEL_LOADED, controller()->state());
+ RegisterWithBackend();
+ ExpectProcessorConnected(true);
+
+ StartAssociating();
+ EXPECT_EQ(DataTypeController::RUNNING, controller()->state());
+}
+
+TEST_F(ModelTypeControllerTest, Stop) {
+ LoadModels();
+ RunAllTasks();
+ RegisterWithBackend();
+ ExpectProcessorConnected(true);
+
+ StartAssociating();
+
+ DeactivateDataTypeAndStop();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, controller()->state());
+}
+
+// Test emulates normal browser shutdown. Ensures that DisableSync is not
+// called.
+TEST_F(ModelTypeControllerTest, StopWhenDatatypeEnabled) {
+ // Enable datatype through preferences.
+ sync_prefs()->SetFirstSetupComplete();
+ sync_prefs()->SetKeepEverythingSynced(true);
+
+ LoadModels();
+ RunAllTasks();
+ StartAssociating();
+
+ controller()->Stop();
+ RunAllTasks();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, controller()->state());
+ // Ensure that DisableSync is not called and service still has valid change
+ // processor.
+ EXPECT_EQ(0, disable_sync_call_count());
+ ExpectHasChangeProcessor(true);
+ ExpectProcessorConnected(false);
+}
+
+// Test emulates scenario when user disables datatype. DisableSync should be
+// called.
+TEST_F(ModelTypeControllerTest, StopWhenDatatypeDisabled) {
+ // Enable datatype through preferences.
+ sync_prefs()->SetFirstSetupComplete();
+ sync_prefs()->SetKeepEverythingSynced(true);
+ LoadModels();
+ RunAllTasks();
+ StartAssociating();
+
+ // Disable datatype through preferences.
+ sync_prefs()->SetKeepEverythingSynced(false);
+ sync_prefs()->SetPreferredDataTypes(ModelTypeSet(kTestModelType),
+ ModelTypeSet());
+
+ controller()->Stop();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, controller()->state());
+ // Ensure that DisableSync is called and change processor is reset.
+ PumpModelThread();
+ EXPECT_EQ(1, disable_sync_call_count());
+ ExpectHasChangeProcessor(false);
+}
+
+// Test emulates disabling sync by signing out. DisableSync should be called.
+TEST_F(ModelTypeControllerTest, StopWithInitialSyncPrefs) {
+ // Enable datatype through preferences.
+ sync_prefs()->SetFirstSetupComplete();
+ sync_prefs()->SetKeepEverythingSynced(true);
+ LoadModels();
+ RunAllTasks();
+ StartAssociating();
+
+ // Clearing preferences emulates signing out.
+ sync_prefs()->ClearPreferences();
+ controller()->Stop();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, controller()->state());
+ // Ensure that DisableSync is called and change processor is reset.
+ PumpModelThread();
+ EXPECT_EQ(1, disable_sync_call_count());
+ ExpectHasChangeProcessor(false);
+}
+
+// Test emulates disabling sync when datatype is not loaded yet. DisableSync
+// should not be called as service is potentially not ready to handle it.
+TEST_F(ModelTypeControllerTest, StopBeforeLoadModels) {
+ // Enable datatype through preferences.
+ sync_prefs()->SetFirstSetupComplete();
+ sync_prefs()->SetKeepEverythingSynced(true);
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, controller()->state());
+
+ // Clearing preferences emulates signing out.
+ sync_prefs()->ClearPreferences();
+ controller()->Stop();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, controller()->state());
+ // Ensure that DisableSync is not called.
+ EXPECT_EQ(0, disable_sync_call_count());
+ // A change processor was never created.
+ ExpectHasChangeProcessor(false);
+}
+
+} // namespace syncer
« no previous file with comments | « components/sync/driver/model_type_controller.cc ('k') | components/sync/driver/non_blocking_data_type_controller.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698