1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/sync/glue/ui_data_type_controller.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/tracked_objects.h"
11 #include "chrome/browser/sync/glue/fake_generic_change_processor.h"
12 #include "chrome/browser/sync/profile_sync_components_factory_mock.h"
13 #include "chrome/browser/sync/profile_sync_service_mock.h"
14 #include "chrome/test/base/profile_mock.h"
15 #include "components/sync_driver/data_type_controller_mock.h"
16 #include "content/public/test/test_browser_thread.h"
17 #include "sync/api/fake_syncable_service.h"
18 #include "testing/gtest/include/gtest/gtest.h"
20 using content::BrowserThread;
22 using testing::InvokeWithoutArgs;
23 using testing::Return;
25 namespace browser_sync {
28 ACTION(MakeSharedChangeProcessor) {
29 return new SharedChangeProcessor();
32 ACTION_P(ReturnAndRelease, change_processor) {
33 return change_processor->release();
36 // TODO(zea): Expand this to make the dtc type paramterizable. This will let us
37 // test the basic functionality of all UIDataTypeControllers. We'll need to have
38 // intelligent default values for the methods queried in the dependent services
39 // (e.g. those queried in StartModels).
40 class SyncUIDataTypeControllerTest : public testing::Test {
42 SyncUIDataTypeControllerTest()
43 : ui_thread_(BrowserThread::UI, &message_loop_),
44 profile_sync_service_(&profile_),
45 type_(syncer::PREFERENCES),
46 change_processor_(new FakeGenericChangeProcessor()) {}
48 virtual void SetUp() {
49 profile_sync_factory_.reset(new ProfileSyncComponentsFactoryMock());
51 new UIDataTypeController(base::MessageLoopProxy::current(),
54 profile_sync_factory_.get(),
56 &profile_sync_service_);
57 SetStartExpectations();
60 virtual void TearDown() {
61 // Must be done before we pump the loop.
62 syncable_service_.StopSyncing(type_);
63 preference_dtc_ = NULL;
68 void SetStartExpectations() {
69 // Ownership gets passed to caller of CreateGenericChangeProcessor.
70 change_processor_.reset(new FakeGenericChangeProcessor());
71 EXPECT_CALL(model_load_callback_, Run(_, _));
72 EXPECT_CALL(*profile_sync_factory_, GetSyncableServiceForType(type_)).
73 WillOnce(Return(syncable_service_.AsWeakPtr()));
74 EXPECT_CALL(*profile_sync_factory_, CreateSharedChangeProcessor()).
75 WillOnce(MakeSharedChangeProcessor());
76 EXPECT_CALL(*profile_sync_factory_,
77 CreateGenericChangeProcessor(_, _, _, _)).
78 WillOnce(ReturnAndRelease(&change_processor_));
81 void SetActivateExpectations() {
82 EXPECT_CALL(profile_sync_service_, ActivateDataType(type_, _, _));
85 void SetStopExpectations() {
86 EXPECT_CALL(profile_sync_service_, DeactivateDataType(type_));
90 preference_dtc_->LoadModels(
91 base::Bind(&ModelLoadCallbackMock::Run,
92 base::Unretained(&model_load_callback_)));
93 preference_dtc_->StartAssociating(
94 base::Bind(&StartCallbackMock::Run,
95 base::Unretained(&start_callback_)));
99 message_loop_.RunUntilIdle();
102 base::MessageLoopForUI message_loop_;
103 content::TestBrowserThread ui_thread_;
104 ProfileMock profile_;
105 scoped_ptr<ProfileSyncComponentsFactoryMock> profile_sync_factory_;
106 ProfileSyncServiceMock profile_sync_service_;
107 const syncer::ModelType type_;
108 StartCallbackMock start_callback_;
109 ModelLoadCallbackMock model_load_callback_;
110 scoped_refptr<UIDataTypeController> preference_dtc_;
111 scoped_ptr<FakeGenericChangeProcessor> change_processor_;
112 syncer::FakeSyncableService syncable_service_;
115 // Start the DTC. Verify that the callback is called with OK, the
116 // service has been told to start syncing and that the DTC is now in RUNNING
118 TEST_F(SyncUIDataTypeControllerTest, Start) {
119 SetActivateExpectations();
120 EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _, _));
122 EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
123 EXPECT_FALSE(syncable_service_.syncing());
125 EXPECT_EQ(DataTypeController::RUNNING, preference_dtc_->state());
126 EXPECT_TRUE(syncable_service_.syncing());
129 // Start and then stop the DTC. Verify that the service started and stopped
130 // syncing, and that the DTC went from RUNNING to NOT_RUNNING.
131 TEST_F(SyncUIDataTypeControllerTest, StartStop) {
132 SetActivateExpectations();
133 SetStopExpectations();
134 EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _, _));
136 EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
137 EXPECT_FALSE(syncable_service_.syncing());
139 EXPECT_EQ(DataTypeController::RUNNING, preference_dtc_->state());
140 EXPECT_TRUE(syncable_service_.syncing());
141 preference_dtc_->Stop();
142 EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
143 EXPECT_FALSE(syncable_service_.syncing());
146 // Start the DTC when no user nodes are created. Verify that the callback
147 // is called with OK_FIRST_RUN. Stop the DTC.
148 TEST_F(SyncUIDataTypeControllerTest, StartStopFirstRun) {
149 SetActivateExpectations();
150 SetStopExpectations();
151 EXPECT_CALL(start_callback_, Run(DataTypeController::OK_FIRST_RUN, _, _));
152 change_processor_->set_sync_model_has_user_created_nodes(false);
154 EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
155 EXPECT_FALSE(syncable_service_.syncing());
157 EXPECT_EQ(DataTypeController::RUNNING, preference_dtc_->state());
158 EXPECT_TRUE(syncable_service_.syncing());
159 preference_dtc_->Stop();
160 EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
161 EXPECT_FALSE(syncable_service_.syncing());
164 // Start the DTC, but have the service fail association. Verify the callback
165 // is called with ASSOCIATION_FAILED, the DTC goes to state DISABLED, and the
166 // service is not syncing. Then stop the DTC.
167 TEST_F(SyncUIDataTypeControllerTest, StartAssociationFailed) {
168 SetStopExpectations();
169 EXPECT_CALL(start_callback_,
170 Run(DataTypeController::ASSOCIATION_FAILED, _, _));
171 syncable_service_.set_merge_data_and_start_syncing_error(
172 syncer::SyncError(FROM_HERE,
173 syncer::SyncError::DATATYPE_ERROR,
177 EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
178 EXPECT_FALSE(syncable_service_.syncing());
180 EXPECT_EQ(DataTypeController::DISABLED, preference_dtc_->state());
181 EXPECT_FALSE(syncable_service_.syncing());
182 preference_dtc_->Stop();
183 EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
184 EXPECT_FALSE(syncable_service_.syncing());
187 // Start the DTC but fail to check if there are user created nodes. Verify the
188 // DTC calls the callback with UNRECOVERABLE_ERROR and that it goes into
189 // NOT_RUNNING state. Verify the syncable service is not syncing.
190 TEST_F(SyncUIDataTypeControllerTest,
191 StartAssociationTriggersUnrecoverableError) {
192 EXPECT_CALL(start_callback_,
193 Run(DataTypeController::UNRECOVERABLE_ERROR, _, _));
194 change_processor_->set_sync_model_has_user_created_nodes_success(false);
196 EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
197 EXPECT_FALSE(syncable_service_.syncing());
199 EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
200 EXPECT_FALSE(syncable_service_.syncing());
203 // Start the DTC, but then trigger an unrecoverable error. Verify the syncer
204 // gets stopped and the DTC is in NOT_RUNNING state.
205 TEST_F(SyncUIDataTypeControllerTest, OnSingleDatatypeUnrecoverableError) {
206 SetActivateExpectations();
207 EXPECT_CALL(profile_sync_service_, DisableBrokenDatatype(_,_,_)).
208 WillOnce(InvokeWithoutArgs(preference_dtc_.get(),
209 &UIDataTypeController::Stop));
210 SetStopExpectations();
211 EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _, _));
213 EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
214 EXPECT_FALSE(syncable_service_.syncing());
216 EXPECT_TRUE(syncable_service_.syncing());
217 preference_dtc_->OnSingleDatatypeUnrecoverableError(FROM_HERE, "Test");
219 EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
220 EXPECT_FALSE(syncable_service_.syncing());
224 } // namespace browser_sync