summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorskrul@chromium.org <skrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-10 20:13:43 +0000
committerskrul@chromium.org <skrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-10 20:13:43 +0000
commit4aea04a6cd871857af72c351a502f21aa142de9e (patch)
treec67020ad646a5b4056036fbe2a7529917502ffb7
parent7a5b2d8af981cb861f0b555f2b15895165a02369 (diff)
downloadchromium_src-4aea04a6cd871857af72c351a502f21aa142de9e.zip
chromium_src-4aea04a6cd871857af72c351a502f21aa142de9e.tar.gz
chromium_src-4aea04a6cd871857af72c351a502f21aa142de9e.tar.bz2
First stab at a DataTypeController.
This is my first stab at a DataTypeController, plus a BookmarkDataTypeController implementation. It is not fully wired into the PSS yet :) Review URL: http://codereview.chromium.org/545074 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@38655 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/bookmarks/bookmark_model.h2
-rw-r--r--chrome/browser/profile.cc7
-rw-r--r--chrome/browser/profile.h2
-rw-r--r--chrome/browser/sync/glue/bookmark_change_processor.cc3
-rw-r--r--chrome/browser/sync/glue/bookmark_change_processor.h7
-rw-r--r--chrome/browser/sync/glue/bookmark_data_type_controller.cc142
-rw-r--r--chrome/browser/sync/glue/bookmark_data_type_controller.h86
-rw-r--r--chrome/browser/sync/glue/bookmark_data_type_controller_unittest.cc217
-rw-r--r--chrome/browser/sync/glue/change_processor_mock.h29
-rw-r--r--chrome/browser/sync/glue/data_type_controller.h81
-rw-r--r--chrome/browser/sync/glue/model_associator_mock.h23
-rw-r--r--chrome/browser/sync/glue/sync_backend_host.cc51
-rw-r--r--chrome/browser/sync/glue/sync_backend_host.h19
-rw-r--r--chrome/browser/sync/profile_sync_factory.h45
-rw-r--r--chrome/browser/sync/profile_sync_factory_impl.cc42
-rw-r--r--chrome/browser/sync/profile_sync_factory_impl.h31
-rw-r--r--chrome/browser/sync/profile_sync_factory_impl_unittest.cc54
-rw-r--r--chrome/browser/sync/profile_sync_factory_mock.cc30
-rw-r--r--chrome/browser/sync/profile_sync_factory_mock.h36
-rw-r--r--chrome/browser/sync/profile_sync_service.cc199
-rw-r--r--chrome/browser/sync/profile_sync_service.h78
-rw-r--r--chrome/browser/sync/profile_sync_service_mock.h44
-rw-r--r--chrome/browser/sync/profile_sync_service_unittest.cc92
-rwxr-xr-xchrome/chrome_browser.gypi7
-rwxr-xr-xchrome/chrome_tests.gypi10
-rw-r--r--chrome/common/chrome_switches.cc10
-rw-r--r--chrome/common/chrome_switches.h2
27 files changed, 1143 insertions, 206 deletions
diff --git a/chrome/browser/bookmarks/bookmark_model.h b/chrome/browser/bookmarks/bookmark_model.h
index 7790790..312d04c 100644
--- a/chrome/browser/bookmarks/bookmark_model.h
+++ b/chrome/browser/bookmarks/bookmark_model.h
@@ -237,7 +237,7 @@ class BookmarkModel : public NotificationObserver, public BookmarkService {
void SetURL(const BookmarkNode* node, const GURL& url);
// Returns true if the model finished loading.
- bool IsLoaded() { return loaded_; }
+ virtual bool IsLoaded() { return loaded_; }
// Returns the set of nodes with the specified URL.
void GetNodesByURL(const GURL& url, std::vector<const BookmarkNode*>* nodes);
diff --git a/chrome/browser/profile.cc b/chrome/browser/profile.cc
index 63b8c1d..a1594b2 100644
--- a/chrome/browser/profile.cc
+++ b/chrome/browser/profile.cc
@@ -46,6 +46,7 @@
#include "chrome/browser/sessions/tab_restore_service.h"
#include "chrome/browser/ssl/ssl_host_state.h"
#include "chrome/browser/sync/profile_sync_service.h"
+#include "chrome/browser/sync/profile_sync_factory_impl.h"
#include "chrome/browser/thumbnail_store.h"
#include "chrome/browser/visitedlink_master.h"
#include "chrome/browser/visitedlink_event_listener.h"
@@ -1317,6 +1318,10 @@ ProfileSyncService* ProfileImpl::GetProfileSyncService() {
}
void ProfileImpl::InitSyncService() {
- sync_service_.reset(new ProfileSyncService(this));
+ profile_sync_factory_.reset(
+ new ProfileSyncFactoryImpl(this,
+ CommandLine::ForCurrentProcess()));
+ sync_service_.reset(
+ profile_sync_factory_->CreateProfileSyncService());
sync_service_->Initialize();
}
diff --git a/chrome/browser/profile.h b/chrome/browser/profile.h
index 3a5ff60..eaa05b6 100644
--- a/chrome/browser/profile.h
+++ b/chrome/browser/profile.h
@@ -51,6 +51,7 @@ class PasswordStore;
class PersonalDataManager;
class PrefService;
class ProfileSyncService;
+class ProfileSyncFactory;
class SearchVersusNavigateClassifier;
class SessionService;
class SpellCheckHost;
@@ -538,6 +539,7 @@ class ProfileImpl : public Profile,
scoped_refptr<WebResourceService> web_resource_service_;
scoped_ptr<NTPResourceCache> ntp_resource_cache_;
+ scoped_ptr<ProfileSyncFactory> profile_sync_factory_;
scoped_ptr<ProfileSyncService> sync_service_;
scoped_refptr<ChromeURLRequestContextGetter> request_context_;
diff --git a/chrome/browser/sync/glue/bookmark_change_processor.cc b/chrome/browser/sync/glue/bookmark_change_processor.cc
index 2bf9516..d41ec3e 100644
--- a/chrome/browser/sync/glue/bookmark_change_processor.cc
+++ b/chrome/browser/sync/glue/bookmark_change_processor.cc
@@ -18,10 +18,11 @@
namespace browser_sync {
BookmarkChangeProcessor::BookmarkChangeProcessor(
+ BookmarkModelAssociator* model_associator,
UnrecoverableErrorHandler* error_handler)
: ChangeProcessor(error_handler),
bookmark_model_(NULL),
- model_associator_(NULL) {
+ model_associator_(model_associator) {
}
void BookmarkChangeProcessor::StartImpl(Profile* profile) {
diff --git a/chrome/browser/sync/glue/bookmark_change_processor.h b/chrome/browser/sync/glue/bookmark_change_processor.h
index 0847919..5ae1811 100644
--- a/chrome/browser/sync/glue/bookmark_change_processor.h
+++ b/chrome/browser/sync/glue/bookmark_change_processor.h
@@ -25,13 +25,10 @@ namespace browser_sync {
class BookmarkChangeProcessor : public BookmarkModelObserver,
public ChangeProcessor {
public:
- explicit BookmarkChangeProcessor(UnrecoverableErrorHandler* error_handler);
+ explicit BookmarkChangeProcessor(BookmarkModelAssociator* model_associator,
+ UnrecoverableErrorHandler* error_handler);
virtual ~BookmarkChangeProcessor() {}
- void set_model_associator(BookmarkModelAssociator* model_associator) {
- model_associator_ = model_associator;
- }
-
// BookmarkModelObserver implementation.
// BookmarkModel -> sync_api model change application.
virtual void Loaded(BookmarkModel* model) { NOTREACHED(); }
diff --git a/chrome/browser/sync/glue/bookmark_data_type_controller.cc b/chrome/browser/sync/glue/bookmark_data_type_controller.cc
new file mode 100644
index 0000000..b37c899
--- /dev/null
+++ b/chrome/browser/sync/glue/bookmark_data_type_controller.cc
@@ -0,0 +1,142 @@
+// Copyright (c) 2009 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 "base/histogram.h"
+#include "base/logging.h"
+#include "base/time.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/sync/glue/bookmark_change_processor.h"
+#include "chrome/browser/sync/glue/bookmark_data_type_controller.h"
+#include "chrome/browser/sync/glue/bookmark_model_associator.h"
+#include "chrome/browser/sync/profile_sync_service.h"
+#include "chrome/browser/sync/profile_sync_factory.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/notification_type.h"
+
+namespace browser_sync {
+
+BookmarkDataTypeController::BookmarkDataTypeController(
+ ProfileSyncFactory* profile_sync_factory,
+ Profile* profile,
+ ProfileSyncService* sync_service)
+ : profile_sync_factory_(profile_sync_factory),
+ profile_(profile),
+ sync_service_(sync_service),
+ state_(NOT_RUNNING),
+ merge_allowed_(false) {
+ DCHECK(profile_sync_factory);
+ DCHECK(profile);
+ DCHECK(sync_service);
+}
+
+BookmarkDataTypeController::~BookmarkDataTypeController() {
+}
+
+void BookmarkDataTypeController::Start(bool merge_allowed,
+ StartCallback* start_callback) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ if (state_ != NOT_RUNNING) {
+ start_callback->Run(BUSY);
+ delete start_callback;
+ return;
+ }
+
+ start_callback_.reset(start_callback);
+ merge_allowed_ = merge_allowed;
+
+ if (!enabled()) {
+ FinishStart(NOT_ENABLED);
+ return;
+ }
+
+ state_ = MODEL_STARTING;
+
+ // If the bookmarks model is loaded, continue with association.
+ BookmarkModel* bookmark_model = profile_->GetBookmarkModel();
+ if (bookmark_model && bookmark_model->IsLoaded()) {
+ Associate();
+ return;
+ }
+
+ // Add an observer and continue when the bookmarks model is loaded.
+ registrar_.Add(this, NotificationType::BOOKMARK_MODEL_LOADED,
+ Source<Profile>(sync_service_->profile()));
+}
+
+void BookmarkDataTypeController::Stop() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ // If Stop() is called while Start() is waiting for the bookmark
+ // model to load, abort the start.
+ if (state_ == MODEL_STARTING) {
+ FinishStart(ABORTED);
+ }
+
+ registrar_.RemoveAll();
+ if (change_processor_ != NULL)
+ sync_service_->DeactivateDataType(this, change_processor_.get());
+
+ if (model_associator_ != NULL)
+ model_associator_->DisassociateModels();
+
+ change_processor_.reset();
+ model_associator_.reset();
+
+ state_ = NOT_RUNNING;
+ merge_allowed_ = false;
+}
+
+void BookmarkDataTypeController::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK_EQ(NotificationType::BOOKMARK_MODEL_LOADED, type.value);
+ registrar_.RemoveAll();
+ Associate();
+}
+
+void BookmarkDataTypeController::Associate() {
+ DCHECK_EQ(state_, MODEL_STARTING);
+ state_ = ASSOCIATING;
+
+ ProfileSyncFactory::BookmarkComponents bookmark_components =
+ profile_sync_factory_->CreateBookmarkComponents(sync_service_);
+ model_associator_.reset(bookmark_components.model_associator);
+ change_processor_.reset(bookmark_components.change_processor);
+
+ bool needs_merge = model_associator_->ChromeModelHasUserCreatedNodes() &&
+ model_associator_->SyncModelHasUserCreatedNodes();
+ if (needs_merge && !merge_allowed_) {
+ model_associator_.reset();
+ change_processor_.reset();
+ state_ = NOT_RUNNING;
+ FinishStart(NEEDS_MERGE);
+ return;
+ }
+
+ base::TimeTicks start_time = base::TimeTicks::Now();
+ bool first_run = !model_associator_->SyncModelHasUserCreatedNodes();
+ bool merge_success = model_associator_->AssociateModels();
+ UMA_HISTOGRAM_TIMES("Sync.BookmarkAssociationTime",
+ base::TimeTicks::Now() - start_time);
+ if (!merge_success) {
+ model_associator_.reset();
+ change_processor_.reset();
+ state_ = NOT_RUNNING;
+ FinishStart(ASSOCIATION_FAILED);
+ return;
+ }
+
+ sync_service_->ActivateDataType(this, change_processor_.get());
+ state_ = RUNNING;
+ FinishStart(first_run ? OK_FIRST_RUN : OK);
+}
+
+void BookmarkDataTypeController::FinishStart(StartResult result) {
+ start_callback_->Run(result);
+ start_callback_.reset();
+}
+
+} // namespace browser_sync
diff --git a/chrome/browser/sync/glue/bookmark_data_type_controller.h b/chrome/browser/sync/glue/bookmark_data_type_controller.h
new file mode 100644
index 0000000..f0719de
--- /dev/null
+++ b/chrome/browser/sync/glue/bookmark_data_type_controller.h
@@ -0,0 +1,86 @@
+// Copyright (c) 2009 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.
+
+#ifndef CHROME_BROWSER_SYNC_GLUE_BOOKMARK_DATA_TYPE_CONTROLLER_H__
+#define CHROME_BROWSER_SYNC_GLUE_BOOKMARK_DATA_TYPE_CONTROLLER_H__
+
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/sync/glue/data_type_controller.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_observer.h"
+
+class NotificationDetails;
+class NotificationType;
+class NotificationSource;
+class Profile;
+class ProfileSyncService;
+class ProfileSyncFactory;
+
+namespace browser_sync {
+
+class AssociatorInterface;
+class ChangeProcessor;
+
+// A class that manages the startup and shutdown of bookmark sync.
+class BookmarkDataTypeController : public DataTypeController,
+ public NotificationObserver {
+ public:
+ BookmarkDataTypeController(
+ ProfileSyncFactory* profile_sync_factory,
+ Profile* profile,
+ ProfileSyncService* sync_service);
+ virtual ~BookmarkDataTypeController();
+
+ // DataTypeController interface.
+ virtual void Start(bool merge_allowed, StartCallback* start_callback);
+
+ virtual void Stop();
+
+ virtual bool enabled() {
+ return true;
+ }
+
+ virtual syncable::ModelType type() {
+ return syncable::BOOKMARKS;
+ }
+
+ virtual browser_sync::ModelSafeGroup model_safe_group() {
+ return browser_sync::GROUP_UI;
+ }
+
+ virtual State state() {
+ return state_;
+ }
+
+ // NotificationObserver interface.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ private:
+ // Runs model association and change processor registration.
+ void Associate();
+
+ // Helper method to run the stashed start callback with a given result.
+ void FinishStart(StartResult result);
+
+ ProfileSyncFactory* profile_sync_factory_;
+ Profile* profile_;
+ ProfileSyncService* sync_service_;
+
+ State state_;
+ bool merge_allowed_;
+
+ scoped_ptr<StartCallback> start_callback_;
+ scoped_ptr<AssociatorInterface> model_associator_;
+ scoped_ptr<ChangeProcessor> change_processor_;
+ NotificationRegistrar registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(BookmarkDataTypeController);
+};
+
+} // namespace browser_sync
+
+#endif // CHROME_BROWSER_SYNC_GLUE_BOOKMARK_DATA_TYPE_CONTROLLER_H__
diff --git a/chrome/browser/sync/glue/bookmark_data_type_controller_unittest.cc b/chrome/browser/sync/glue/bookmark_data_type_controller_unittest.cc
new file mode 100644
index 0000000..26f025b
--- /dev/null
+++ b/chrome/browser/sync/glue/bookmark_data_type_controller_unittest.cc
@@ -0,0 +1,217 @@
+// Copyright (c) 2010 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 "testing/gtest/include/gtest/gtest.h"
+
+#include "base/message_loop.h"
+#include "base/scoped_ptr.h"
+#include "base/task.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/sync/glue/bookmark_data_type_controller.h"
+#include "chrome/browser/sync/glue/change_processor_mock.h"
+#include "chrome/browser/sync/glue/model_associator_mock.h"
+#include "chrome/browser/sync/profile_sync_factory_mock.h"
+#include "chrome/browser/sync/profile_sync_service_mock.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/notification_type.h"
+#include "chrome/test/testing_profile.h"
+
+using browser_sync::BookmarkDataTypeController;
+using browser_sync::ChangeProcessorMock;
+using browser_sync::DataTypeController;
+using browser_sync::ModelAssociatorMock;
+using testing::_;
+using testing::Return;
+
+class StartCallback {
+ public:
+ MOCK_METHOD1(Run, void(DataTypeController::StartResult result));
+};
+
+class ProfileMock : public TestingProfile {
+ public:
+ MOCK_METHOD0(GetBookmarkModel, BookmarkModel*());
+};
+
+class BookmarkModelMock : public BookmarkModel {
+ public:
+ BookmarkModelMock() : BookmarkModel(NULL) {}
+ MOCK_METHOD0(IsLoaded, bool());
+};
+
+class BookmarkDataTypeControllerTest : public testing::Test {
+ public:
+ BookmarkDataTypeControllerTest()
+ : ui_thread_(ChromeThread::UI, &message_loop_) {}
+
+ virtual void SetUp() {
+ model_associator_ = new ModelAssociatorMock();
+ change_processor_ = new ChangeProcessorMock();
+ profile_sync_factory_.reset(
+ new ProfileSyncFactoryMock(model_associator_,
+ change_processor_));
+ bookmark_dtc_.reset(
+ new BookmarkDataTypeController(profile_sync_factory_.get(),
+ &profile_,
+ &service_));
+ }
+
+ protected:
+ void SetStartExpectations() {
+ EXPECT_CALL(profile_, GetBookmarkModel()).
+ WillOnce(Return(&bookmark_model_));
+ EXPECT_CALL(bookmark_model_, IsLoaded()).WillRepeatedly(Return(true));
+ }
+
+ void SetAssociateExpectations() {
+ EXPECT_CALL(*profile_sync_factory_, CreateBookmarkComponents(_));
+ EXPECT_CALL(*model_associator_, ChromeModelHasUserCreatedNodes()).
+ WillRepeatedly(Return(false));
+ EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes()).
+ WillRepeatedly(Return(true));
+ EXPECT_CALL(*model_associator_, AssociateModels()).
+ WillRepeatedly(Return(true));
+ EXPECT_CALL(service_, ActivateDataType(_, _));
+ }
+
+ void SetStopExpectations() {
+ EXPECT_CALL(service_, DeactivateDataType(_, _));
+ EXPECT_CALL(*model_associator_, DisassociateModels());
+ }
+
+ MessageLoopForUI message_loop_;
+ ChromeThread ui_thread_;
+ scoped_ptr<BookmarkDataTypeController> bookmark_dtc_;
+ scoped_ptr<ProfileSyncFactoryMock> profile_sync_factory_;
+ ProfileMock profile_;
+ BookmarkModelMock bookmark_model_;
+ ProfileSyncServiceMock service_;
+ ModelAssociatorMock* model_associator_;
+ ChangeProcessorMock* change_processor_;
+ StartCallback start_callback_;
+};
+
+TEST_F(BookmarkDataTypeControllerTest, StartBookmarkModelReady) {
+ SetStartExpectations();
+ SetAssociateExpectations();
+
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, bookmark_dtc_->state());
+
+ EXPECT_CALL(start_callback_, Run(DataTypeController::OK));
+ bookmark_dtc_->Start(false,
+ NewCallback(&start_callback_, &StartCallback::Run));
+ EXPECT_EQ(DataTypeController::RUNNING, bookmark_dtc_->state());
+}
+
+TEST_F(BookmarkDataTypeControllerTest, StartBookmarkModelNotReady) {
+ SetStartExpectations();
+ EXPECT_CALL(bookmark_model_, IsLoaded()).WillRepeatedly(Return(false));
+ SetAssociateExpectations();
+
+ EXPECT_CALL(start_callback_, Run(DataTypeController::OK));
+ bookmark_dtc_->Start(false,
+ NewCallback(&start_callback_, &StartCallback::Run));
+ EXPECT_EQ(DataTypeController::MODEL_STARTING, bookmark_dtc_->state());
+
+ // Send the notification that the bookmark model has started.
+ NotificationService::current()->Notify(
+ NotificationType::BOOKMARK_MODEL_LOADED,
+ Source<Profile>(&profile_),
+ NotificationService::NoDetails());
+ EXPECT_EQ(DataTypeController::RUNNING, bookmark_dtc_->state());
+}
+
+TEST_F(BookmarkDataTypeControllerTest, StartFirstRun) {
+ SetStartExpectations();
+ SetAssociateExpectations();
+ EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes()).
+ WillRepeatedly(Return(false));
+ EXPECT_CALL(start_callback_, Run(DataTypeController::OK_FIRST_RUN));
+ bookmark_dtc_->Start(false,
+ NewCallback(&start_callback_, &StartCallback::Run));
+}
+
+TEST_F(BookmarkDataTypeControllerTest, StartBusy) {
+ SetStartExpectations();
+ EXPECT_CALL(bookmark_model_, IsLoaded()).WillRepeatedly(Return(false));
+
+ EXPECT_CALL(start_callback_, Run(DataTypeController::BUSY));
+ bookmark_dtc_->Start(false,
+ NewCallback(&start_callback_, &StartCallback::Run));
+ bookmark_dtc_->Start(false,
+ NewCallback(&start_callback_, &StartCallback::Run));
+}
+
+TEST_F(BookmarkDataTypeControllerTest, StartNeedsMerge) {
+ SetStartExpectations();
+ EXPECT_CALL(*profile_sync_factory_, CreateBookmarkComponents(_));
+ EXPECT_CALL(*model_associator_, ChromeModelHasUserCreatedNodes()).
+ WillRepeatedly(Return(true));
+ EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes()).
+ WillRepeatedly(Return(true));
+
+ EXPECT_CALL(start_callback_, Run(DataTypeController::NEEDS_MERGE));
+ bookmark_dtc_->Start(false,
+ NewCallback(&start_callback_, &StartCallback::Run));
+}
+
+TEST_F(BookmarkDataTypeControllerTest, StartMergeAllowed) {
+ SetStartExpectations();
+ SetAssociateExpectations();
+ EXPECT_CALL(*model_associator_, ChromeModelHasUserCreatedNodes()).
+ WillRepeatedly(Return(true));
+ EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes()).
+ WillRepeatedly(Return(true));
+
+ EXPECT_CALL(start_callback_, Run(DataTypeController::OK));
+ bookmark_dtc_->Start(true,
+ NewCallback(&start_callback_, &StartCallback::Run));
+}
+
+TEST_F(BookmarkDataTypeControllerTest, StartAssociationFailed) {
+ SetStartExpectations();
+ // Set up association to fail.
+ EXPECT_CALL(*profile_sync_factory_, CreateBookmarkComponents(_));
+ EXPECT_CALL(*model_associator_, ChromeModelHasUserCreatedNodes()).
+ WillRepeatedly(Return(false));
+ EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes()).
+ WillRepeatedly(Return(true));
+ EXPECT_CALL(*model_associator_, AssociateModels()).
+ WillRepeatedly(Return(false));
+
+ EXPECT_CALL(start_callback_, Run(DataTypeController::ASSOCIATION_FAILED));
+ bookmark_dtc_->Start(true,
+ NewCallback(&start_callback_, &StartCallback::Run));
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, bookmark_dtc_->state());
+}
+
+TEST_F(BookmarkDataTypeControllerTest, StartAborted) {
+ SetStartExpectations();
+ EXPECT_CALL(bookmark_model_, IsLoaded()).WillRepeatedly(Return(false));
+
+ EXPECT_CALL(start_callback_, Run(DataTypeController::ABORTED));
+ bookmark_dtc_->Start(false,
+ NewCallback(&start_callback_, &StartCallback::Run));
+ bookmark_dtc_->Stop();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, bookmark_dtc_->state());
+}
+
+TEST_F(BookmarkDataTypeControllerTest, Stop) {
+ SetStartExpectations();
+ SetAssociateExpectations();
+ SetStopExpectations();
+
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, bookmark_dtc_->state());
+
+ EXPECT_CALL(start_callback_, Run(DataTypeController::OK));
+ bookmark_dtc_->Start(false,
+ NewCallback(&start_callback_, &StartCallback::Run));
+ EXPECT_EQ(DataTypeController::RUNNING, bookmark_dtc_->state());
+ bookmark_dtc_->Stop();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, bookmark_dtc_->state());
+
+}
diff --git a/chrome/browser/sync/glue/change_processor_mock.h b/chrome/browser/sync/glue/change_processor_mock.h
new file mode 100644
index 0000000..42bad36
--- /dev/null
+++ b/chrome/browser/sync/glue/change_processor_mock.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2010 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.
+
+#ifndef CHROME_BROWSER_SYNC_GLUE_CHANGE_PROCESSOR_MOCK_H__
+#define CHROME_BROWSER_SYNC_GLUE_CHANGE_PROCESSOR_MOCK_H__
+
+#include "chrome/browser/profile.h"
+#include "chrome/browser/sync/engine/syncapi.h"
+#include "chrome/browser/sync/glue/change_processor.h"
+#include "chrome/browser/sync/syncable/syncable.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace browser_sync {
+
+class ChangeProcessorMock : public ChangeProcessor {
+ public:
+ ChangeProcessorMock() : ChangeProcessor(NULL) {}
+ MOCK_METHOD3(ApplyChangesFromSyncModel,
+ void(const sync_api::BaseTransaction* trans,
+ const sync_api::SyncManager::ChangeRecord* changes,
+ int change_count));
+ MOCK_METHOD1(StartImpl, void(Profile* profile));
+ MOCK_METHOD0(StopImpl, void());
+};
+
+} // namespace browser_sync
+
+#endif // CHROME_BROWSER_SYNC_GLUE_CHANGE_PROCESSOR_MOCK_H__
diff --git a/chrome/browser/sync/glue/data_type_controller.h b/chrome/browser/sync/glue/data_type_controller.h
new file mode 100644
index 0000000..62709ff
--- /dev/null
+++ b/chrome/browser/sync/glue/data_type_controller.h
@@ -0,0 +1,81 @@
+// Copyright (c) 2009 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.
+
+#ifndef CHROME_BROWSER_SYNC_GLUE_DATA_TYPE_CONTROLLER_H__
+#define CHROME_BROWSER_SYNC_GLUE_DATA_TYPE_CONTROLLER_H__
+
+#include "base/task.h"
+#include "chrome/browser/sync/engine/model_safe_worker.h"
+#include "chrome/browser/sync/syncable/model_type.h"
+
+namespace browser_sync {
+
+class DataTypeController {
+ public:
+ enum State {
+ NOT_RUNNING, // The controller has never been started or has
+ // previously been stopped. Must be in this state to start.
+ MODEL_STARTING, // The controller is waiting on dependent services
+ // that need to be available before model
+ // association.
+ ASSOCIATING, // Model association is in progress.
+ RUNNING, // The controller is running and the data type is
+ // in sync with the cloud.
+ STOPPING // The controller is in the process of stopping
+ // and is waiting for dependent services to stop.
+ };
+
+ enum StartResult {
+ OK, // The data type has started normally.
+ OK_FIRST_RUN, // Same as OK, but sent on first successful
+ // start for this type for this user as
+ // determined by cloud state.
+ BUSY, // Start() was called while already in progress.
+ NOT_ENABLED, // This data type is not enabled for the current user.
+ NEEDS_MERGE, // Can't start without explicit permission to
+ // perform a data merge. Re-starting with
+ // merge_allowed = true will allow this data
+ // type to start.
+ ASSOCIATION_FAILED, // An error occurred during model association.
+ ABORTED // Start was aborted by calling Stop().
+ };
+
+ typedef Callback1<StartResult>::Type StartCallback;
+
+ virtual ~DataTypeController() {}
+
+ // Begins asynchronous start up of this data type. Start up will
+ // wait for all other dependent services to be available, then
+ // proceed with model association and then change processor
+ // activation. Upon completion, the start_callback will be invoked
+ // on the UI thread. The merge_allowed parameter gives the data
+ // type permission to perform a data merge at start time. See the
+ // StartResult enum above for details on the possible start results.
+ virtual void Start(bool merge_allowed, StartCallback* start_callback) = 0;
+
+ // Synchronously stops the data type. If called after Start() is
+ // called but before the start callback is called, the start is
+ // aborted and the start callback is invoked with the ABORTED start
+ // result.
+ virtual void Stop() = 0;
+
+ // Returns true if the user has indicated that they want this data
+ // type to be enabled.
+ virtual bool enabled() = 0;
+
+ // Unique model type for this data type controller.
+ virtual syncable::ModelType type() = 0;
+
+ // The model safe group of this data type. This should reflect the
+ // thread that should be used to modify the data type's native
+ // model.
+ virtual browser_sync::ModelSafeGroup model_safe_group() = 0;
+
+ // Current state of the data type controller.
+ virtual State state() = 0;
+};
+
+} // namespace browser_sync
+
+#endif // CHROME_BROWSER_SYNC_GLUE_DATA_TYPE_CONTROLLER_H__
diff --git a/chrome/browser/sync/glue/model_associator_mock.h b/chrome/browser/sync/glue/model_associator_mock.h
new file mode 100644
index 0000000..7852dba
--- /dev/null
+++ b/chrome/browser/sync/glue/model_associator_mock.h
@@ -0,0 +1,23 @@
+// Copyright (c) 2010 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.
+
+#ifndef CHROME_BROWSER_SYNC_GLUE_MODEL_ASSOCIATOR_MOCK_H__
+#define CHROME_BROWSER_SYNC_GLUE_MODEL_ASSOCIATOR_MOCK_H__
+
+#include "chrome/browser/sync/glue/model_associator.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace browser_sync {
+
+class ModelAssociatorMock : public AssociatorInterface {
+ public:
+ MOCK_METHOD0(AssociateModels, bool());
+ MOCK_METHOD0(DisassociateModels, bool());
+ MOCK_METHOD0(SyncModelHasUserCreatedNodes, bool());
+ MOCK_METHOD0(ChromeModelHasUserCreatedNodes, bool());
+};
+
+} // namespace browser_sync
+
+#endif // CHROME_BROWSER_SYNC_GLUE_MODEL_ASSOCIATOR_MOCK_H__
diff --git a/chrome/browser/sync/glue/sync_backend_host.cc b/chrome/browser/sync/glue/sync_backend_host.cc
index 9b18d90..c154137 100644
--- a/chrome/browser/sync/glue/sync_backend_host.cc
+++ b/chrome/browser/sync/glue/sync_backend_host.cc
@@ -8,6 +8,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/sync/glue/change_processor.h"
+#include "chrome/browser/sync/glue/data_type_controller.h"
#include "chrome/browser/sync/glue/sync_backend_host.h"
#include "chrome/browser/sync/glue/http_bridge.h"
#include "webkit/glue/webkit_glue.h"
@@ -23,12 +24,10 @@ typedef GoogleServiceAuthError AuthError;
namespace browser_sync {
SyncBackendHost::SyncBackendHost(SyncFrontend* frontend,
- const FilePath& profile_path,
- std::set<ChangeProcessor*> processors)
+ const FilePath& profile_path)
: core_thread_("Chrome_SyncCoreThread"),
frontend_loop_(MessageLoop::current()),
frontend_(frontend),
- processors_(processors),
sync_data_folder_path_(profile_path.Append(kSyncDataFolderName)),
last_auth_error_(AuthError::None()) {
@@ -62,7 +61,6 @@ void SyncBackendHost::Initialize(
// when a new type is synced as the worker may already exist and you just
// need to update routing_info_.
registrar_.workers[GROUP_UI] = new UIModelWorker(frontend_loop_);
- registrar_.routing_info[syncable::BOOKMARKS] = GROUP_UI;
core_thread_.message_loop()->PostTask(FROM_HERE,
NewRunnableMethod(core_.get(), &SyncBackendHost::Core::DoInitialize,
@@ -118,6 +116,39 @@ void SyncBackendHost::Shutdown(bool sync_disabled) {
core_ = NULL; // Releases reference to core_.
}
+void SyncBackendHost::ActivateDataType(
+ DataTypeController* data_type_controller,
+ ChangeProcessor* change_processor) {
+ // Ensure that the given data type is in the PASSIVE group.
+ browser_sync::ModelSafeRoutingInfo::iterator i =
+ registrar_.routing_info.find(data_type_controller->type());
+ DCHECK(i != registrar_.routing_info.end());
+ DCHECK((*i).second == GROUP_PASSIVE);
+
+ // Change the data type's routing info to its group.
+ registrar_.routing_info[data_type_controller->type()] =
+ data_type_controller->model_safe_group();
+
+ // Add the data type's change processor to the list of change
+ // processors so it can receive updates.
+ std::pair<std::set<ChangeProcessor*>::iterator, bool> result =
+ processors_.insert(change_processor);
+ DCHECK(result.second);
+}
+
+void SyncBackendHost::DeactivateDataType(
+ DataTypeController* data_type_controller,
+ ChangeProcessor* change_processor) {
+ registrar_.routing_info.erase(data_type_controller->type());
+
+ std::set<ChangeProcessor*>::size_type erased =
+ processors_.erase(change_processor);
+ DCHECK(erased == 1);
+
+ // TODO(sync): At this point we need to purge the data associated
+ // with this data type from the sync db.
+}
+
void SyncBackendHost::Core::NotifyFrontend(FrontendNotification notification) {
if (!host_ || !host_->frontend_) {
return; // This can happen in testing because the UI loop processes tasks
@@ -278,6 +309,18 @@ void SyncBackendHost::Core::OnChangesApplied(
return;
}
+ // Right now we only support bookmarks, and until bookmark model
+ // association happens, the processors list will be empty. During
+ // this time, it is OK to drop changes on the floor (since model
+ // association has not happened yet). When the bookmark data type
+ // is activated, model association takes place then the change
+ // processor is added to the processors_ list. This all happens on
+ // the UI thread so we will never drop any changes after model
+ // association.
+ // TODO(sync): Replace this with proper change filtering.
+ if (!host_->processors_.size())
+ return;
+
// ChangesApplied is the one exception that should come over from the sync
// backend already on the service_loop_ thanks to our UIModelWorker.
// SyncFrontend changes exclusively on the UI loop, because it updates
diff --git a/chrome/browser/sync/glue/sync_backend_host.h b/chrome/browser/sync/glue/sync_backend_host.h
index be9e90b..731a172 100644
--- a/chrome/browser/sync/glue/sync_backend_host.h
+++ b/chrome/browser/sync/glue/sync_backend_host.h
@@ -26,6 +26,7 @@
namespace browser_sync {
class ChangeProcessor;
+class DataTypeController;
// SyncFrontend is the interface used by SyncBackendHost to communicate with
// the entity that created it and, presumably, is interested in sync-related
@@ -69,10 +70,8 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
// Create a SyncBackendHost with a reference to the |frontend| that it serves
// and communicates to via the SyncFrontend interface (on the same thread
- // it used to call the constructor), and push changes from sync_api through
- // |processor|.
- SyncBackendHost(SyncFrontend* frontend, const FilePath& profile_path,
- std::set<ChangeProcessor*> processor);
+ // it used to call the constructor).
+ SyncBackendHost(SyncFrontend* frontend, const FilePath& profile_path);
~SyncBackendHost();
// Called on |frontend_loop_| to kick off asynchronous initialization.
@@ -94,6 +93,17 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
// See the implementation and Core::DoShutdown for details.
void Shutdown(bool sync_disabled);
+ // Activates change processing for the given data type. This must
+ // be called synchronously with the data type's model association so
+ // no changes are dropped between model association and change
+ // processor activation.
+ void ActivateDataType(DataTypeController* data_type_controller,
+ ChangeProcessor* change_processor);
+
+ // Deactivates change processing for the given data type.
+ void DeactivateDataType(DataTypeController* data_type_controller,
+ ChangeProcessor* change_processor);
+
// Called on |frontend_loop_| to obtain a handle to the UserShare needed
// for creating transactions.
UserShareHandle GetUserShareHandle() const;
@@ -127,7 +137,6 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
if (!core_thread_.Start())
return;
registrar_.workers[GROUP_UI] = new UIModelWorker(frontend_loop_);
- registrar_.routing_info[syncable::BOOKMARKS] = GROUP_UI;
core_thread_.message_loop()->PostTask(FROM_HERE,
NewRunnableMethod(core_.get(),
diff --git a/chrome/browser/sync/profile_sync_factory.h b/chrome/browser/sync/profile_sync_factory.h
new file mode 100644
index 0000000..107807e
--- /dev/null
+++ b/chrome/browser/sync/profile_sync_factory.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2010 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.
+
+#ifndef CHROME_BROWSER_SYNC_PROFILE_SYNC_FACTORY_H__
+#define CHROME_BROWSER_SYNC_PROFILE_SYNC_FACTORY_H__
+
+#include <utility>
+#include "base/task.h"
+
+class ProfileSyncService;
+
+namespace browser_sync {
+class AssociatorInterface;
+class ChangeProcessor;
+}
+
+// Factory class for all profile sync related classes.
+class ProfileSyncFactory {
+ public:
+ struct BookmarkComponents {
+ browser_sync::AssociatorInterface* model_associator;
+ browser_sync::ChangeProcessor* change_processor;
+ BookmarkComponents(browser_sync::AssociatorInterface* ma,
+ browser_sync::ChangeProcessor* cp)
+ : model_associator(ma), change_processor(cp) {}
+ };
+
+ virtual ~ProfileSyncFactory() {}
+
+ // Instantiates and initializes a new ProfileSyncService. Enabled
+ // data types are registered with the service. The return pointer
+ // is owned by the caller.
+ virtual ProfileSyncService* CreateProfileSyncService() = 0;
+
+ // Instantiates both a model associator and change processor for the
+ // bookmark data type. Ideally we would have separate factory
+ // methods for these components, but the bookmark implementation of
+ // these are tightly coupled and must be created at the same time.
+ // The pointers in the return struct are owned by the caller.
+ virtual BookmarkComponents CreateBookmarkComponents(
+ ProfileSyncService* profile_sync_service) = 0;
+};
+
+#endif // CHROME_BROWSER_SYNC_PROFILE_SYNC_FACTORY_H__
diff --git a/chrome/browser/sync/profile_sync_factory_impl.cc b/chrome/browser/sync/profile_sync_factory_impl.cc
new file mode 100644
index 0000000..d7658de
--- /dev/null
+++ b/chrome/browser/sync/profile_sync_factory_impl.cc
@@ -0,0 +1,42 @@
+// Copyright (c) 2010 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 "base/command_line.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/sync/glue/change_processor.h"
+#include "chrome/browser/sync/glue/bookmark_change_processor.h"
+#include "chrome/browser/sync/glue/bookmark_data_type_controller.h"
+#include "chrome/browser/sync/glue/bookmark_model_associator.h"
+#include "chrome/browser/sync/glue/model_associator.h"
+#include "chrome/browser/sync/profile_sync_service.h"
+#include "chrome/browser/sync/profile_sync_factory_impl.h"
+#include "chrome/common/chrome_switches.h"
+
+ProfileSyncFactoryImpl::ProfileSyncFactoryImpl(
+ Profile* profile,
+ CommandLine* command_line)
+ : profile_(profile), command_line_(command_line) {
+}
+
+ProfileSyncService* ProfileSyncFactoryImpl::CreateProfileSyncService() {
+ ProfileSyncService* pss = new ProfileSyncService(profile_);
+
+ // Bookmark sync is enabled by default. Register unless explicitly disabled.
+ if (!command_line_->HasSwitch(switches::kDisableSyncBookmarks)) {
+ pss->RegisterDataTypeController(
+ new browser_sync::BookmarkDataTypeController(this, profile_, pss));
+ }
+ return pss;
+}
+
+ProfileSyncFactory::BookmarkComponents
+ProfileSyncFactoryImpl::CreateBookmarkComponents(
+ ProfileSyncService* profile_sync_service) {
+ browser_sync::BookmarkModelAssociator* model_associator =
+ new browser_sync::BookmarkModelAssociator(profile_sync_service);
+ browser_sync::BookmarkChangeProcessor* change_processor =
+ new browser_sync::BookmarkChangeProcessor(model_associator,
+ profile_sync_service);
+ return BookmarkComponents(model_associator, change_processor);
+}
diff --git a/chrome/browser/sync/profile_sync_factory_impl.h b/chrome/browser/sync/profile_sync_factory_impl.h
new file mode 100644
index 0000000..638a508
--- /dev/null
+++ b/chrome/browser/sync/profile_sync_factory_impl.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2010 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.
+
+#ifndef CHROME_BROWSER_SYNC_PROFILE_SYNC_FACTORY_IMPL_H__
+#define CHROME_BROWSER_SYNC_PROFILE_SYNC_FACTORY_IMPL_H__
+
+#include "base/basictypes.h"
+#include "chrome/browser/sync/profile_sync_factory.h"
+
+class CommandLine;
+class Profile;
+
+class ProfileSyncFactoryImpl : public ProfileSyncFactory {
+ public:
+ ProfileSyncFactoryImpl(Profile* profile, CommandLine* command_line);
+ virtual ~ProfileSyncFactoryImpl() {}
+
+ virtual ProfileSyncService* CreateProfileSyncService();
+
+ virtual BookmarkComponents CreateBookmarkComponents(
+ ProfileSyncService* profile_sync_service);
+
+ private:
+ Profile* profile_;
+ CommandLine* command_line_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProfileSyncFactoryImpl);
+};
+
+#endif // CHROME_BROWSER_SYNC_PROFILE_SYNC_FACTORY_IMPL_H__
diff --git a/chrome/browser/sync/profile_sync_factory_impl_unittest.cc b/chrome/browser/sync/profile_sync_factory_impl_unittest.cc
new file mode 100644
index 0000000..1dbbdb3
--- /dev/null
+++ b/chrome/browser/sync/profile_sync_factory_impl_unittest.cc
@@ -0,0 +1,54 @@
+// Copyright (c) 2010 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 "testing/gtest/include/gtest/gtest.h"
+#include "base/command_line.h"
+#include "base/file_path.h"
+#include "base/message_loop.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/sync/engine/syncapi.h"
+#include "chrome/browser/sync/profile_sync_service.h"
+#include "chrome/browser/sync/profile_sync_factory_impl.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/test/testing_profile.h"
+
+class ProfileSyncFactoryImplTest : public testing::Test {
+ protected:
+ ProfileSyncFactoryImplTest()
+ : ui_thread_(ChromeThread::UI, &message_loop_) {}
+
+ virtual void SetUp() {
+ profile_.reset(new TestingProfile());
+ FilePath program_path(FILE_PATH_LITERAL("chrome.exe"));
+ command_line_.reset(new CommandLine(program_path));
+ profile_sync_service_factory_.reset(
+ new ProfileSyncFactoryImpl(profile_.get(), command_line_.get()));
+ }
+
+ MessageLoop message_loop_;
+ ChromeThread ui_thread_;
+ scoped_ptr<Profile> profile_;
+ scoped_ptr<CommandLine> command_line_;
+ scoped_ptr<ProfileSyncFactoryImpl> profile_sync_service_factory_;
+};
+
+TEST_F(ProfileSyncFactoryImplTest, CreatePSSDefault) {
+ scoped_ptr<ProfileSyncService> pss;
+ pss.reset(profile_sync_service_factory_->CreateProfileSyncService());
+ ProfileSyncService::DataTypeControllerMap controllers(
+ pss->data_type_controllers());
+ EXPECT_EQ(1U, controllers.size());
+ EXPECT_EQ(1U, controllers.count(syncable::BOOKMARKS));
+}
+
+TEST_F(ProfileSyncFactoryImplTest, CreatePSSDisableBookmarks) {
+ command_line_->AppendSwitch(switches::kDisableSyncBookmarks);
+ scoped_ptr<ProfileSyncService> pss;
+ pss.reset(profile_sync_service_factory_->CreateProfileSyncService());
+ ProfileSyncService::DataTypeControllerMap controllers(
+ pss->data_type_controllers());
+ EXPECT_EQ(0U, controllers.size());
+ EXPECT_EQ(0U, controllers.count(syncable::BOOKMARKS));
+}
diff --git a/chrome/browser/sync/profile_sync_factory_mock.cc b/chrome/browser/sync/profile_sync_factory_mock.cc
new file mode 100644
index 0000000..c30331f
--- /dev/null
+++ b/chrome/browser/sync/profile_sync_factory_mock.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 2010 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/glue/change_processor.h"
+#include "chrome/browser/sync/glue/model_associator.h"
+#include "chrome/browser/sync/profile_sync_factory_mock.h"
+
+using browser_sync::AssociatorInterface;
+using browser_sync::ChangeProcessor;
+using testing::_;
+using testing::InvokeWithoutArgs;
+
+ProfileSyncFactoryMock::ProfileSyncFactoryMock(
+ AssociatorInterface* bookmark_model_associator,
+ ChangeProcessor* bookmark_change_processor)
+ : bookmark_model_associator_(bookmark_model_associator),
+ bookmark_change_processor_(bookmark_change_processor) {
+ ON_CALL(*this, CreateBookmarkComponents(_)).
+ WillByDefault(
+ InvokeWithoutArgs(
+ this,
+ &ProfileSyncFactoryMock::MakeBookmarkComponents));
+}
+
+ProfileSyncFactory::BookmarkComponents
+ProfileSyncFactoryMock::MakeBookmarkComponents() {
+ return BookmarkComponents(bookmark_model_associator_.release(),
+ bookmark_change_processor_.release());
+}
diff --git a/chrome/browser/sync/profile_sync_factory_mock.h b/chrome/browser/sync/profile_sync_factory_mock.h
new file mode 100644
index 0000000..3ac7d51
--- /dev/null
+++ b/chrome/browser/sync/profile_sync_factory_mock.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2010 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.
+
+#ifndef CHROME_BROWSER_SYNC_PROFILE_SYNC_FACTORY_MOCK_H__
+#define CHROME_BROWSER_SYNC_PROFILE_SYNC_FACTORY_MOCK_H__
+
+#include "base/scoped_ptr.h"
+#include "chrome/browser/sync/profile_sync_service.h"
+#include "chrome/browser/sync/profile_sync_factory.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace browser_sync {
+class AssociatorInterface;
+class ChangeProcessor;
+}
+
+class ProfileSyncFactoryMock : public ProfileSyncFactory {
+ public:
+ ProfileSyncFactoryMock(
+ browser_sync::AssociatorInterface* bookmark_model_associator,
+ browser_sync::ChangeProcessor* bookmark_change_processor);
+
+ MOCK_METHOD0(CreateProfileSyncService,
+ ProfileSyncService*(void));
+ MOCK_METHOD1(CreateBookmarkComponents,
+ BookmarkComponents(ProfileSyncService* profile_sync_service));
+
+ private:
+ BookmarkComponents MakeBookmarkComponents();
+
+ scoped_ptr<browser_sync::AssociatorInterface> bookmark_model_associator_;
+ scoped_ptr<browser_sync::ChangeProcessor> bookmark_change_processor_;
+};
+
+#endif // CHROME_BROWSER_SYNC_PROFILE_SYNC_FACTORY_MOCK_H__
diff --git a/chrome/browser/sync/profile_sync_service.cc b/chrome/browser/sync/profile_sync_service.cc
index 88e080e..df65f79 100644
--- a/chrome/browser/sync/profile_sync_service.cc
+++ b/chrome/browser/sync/profile_sync_service.cc
@@ -4,28 +4,20 @@
#include "chrome/browser/sync/profile_sync_service.h"
-#include <stack>
-#include <vector>
-
#include "app/l10n_util.h"
-#include "base/basictypes.h"
#include "base/command_line.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/histogram.h"
+#include "base/stl_util-inl.h"
#include "base/string_util.h"
-#include "base/time.h"
-#include "chrome/browser/bookmarks/bookmark_utils.h"
+#include "base/task.h"
#include "chrome/browser/defaults.h"
-#include "chrome/browser/history/history_notifications.h"
#include "chrome/browser/history/history_types.h"
-#include "chrome/browser/profile.h"
#include "chrome/browser/sync/engine/syncapi.h"
-#include "chrome/browser/sync/glue/bookmark_change_processor.h"
-#include "chrome/browser/sync/glue/bookmark_model_associator.h"
+#include "chrome/browser/sync/glue/change_processor.h"
+#include "chrome/browser/sync/glue/data_type_controller.h"
#include "chrome/common/chrome_switches.h"
-#include "chrome/common/notification_service.h"
-#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/pref_service.h"
#include "chrome/common/time_format.h"
@@ -33,10 +25,8 @@
#include "net/base/cookie_monster.h"
#include "views/window/window.h"
-using browser_sync::BookmarkChangeProcessor;
-using browser_sync::BookmarkModelAssociator;
using browser_sync::ChangeProcessor;
-using browser_sync::ModelAssociator;
+using browser_sync::DataTypeController;
using browser_sync::SyncBackendHost;
typedef GoogleServiceAuthError AuthError;
@@ -48,8 +38,6 @@ ProfileSyncService::ProfileSyncService(Profile* profile)
: last_auth_error_(AuthError::None()),
profile_(profile),
sync_service_url_(kSyncServerUrl),
- ALLOW_THIS_IN_INITIALIZER_LIST(model_associator_(
- new ModelAssociator(this))),
backend_initialized_(false),
expecting_first_run_auth_needed_event_(false),
is_auth_in_progress_(false),
@@ -59,6 +47,7 @@ ProfileSyncService::ProfileSyncService(Profile* profile)
ProfileSyncService::~ProfileSyncService() {
Shutdown(false);
+ STLDeleteValues(&data_type_controllers_);
}
void ProfileSyncService::Initialize() {
@@ -79,6 +68,13 @@ void ProfileSyncService::Initialize() {
}
}
+void ProfileSyncService::RegisterDataTypeController(
+ DataTypeController* data_type_controller) {
+ DCHECK(data_type_controllers_.count(data_type_controller->type()) == 0);
+ data_type_controllers_[data_type_controller->type()] =
+ data_type_controller;
+}
+
void ProfileSyncService::InitSettings() {
const CommandLine& command_line = *CommandLine::ForCurrentProcess();
@@ -155,21 +151,10 @@ void ProfileSyncService::StartUp() {
if (backend_.get())
return;
- // Register associator impls for all currently synced data types, and hook
- // them up to the associated change processors. If you add a new data type
- // and want that data type to be synced, call CreateGlue with appropriate
- // association and change processing implementations.
- // Bookmarks.
- InstallGlue<BookmarkModelAssociator, BookmarkChangeProcessor>();
-
last_synced_time_ = base::Time::FromInternalValue(
profile_->GetPrefs()->GetInt64(prefs::kSyncLastSyncedTime));
- backend_.reset(new SyncBackendHost(this, profile_->GetPath(),
- change_processors_));
-
- registrar_.Add(this, NotificationType::BOOKMARK_MODEL_LOADED,
- Source<Profile>(profile_));
+ backend_.reset(new SyncBackendHost(this, profile_->GetPath()));
// Initialize the backend. Every time we start up a new SyncBackendHost,
// we'll want to start from a fresh SyncDB, so delete any old one that might
@@ -178,22 +163,15 @@ void ProfileSyncService::StartUp() {
}
void ProfileSyncService::Shutdown(bool sync_disabled) {
- registrar_.RemoveAll();
-
if (backend_.get())
backend_->Shutdown(sync_disabled);
- for (std::set<ChangeProcessor*>::const_iterator it =
- change_processors_.begin(); it != change_processors_.end(); ++it) {
- (*it)->Stop();
- }
- backend_.reset();
+ // Stop all data type controllers.
+ // TODO(skrul): Change this to support multiple data type controllers.
+ if (data_type_controllers_.count(syncable::BOOKMARKS))
+ data_type_controllers_[syncable::BOOKMARKS]->Stop();
- // Clear all associations and throw away the association manager instance.
- model_associator_->DisassociateModels();
- model_associator_->CleanupAllAssociators();
-
- STLDeleteElements(&change_processors_);
+ backend_.reset();
// Clear various flags.
is_auth_in_progress_ = false;
@@ -224,23 +202,6 @@ void ProfileSyncService::DisableForUser() {
FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
}
-void ProfileSyncService::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- DCHECK_EQ(NotificationType::BOOKMARK_MODEL_LOADED, type.value);
- registrar_.RemoveAll();
- StartProcessingChangesIfReady();
-}
-
-bool ProfileSyncService::MergeAndSyncAcceptanceNeeded() const {
- // If we've shown the dialog before, don't show it again.
- if (profile_->GetPrefs()->GetBoolean(prefs::kSyncHasSetupCompleted))
- return false;
-
- return model_associator_->ChromeModelHasUserCreatedNodes() &&
- model_associator_->SyncModelHasUserCreatedNodes();
-}
-
bool ProfileSyncService::HasSyncSetupCompleted() const {
return profile_->GetPrefs()->GetBoolean(prefs::kSyncHasSetupCompleted);
}
@@ -262,10 +223,9 @@ void ProfileSyncService::UpdateLastSyncedTime() {
// to do as little work as possible, to avoid further corruption or crashes.
void ProfileSyncService::OnUnrecoverableError() {
unrecoverable_error_detected_ = true;
- for (std::set<ChangeProcessor*>::const_iterator it =
- change_processors_.begin(); it != change_processors_.end(); ++it) {
- (*it)->Stop();
- }
+
+ // TODO(skrul): Change this to support multiple data type controllers.
+ data_type_controllers_[syncable::BOOKMARKS]->Stop();
// Tell the wizard so it can inform the user only if it is already open.
wizard_.Step(SyncSetupWizard::FATAL_ERROR);
@@ -392,27 +352,12 @@ void ProfileSyncService::OnUserSubmittedAuth(
}
void ProfileSyncService::OnUserAcceptedMergeAndSync() {
- base::TimeTicks start_time = base::TimeTicks::Now();
- // TODO(sync): Figure out what do to when a single associator fails.
- // http://crbug.com/30038
- bool not_first_run = model_associator_->SyncModelHasUserCreatedNodes();
- bool merge_success = model_associator_->AssociateModels();
- UMA_HISTOGRAM_MEDIUM_TIMES("Sync.UserPerceivedBookmarkAssociation",
- base::TimeTicks::Now() - start_time);
- if (!merge_success) {
- LOG(ERROR) << "Model association failed.";
- OnUnrecoverableError();
- return;
- }
-
- wizard_.Step(not_first_run ? SyncSetupWizard::DONE :
- SyncSetupWizard::DONE_FIRST_TIME);
-
- for (std::set<ChangeProcessor*>::const_iterator it =
- change_processors_.begin(); it != change_processors_.end(); ++it) {
- (*it)->Start(profile(), backend_->GetUserShareHandle());
- }
- FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
+ // Start each data type with "merge_allowed" to correspond to the
+ // user's acceptance of merge.
+ // TODO(skrul): Change this to support multiple data type controllers.
+ data_type_controllers_[syncable::BOOKMARKS]->Start(
+ true,
+ NewCallback(this, &ProfileSyncService::BookmarkStartCallback));
}
void ProfileSyncService::OnUserCancelledDialog() {
@@ -426,53 +371,63 @@ void ProfileSyncService::OnUserCancelledDialog() {
}
void ProfileSyncService::StartProcessingChangesIfReady() {
- BookmarkModel* model = profile_->GetBookmarkModel();
-
- for (std::set<ChangeProcessor*>::const_iterator it =
- change_processors_.begin(); it != change_processors_.end(); ++it) {
- DCHECK(!(*it)->IsRunning());
- }
+ DCHECK(backend_initialized_);
- // First check if the subsystems are ready. We can't proceed until they
- // both have finished loading.
- if (!model->IsLoaded())
- return;
- if (!backend_initialized_)
- return;
+ // If the user has completed sync setup, we are always allowed to
+ // merge data.
+ bool merge_allowed =
+ profile_->GetPrefs()->GetBoolean(prefs::kSyncHasSetupCompleted);
+ // If we're running inside Chrome OS, always allow merges and
+ // consider the sync setup complete.
if (browser_defaults::kBootstrapSyncAuthentication) {
- // If we're running inside Chrome OS, skip the merge warning and consider
- // the sync setup complete.
+ merge_allowed = true;
SetSyncSetupCompleted();
- } else {
- // Show the sync merge warning dialog if needed.
- if (MergeAndSyncAcceptanceNeeded()) {
+ }
+
+ // Start data types.
+ // TODO(skrul): Change this to support multiple data type controllers.
+ data_type_controllers_[syncable::BOOKMARKS]->Start(
+ merge_allowed,
+ NewCallback(this, &ProfileSyncService::BookmarkStartCallback));
+}
+
+void ProfileSyncService::BookmarkStartCallback(
+ DataTypeController::StartResult result) {
+ switch (result) {
+ case DataTypeController::OK:
+ case DataTypeController::OK_FIRST_RUN: {
+ wizard_.Step(result == DataTypeController::OK ? SyncSetupWizard::DONE :
+ SyncSetupWizard::DONE_FIRST_TIME);
+ FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
+ break;
+ }
+
+ case DataTypeController::NEEDS_MERGE: {
ProfileSyncService::SyncEvent(MERGE_AND_SYNC_NEEDED);
wizard_.Step(SyncSetupWizard::MERGE_AND_SYNC);
- return;
+ break;
}
- }
- // We're ready to merge the models.
- base::TimeTicks start_time = base::TimeTicks::Now();
- bool not_first_run = model_associator_->SyncModelHasUserCreatedNodes();
- bool merge_success = model_associator_->AssociateModels();
- UMA_HISTOGRAM_TIMES("Sync.BookmarkAssociationTime",
- base::TimeTicks::Now() - start_time);
- if (!merge_success) {
- LOG(ERROR) << "Model association failed.";
+ default: {
+ LOG(ERROR) << "Bookmark start failed";
OnUnrecoverableError();
- return;
+ }
}
+}
- wizard_.Step(not_first_run ? SyncSetupWizard::DONE :
- SyncSetupWizard::DONE_FIRST_TIME);
+void ProfileSyncService::ActivateDataType(
+ DataTypeController* data_type_controller,
+ ChangeProcessor* change_processor) {
+ change_processor->Start(profile(), backend_->GetUserShareHandle());
+ backend_->ActivateDataType(data_type_controller, change_processor);
+}
- for (std::set<ChangeProcessor*>::const_iterator it =
- change_processors_.begin(); it != change_processors_.end(); ++it) {
- (*it)->Start(profile(), backend_->GetUserShareHandle());
- }
- FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
+void ProfileSyncService::DeactivateDataType(
+ DataTypeController* data_type_controller,
+ ChangeProcessor* change_processor) {
+ change_processor->Stop();
+ backend_->DeactivateDataType(data_type_controller, change_processor);
}
void ProfileSyncService::AddObserver(Observer* observer) {
@@ -497,9 +452,9 @@ bool ProfileSyncService::ShouldPushChanges() {
// True only after all bootstrapping has succeeded: the bookmark model is
// loaded, the sync backend is initialized, the two domains are
// consistent with one another, and no unrecoverable error has transpired.
- for (std::set<ChangeProcessor*>::const_iterator it =
- change_processors_.begin(); it != change_processors_.end(); ++it) {
- if (!(*it)->IsRunning()) return false;
+ if (data_type_controllers_.count(syncable::BOOKMARKS)) {
+ return data_type_controllers_[syncable::BOOKMARKS]->state() ==
+ DataTypeController::RUNNING;
}
- return true;
+ return false;
}
diff --git a/chrome/browser/sync/profile_sync_service.h b/chrome/browser/sync/profile_sync_service.h
index 33be503..0c1f8ae 100644
--- a/chrome/browser/sync/profile_sync_service.h
+++ b/chrome/browser/sync/profile_sync_service.h
@@ -7,27 +7,25 @@
#include <string>
#include <map>
-#include <vector>
#include "base/basictypes.h"
-#include "base/file_path.h"
#include "base/observer_list.h"
#include "base/scoped_ptr.h"
+#include "base/time.h"
#include "chrome/browser/google_service_auth_error.h"
-#include "chrome/browser/sync/glue/change_processor.h"
-#include "chrome/browser/sync/glue/model_associator.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/sync/glue/data_type_controller.h" // For StartResult.
#include "chrome/browser/sync/glue/sync_backend_host.h"
#include "chrome/browser/sync/sync_setup_wizard.h"
-#include "chrome/common/notification_registrar.h"
+#include "chrome/browser/sync/syncable/model_type.h"
#include "googleurl/src/gurl.h"
#include "testing/gtest/include/gtest/gtest_prod.h"
-class CommandLine;
-class MessageLoop;
-class Profile;
-
namespace browser_sync {
+class ChangeProcessor;
+class DataTypeController;
+
class UnrecoverableErrorHandler {
public:
// Call this when normal operation detects that the bookmark model and the
@@ -58,10 +56,11 @@ class ProfileSyncServiceObserver {
// ProfileSyncService is the layer between browser subsystems like bookmarks,
// and the sync backend.
-class ProfileSyncService : public NotificationObserver,
- public browser_sync::SyncFrontend,
+class ProfileSyncService : public browser_sync::SyncFrontend,
public browser_sync::UnrecoverableErrorHandler {
public:
+ typedef std::map<syncable::ModelType, browser_sync::DataTypeController*>
+ DataTypeControllerMap;
typedef ProfileSyncServiceObserver Observer;
typedef browser_sync::SyncBackendHost::Status Status;
@@ -96,6 +95,17 @@ class ProfileSyncService : public NotificationObserver,
// class is constructed.
void Initialize();
+ // Registers a data type controller with the sync service. This
+ // makes the data type controller available for use, it does not
+ // enable or activate the synchronization of the data type (see
+ // ActivateDataType). Takes ownership of the pointer.
+ void RegisterDataTypeController(
+ browser_sync::DataTypeController* data_type_controller);
+
+ const DataTypeControllerMap& data_type_controllers() const {
+ return data_type_controllers_;
+ }
+
// Enables/disables sync for user.
virtual void EnableForUser();
virtual void DisableForUser();
@@ -104,11 +114,6 @@ class ProfileSyncService : public NotificationObserver,
bool HasSyncSetupCompleted() const;
void SetSyncSetupCompleted();
- // NotificationObserver implementation.
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
// SyncFrontend implementation.
virtual void OnBackendInitialized();
virtual void OnSyncCycleCompleted();
@@ -204,6 +209,13 @@ class ProfileSyncService : public NotificationObserver,
browser_sync::SyncBackendHost* backend() { return backend_.get(); }
+ virtual void ActivateDataType(
+ browser_sync::DataTypeController* data_type_controller,
+ browser_sync::ChangeProcessor* change_processor);
+ virtual void DeactivateDataType(
+ browser_sync::DataTypeController* data_type_controller,
+ browser_sync::ChangeProcessor* change_processor);
+
protected:
// Call this after any of the subsystems being synced (the bookmark
// model and the sync backend) finishes its initialization. When everything
@@ -225,30 +237,14 @@ class ProfileSyncService : public NotificationObserver,
void RegisterPreferences();
void ClearPreferences();
+ void BookmarkStartCallback(
+ browser_sync::DataTypeController::StartResult result);
+
// Tests need to override this. If |delete_sync_data_folder| is true, then
// this method will delete all previous "Sync Data" folders. (useful if the
// folder is partial/corrupt)
virtual void InitializeBackend(bool delete_sync_data_folder);
- template <class AssociatorImpl, class ChangeProcessorImpl>
- void InstallGlue() {
- model_associator_->CreateAndRegisterPerDataTypeImpl<AssociatorImpl>();
- // TODO(tim): Keep a map instead of a set so we can register/unregister
- // data type specific ChangeProcessors, once we have more than one.
- STLDeleteElements(processors());
- ChangeProcessorImpl* processor = new ChangeProcessorImpl(this);
- change_processors_.insert(processor);
- processor->set_model_associator(
- model_associator_->GetImpl<AssociatorImpl>());
- }
-
- browser_sync::ModelAssociator* associator() {
- return model_associator_.get();
- }
- std::set<browser_sync::ChangeProcessor*>* processors() {
- return &change_processors_;
- }
-
// We keep track of the last auth error observed so we can cover up the first
// "expected" auth failure from observers.
// TODO(timsteele): Same as expecting_first_run_auth_needed_event_. Remove
@@ -267,9 +263,6 @@ class ProfileSyncService : public NotificationObserver,
// Initializes the various settings from the command line.
void InitSettings();
- // Whether the sync merge warning should be shown.
- bool MergeAndSyncAcceptanceNeeded() const;
-
// Sets the last synced time to the current time.
void UpdateLastSyncedTime();
@@ -298,13 +291,8 @@ class ProfileSyncService : public NotificationObserver,
// other threads.
scoped_ptr<browser_sync::SyncBackendHost> backend_;
- // Model association manager instance.
- scoped_ptr<browser_sync::ModelAssociator> model_associator_;
-
- // The change processors that handle the different data types.
- std::set<browser_sync::ChangeProcessor*> change_processors_;
-
- NotificationRegistrar registrar_;
+ // List of available data type controllers.
+ DataTypeControllerMap data_type_controllers_;
// Whether the SyncBackendHost has been initialized.
bool backend_initialized_;
diff --git a/chrome/browser/sync/profile_sync_service_mock.h b/chrome/browser/sync/profile_sync_service_mock.h
new file mode 100644
index 0000000..e2b4dde
--- /dev/null
+++ b/chrome/browser/sync/profile_sync_service_mock.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2010 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.
+
+#ifndef CHROME_BROWSER_SYNC_PROFILE_SYNC_SERVICE_MOCK_H_
+#define CHROME_BROWSER_SYNC_PROFILE_SYNC_SERVICE_MOCK_H_
+
+#include <string>
+#include "base/string16.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/sync/glue/change_processor.h"
+#include "chrome/browser/sync/glue/data_type_controller.h"
+#include "chrome/browser/sync/profile_sync_service.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+class ProfileSyncServiceMock : public ProfileSyncService {
+ public:
+ ProfileSyncServiceMock() : ProfileSyncService(NULL) {}
+ virtual ~ProfileSyncServiceMock() {}
+
+ MOCK_METHOD0(EnableForUser, void());
+ MOCK_METHOD0(DisableForUser, void());
+ MOCK_METHOD0(OnBackendInitialized, void());
+ MOCK_METHOD0(OnSyncCycleCompleted, void());
+ MOCK_METHOD0(OnAuthError, void());
+ MOCK_METHOD3(OnUserSubmittedAuth,
+ void(const std::string& username,
+ const std::string& password,
+ const std::string& captcha));
+ MOCK_METHOD0(OnUserAcceptedMergeAndSync, void());
+ MOCK_METHOD0(OnUserCancelledDialog, void());
+ MOCK_CONST_METHOD0(GetAuthenticatedUsername, string16());
+ MOCK_METHOD0(OnUnrecoverableError, void());
+ MOCK_METHOD2(ActivateDataType,
+ void(browser_sync::DataTypeController* data_type_controller,
+ browser_sync::ChangeProcessor* change_processor));
+ MOCK_METHOD2(DeactivateDataType,
+ void(browser_sync::DataTypeController* data_type_controller,
+ browser_sync::ChangeProcessor* change_processor));
+
+ MOCK_METHOD0(InitializeBackend, void());
+};
+
+#endif // CHROME_BROWSER_SYNC_PROFILE_SYNC_SERVICE_MOCK_H_
diff --git a/chrome/browser/sync/profile_sync_service_unittest.cc b/chrome/browser/sync/profile_sync_service_unittest.cc
index 6057bf2..584b77d 100644
--- a/chrome/browser/sync/profile_sync_service_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_unittest.cc
@@ -7,22 +7,28 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "base/message_loop.h"
+#include "base/scoped_ptr.h"
#include "base/string_util.h"
#include "base/string16.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/sync/engine/syncapi.h"
+#include "chrome/browser/sync/glue/change_processor.h"
#include "chrome/browser/sync/glue/bookmark_change_processor.h"
+#include "chrome/browser/sync/glue/bookmark_data_type_controller.h"
#include "chrome/browser/sync/glue/bookmark_model_associator.h"
+#include "chrome/browser/sync/glue/model_associator.h"
#include "chrome/browser/sync/glue/sync_backend_host.h"
#include "chrome/browser/sync/profile_sync_service.h"
+#include "chrome/browser/sync/profile_sync_factory.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/testing_profile.h"
#include "chrome/test/sync/test_http_bridge_factory.h"
using std::vector;
+using browser_sync::AssociatorInterface;
using browser_sync::BookmarkChangeProcessor;
using browser_sync::BookmarkModelAssociator;
using browser_sync::ChangeProcessor;
@@ -30,6 +36,34 @@ using browser_sync::ModelAssociator;
using browser_sync::SyncBackendHost;
using browser_sync::TestHttpBridgeFactory;
+class TestProfileSyncFactory : public ProfileSyncFactory {
+ public:
+ TestProfileSyncFactory(ProfileSyncService* profile_sync_service,
+ AssociatorInterface* model_associator,
+ ChangeProcessor* change_processor)
+ : profile_sync_service_(profile_sync_service),
+ model_associator_(model_associator),
+ change_processor_(change_processor) {}
+ virtual ~TestProfileSyncFactory() {}
+
+ virtual ProfileSyncService* CreateProfileSyncService() {
+ return profile_sync_service_.release();
+ }
+
+ virtual BookmarkComponents CreateBookmarkComponents(
+ ProfileSyncService* service) {
+ return BookmarkComponents(model_associator_.release(),
+ change_processor_.release());
+ }
+
+ private:
+ scoped_ptr<ProfileSyncService> profile_sync_service_;
+ scoped_ptr<AssociatorInterface> model_associator_;
+ scoped_ptr<ChangeProcessor> change_processor_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestProfileSyncFactory);
+};
+
class TestModelAssociator : public BookmarkModelAssociator {
public:
explicit TestModelAssociator(ProfileSyncService* service)
@@ -94,7 +128,6 @@ class TestProfileSyncService : public ProfileSyncService {
}
virtual void InitializeBackend(bool delete_sync_data_folder) {
- InstallGlue<TestModelAssociator, BookmarkChangeProcessor>();
TestHttpBridgeFactory* factory = new TestHttpBridgeFactory();
TestHttpBridgeFactory* factory2 = new TestHttpBridgeFactory();
backend()->InitializeForTestMode(L"testuser", factory, factory2,
@@ -111,18 +144,11 @@ class TestProfileSyncService : public ProfileSyncService {
MessageLoop::current()->Quit();
}
+ // TODO(skrul): how to handle this?
virtual bool MergeAndSyncAcceptanceNeeded() {
// Never show the dialog.
return false;
}
-
- BookmarkChangeProcessor* change_processor() {
- // TODO(tim): The service should have a way to get specific processors.
- return static_cast<BookmarkChangeProcessor*>(*processors()->begin());
- }
- BookmarkModelAssociator* model_associator() {
- return associator()->GetImpl<BookmarkModelAssociator>();
- }
};
// FakeServerChange constructs a list of sync_api::ChangeRecords while modifying
@@ -278,7 +304,9 @@ class ProfileSyncServiceTest : public testing::Test {
ProfileSyncServiceTest()
: ui_thread_(ChromeThread::UI, &message_loop_),
file_thread_(ChromeThread::FILE, &message_loop_),
- model_(NULL) {
+ model_(NULL),
+ model_associator_(NULL),
+ change_processor_(NULL) {
profile_.reset(new TestingProfile());
profile_->set_has_history_service(true);
}
@@ -292,18 +320,28 @@ class ProfileSyncServiceTest : public testing::Test {
}
BookmarkModelAssociator* associator() {
- DCHECK(service_.get());
- return service_->model_associator();
+ return model_associator_;
}
BookmarkChangeProcessor* change_processor() {
- DCHECK(service_.get());
- return service_->change_processor();
+ return change_processor_;
}
void StartSyncService() {
if (!service_.get()) {
service_.reset(new TestProfileSyncService(profile_.get()));
+
+ // Register the bookmark data type.
+ model_associator_ = new TestModelAssociator(service_.get());
+ change_processor_ = new BookmarkChangeProcessor(model_associator_,
+ service_.get());
+ factory_.reset(new TestProfileSyncFactory(NULL,
+ model_associator_,
+ change_processor_));
+ service_->RegisterDataTypeController(
+ new browser_sync::BookmarkDataTypeController(factory_.get(),
+ profile_.get(),
+ service_.get()));
service_->Initialize();
}
// The service may have already started sync automatically if it's already
@@ -483,7 +521,10 @@ class ProfileSyncServiceTest : public testing::Test {
scoped_ptr<TestProfileSyncService> service_;
scoped_ptr<TestingProfile> profile_;
+ scoped_ptr<TestProfileSyncFactory> factory_;
BookmarkModel* model_;
+ TestModelAssociator* model_associator_;
+ BookmarkChangeProcessor* change_processor_;
};
TEST_F(ProfileSyncServiceTest, InitialState) {
@@ -740,6 +781,7 @@ TEST_F(ProfileSyncServiceTest, DISABLED_ServerChangeWithInvalidURL) {
ExpectModelMatch();
}
+
// Test strings that might pose a problem if the titles ever became used as
// file names in the sync backend.
TEST_F(ProfileSyncServiceTest, CornerCaseNames) {
@@ -841,18 +883,15 @@ TEST_F(ProfileSyncServiceTest, UnrecoverableErrorSuspendsService) {
EXPECT_TRUE(service_->ShouldPushChanges());
// Add a child to the inconsistent node. This should cause detection of the
- // problem.
- const BookmarkNode* nested = model_->AddGroup(node, 0, L"nested");
+ // problem and the syncer should stop processing changes.
+ model_->AddGroup(node, 0, L"nested");
EXPECT_FALSE(service_->ShouldPushChanges());
- ExpectSyncerNodeUnknown(nested);
// Try to add a node under a totally different parent. This should also
// fail -- the ProfileSyncService should stop processing changes after
// encountering a consistency violation.
- const BookmarkNode* unrelated = model_->AddGroup(
- model_->GetBookmarkBarNode(), 0, L"unrelated");
+ model_->AddGroup(model_->GetBookmarkBarNode(), 0, L"unrelated");
EXPECT_FALSE(service_->ShouldPushChanges());
- ExpectSyncerNodeUnknown(unrelated);
// TODO(ncarter): We ought to test the ProfileSyncService state machine
// directly here once that's formalized and exposed.
@@ -1327,6 +1366,7 @@ TEST_F(ProfileSyncServiceTestWithData, RecoverAfterDeletingSyncDataDirectory) {
// Make sure that things still work if sync is not enabled, but some old sync
// databases are lingering in the "Sync Data" folder.
+
TEST_F(ProfileSyncServiceTestWithData, MAYBE_TestStartupWithOldSyncData) {
const char* nonsense1 = "reginald";
const char* nonsense2 = "beartato";
@@ -1345,6 +1385,18 @@ TEST_F(ProfileSyncServiceTestWithData, MAYBE_TestStartupWithOldSyncData) {
if (!service_.get()) {
service_.reset(new TestProfileSyncService(profile_.get()));
profile_->GetPrefs()->SetBoolean(prefs::kSyncHasSetupCompleted, false);
+
+ model_associator_ = new TestModelAssociator(service_.get());
+ change_processor_ = new BookmarkChangeProcessor(model_associator_,
+ service_.get());
+ factory_.reset(new TestProfileSyncFactory(NULL,
+ model_associator_,
+ change_processor_));
+ service_->RegisterDataTypeController(
+ new browser_sync::BookmarkDataTypeController(factory_.get(),
+ profile_.get(),
+ service_.get()));
+
service_->Initialize(); // will call disableForUser because sync setup
// hasn't been completed.
}
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index eae3c48..0d1208c 100755
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -1661,10 +1661,14 @@
'browser/sync/engine/syncapi.h',
'browser/sync/glue/bookmark_change_processor.h',
'browser/sync/glue/bookmark_change_processor.cc',
+ 'browser/sync/glue/bookmark_change_processor.h',
+ 'browser/sync/glue/bookmark_data_type_controller.cc',
+ 'browser/sync/glue/bookmark_data_type_controller.h',
'browser/sync/glue/bookmark_model_associator.h',
'browser/sync/glue/bookmark_model_associator.cc',
'browser/sync/glue/change_processor.cc',
'browser/sync/glue/change_processor.h',
+ 'browser/sync/glue/data_type_controller.h',
'browser/sync/glue/database_model_worker.cc',
'browser/sync/glue/database_model_worker.h',
'browser/sync/glue/http_bridge.cc',
@@ -1680,6 +1684,9 @@
'browser/sync/glue/ui_model_worker.h',
'browser/sync/profile_sync_service.cc',
'browser/sync/profile_sync_service.h',
+ 'browser/sync/profile_sync_factory.h',
+ 'browser/sync/profile_sync_factory_impl.cc',
+ 'browser/sync/profile_sync_factory_impl.h',
'browser/sync/sync_setup_flow.cc',
'browser/sync/sync_setup_flow.h',
'browser/sync/sync_setup_wizard.cc',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 5f6fa02..1520411 100755
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -804,10 +804,15 @@
'browser/shell_integration_unittest.cc',
'browser/spellchecker_platform_engine_unittest.cc',
'browser/ssl/ssl_host_state_unittest.cc',
+ 'browser/sync/glue/change_processor_mock.h',
'browser/sync/glue/database_model_worker_unittest.cc',
'browser/sync/glue/http_bridge_unittest.cc',
'browser/sync/glue/ui_model_worker_unittest.cc',
+ 'browser/sync/profile_sync_service_mock.h',
'browser/sync/profile_sync_service_unittest.cc',
+ 'browser/sync/profile_sync_factory_impl_unittest.cc',
+ 'browser/sync/profile_sync_factory_mock.cc',
+ 'browser/sync/profile_sync_factory_mock.h',
'browser/sync/sync_setup_wizard_unittest.cc',
'browser/sync/sync_ui_util_mac_unittest.mm',
'browser/tab_contents/navigation_controller_unittest.cc',
@@ -1454,8 +1459,12 @@
'browser/sync/engine/syncer_thread_unittest.cc',
'browser/sync/engine/syncer_unittest.cc',
'browser/sync/engine/syncproto_unittest.cc',
+ 'browser/sync/glue/bookmark_data_type_controller_unittest.cc',
+ 'browser/sync/glue/change_processor_mock.h',
'browser/sync/notifier/base/mac/network_status_detector_task_mac_unittest.cc',
'browser/sync/notifier/listener/talk_mediator_unittest.cc',
+ 'browser/sync/profile_sync_factory_mock.cc',
+ 'browser/sync/profile_sync_factory_mock.h',
'browser/sync/sessions/status_controller_unittest.cc',
'browser/sync/sessions/sync_session_unittest.cc',
'browser/sync/syncable/directory_backing_store_unittest.cc',
@@ -1491,6 +1500,7 @@
'common',
'debugger',
'../skia/skia.gyp:skia',
+ '../testing/gmock.gyp:gmock',
'../testing/gtest.gyp:gtest',
'../third_party/libjingle/libjingle.gyp:libjingle',
'syncapi',
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 8b8fa20..69087d9 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -151,9 +151,12 @@ const char kDisableSharedWorkers[] = "disable-shared-workers";
// Disable site-specific tailoring to compatibility issues in WebKit.
const char kDisableSiteSpecificQuirks[] = "disable-site-specific-quirks";
-// Disable syncing bookmarks to a Google Account.
+// Disable syncing browser data to a Google Account.
const char kDisableSync[] = "disable-sync";
+// Disable syncing of bookmarks.
+const char kDisableSyncBookmarks[] = "disable-sync-bookmarks";
+
// Enables the backend service for web resources, used in the new tab page for
// loading tips and recommendations from a JSON feed.
const char kDisableWebResources[] = "disable-web-resources";
@@ -268,9 +271,12 @@ const char kEnableSessionStorage[] = "enable-session-storage";
// Enables StatsTable, logging statistics to a global named shared memory table.
const char kEnableStatsTable[] = "enable-stats-table";
-// Enable syncing bookmarks to a Google Account.
+// Enable syncing browser data to a Google Account.
const char kEnableSync[] = "enable-sync";
+// Enable syncing browser bookmarks.
+const char kEnableSyncBookmarks[] = "enable-sync-bookmarks";
+
// Whether the multiple profiles feature based on the user-data-dir flag is
// enabled or not.
const char kEnableUserDataDirProfiles[] = "enable-udd-profiles";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 141082e..953c5cb 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -59,6 +59,7 @@ extern const char kDisableRemoteFonts[];
extern const char kDisableSharedWorkers[];
extern const char kDisableSiteSpecificQuirks[];
extern const char kDisableSync[];
+extern const char kDisableSyncBookmarks[];
extern const char kDisableWebResources[];
extern const char kDisableWebSecurity[];
extern const char kDisableWebSockets[];
@@ -95,6 +96,7 @@ extern const char kEnableSeccompSandbox[];
extern const char kEnableSessionStorage[];
extern const char kEnableStatsTable[];
extern const char kEnableSync[];
+extern const char kEnableSyncBookmarks[];
extern const char kEnableUserDataDirProfiles[];
extern const char kEnableVerticalTabs[];
extern const char kEnableWatchdog[];