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 "testing/gtest/include/gtest/gtest.h"
8 #include "base/bind_helpers.h"
9 #include "base/callback.h"
10 #include "base/compiler_specific.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/synchronization/waitable_event.h"
14 #include "base/test/test_timeouts.h"
15 #include "base/tracked_objects.h"
16 #include "chrome/browser/sync/glue/non_frontend_data_type_controller.h"
17 #include "chrome/browser/sync/glue/non_frontend_data_type_controller_mock.h"
18 #include "chrome/browser/sync/profile_sync_components_factory_mock.h"
19 #include "chrome/browser/sync/profile_sync_service_mock.h"
20 #include "chrome/test/base/profile_mock.h"
21 #include "components/sync_driver/change_processor_mock.h"
22 #include "components/sync_driver/data_type_controller_mock.h"
23 #include "components/sync_driver/model_associator_mock.h"
24 #include "content/public/test/test_browser_thread.h"
25 #include "sync/internal_api/public/engine/model_safe_worker.h"
27 using base::WaitableEvent;
28 using syncer::GROUP_DB;
29 using browser_sync::NonFrontendDataTypeController;
30 using browser_sync::NonFrontendDataTypeControllerMock;
31 using sync_driver::ChangeProcessorMock;
32 using sync_driver::DataTypeController;
33 using sync_driver::ModelAssociatorMock;
34 using sync_driver::ModelLoadCallbackMock;
35 using sync_driver::StartCallbackMock;
36 using content::BrowserThread;
39 using testing::InvokeWithoutArgs;
40 using testing::Return;
41 using testing::SetArgumentPointee;
42 using testing::StrictMock;
44 ACTION_P(WaitOnEvent, event) {
48 ACTION_P(SignalEvent, event) {
52 class NonFrontendDataTypeControllerFake : public NonFrontendDataTypeController {
54 NonFrontendDataTypeControllerFake(
55 ProfileSyncComponentsFactory* profile_sync_factory,
57 ProfileSyncService* sync_service,
58 NonFrontendDataTypeControllerMock* mock)
59 : NonFrontendDataTypeController(base::MessageLoopProxy::current(),
66 syncer::ModelType type() const override { return syncer::BOOKMARKS; }
67 syncer::ModelSafeGroup model_safe_group() const override {
68 return syncer::GROUP_DB;
72 ~NonFrontendDataTypeControllerFake() override {}
74 ProfileSyncComponentsFactory::SyncComponents CreateSyncComponents() override {
75 return profile_sync_factory()->
76 CreateBookmarkSyncComponents(profile_sync_service(), this);
79 bool PostTaskOnBackendThread(const tracked_objects::Location& from_here,
80 const base::Closure& task) override {
81 return BrowserThread::PostTask(BrowserThread::DB, from_here, task);
84 // We mock the following methods because their default implementations do
85 // nothing, but we still want to make sure they're called appropriately.
86 bool StartModels() override { return mock_->StartModels(); }
87 void RecordUnrecoverableError(const tracked_objects::Location& from_here,
88 const std::string& message) override {
89 mock_->RecordUnrecoverableError(from_here, message);
91 void RecordAssociationTime(base::TimeDelta time) override {
92 mock_->RecordAssociationTime(time);
94 void RecordStartFailure(DataTypeController::ConfigureResult result) override {
95 mock_->RecordStartFailure(result);
97 void DisconnectProcessor(sync_driver::ChangeProcessor* processor) override {
98 mock_->DisconnectProcessor(processor);
102 NonFrontendDataTypeControllerMock* mock_;
105 class SyncNonFrontendDataTypeControllerTest : public testing::Test {
107 SyncNonFrontendDataTypeControllerTest()
108 : ui_thread_(BrowserThread::UI, &message_loop_),
109 db_thread_(BrowserThread::DB),
111 model_associator_(NULL),
112 change_processor_(NULL) {}
114 void SetUp() override {
116 profile_sync_factory_.reset(new ProfileSyncComponentsFactoryMock());
118 // All of these are refcounted, so don't need to be released.
119 dtc_mock_ = new StrictMock<NonFrontendDataTypeControllerMock>();
121 new NonFrontendDataTypeControllerFake(profile_sync_factory_.get(),
127 void TearDown() override {
128 if (non_frontend_dtc_->state() !=
129 NonFrontendDataTypeController::NOT_RUNNING) {
130 non_frontend_dtc_->Stop();
136 void SetStartExpectations() {
137 EXPECT_CALL(*dtc_mock_.get(), StartModels()).WillOnce(Return(true));
138 EXPECT_CALL(model_load_callback_, Run(_, _));
139 model_associator_ = new ModelAssociatorMock();
140 change_processor_ = new ChangeProcessorMock();
141 EXPECT_CALL(*profile_sync_factory_, CreateBookmarkSyncComponents(_, _)).
142 WillOnce(Return(ProfileSyncComponentsFactory::SyncComponents(
143 model_associator_, change_processor_)));
146 void SetAssociateExpectations() {
147 EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
148 WillOnce(Return(true));
149 EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
150 WillOnce(DoAll(SetArgumentPointee<0>(true), Return(true)));
151 EXPECT_CALL(*model_associator_, AssociateModels(_, _)).
152 WillOnce(Return(syncer::SyncError()));
153 EXPECT_CALL(*dtc_mock_.get(), RecordAssociationTime(_));
156 void SetActivateExpectations(DataTypeController::ConfigureResult result) {
157 EXPECT_CALL(start_callback_, Run(result, _, _));
160 void SetStopExpectations() {
161 EXPECT_CALL(*dtc_mock_.get(), DisconnectProcessor(_));
162 EXPECT_CALL(service_, DeactivateDataType(_));
163 EXPECT_CALL(*model_associator_, DisassociateModels()).
164 WillOnce(Return(syncer::SyncError()));
167 void SetStartFailExpectations(DataTypeController::ConfigureResult result) {
168 if (DataTypeController::IsUnrecoverableResult(result))
169 EXPECT_CALL(*dtc_mock_.get(), RecordUnrecoverableError(_, _));
170 if (model_associator_) {
171 EXPECT_CALL(*model_associator_, DisassociateModels()).
172 WillOnce(Return(syncer::SyncError()));
174 EXPECT_CALL(*dtc_mock_.get(), RecordStartFailure(result));
175 EXPECT_CALL(start_callback_, Run(result, _, _));
178 static void SignalDone(WaitableEvent* done) {
183 WaitableEvent done(true, false);
184 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
185 base::Bind(&SyncNonFrontendDataTypeControllerTest::SignalDone, &done));
186 done.TimedWait(TestTimeouts::action_timeout());
187 if (!done.IsSignaled()) {
188 ADD_FAILURE() << "Timed out waiting for DB thread to finish.";
190 base::MessageLoop::current()->RunUntilIdle();
194 non_frontend_dtc_->LoadModels(
195 base::Bind(&ModelLoadCallbackMock::Run,
196 base::Unretained(&model_load_callback_)));
197 non_frontend_dtc_->StartAssociating(
198 base::Bind(&StartCallbackMock::Run,
199 base::Unretained(&start_callback_)));
202 base::MessageLoopForUI message_loop_;
203 content::TestBrowserThread ui_thread_;
204 content::TestBrowserThread db_thread_;
205 scoped_refptr<NonFrontendDataTypeControllerFake> non_frontend_dtc_;
206 scoped_ptr<ProfileSyncComponentsFactoryMock> profile_sync_factory_;
207 scoped_refptr<NonFrontendDataTypeControllerMock> dtc_mock_;
208 ProfileMock profile_;
209 ProfileSyncServiceMock service_;
210 ModelAssociatorMock* model_associator_;
211 ChangeProcessorMock* change_processor_;
212 StartCallbackMock start_callback_;
213 ModelLoadCallbackMock model_load_callback_;
216 TEST_F(SyncNonFrontendDataTypeControllerTest, StartOk) {
217 SetStartExpectations();
218 SetAssociateExpectations();
219 SetActivateExpectations(DataTypeController::OK);
220 SetStopExpectations();
221 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
224 EXPECT_EQ(DataTypeController::RUNNING, non_frontend_dtc_->state());
227 TEST_F(SyncNonFrontendDataTypeControllerTest, StartFirstRun) {
228 SetStartExpectations();
229 EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
230 WillOnce(Return(true));
231 EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
232 WillOnce(DoAll(SetArgumentPointee<0>(false), Return(true)));
233 EXPECT_CALL(*model_associator_, AssociateModels(_, _)).
234 WillOnce(Return(syncer::SyncError()));
235 EXPECT_CALL(*dtc_mock_.get(), RecordAssociationTime(_));
236 SetActivateExpectations(DataTypeController::OK_FIRST_RUN);
237 SetStopExpectations();
238 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
241 EXPECT_EQ(DataTypeController::RUNNING, non_frontend_dtc_->state());
244 TEST_F(SyncNonFrontendDataTypeControllerTest, StartAssociationFailed) {
245 SetStartExpectations();
246 EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
247 WillOnce(Return(true));
248 EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
249 WillOnce(DoAll(SetArgumentPointee<0>(true), Return(true)));
250 EXPECT_CALL(*model_associator_, AssociateModels(_, _)).
252 Return(syncer::SyncError(FROM_HERE,
253 syncer::SyncError::DATATYPE_ERROR,
255 syncer::BOOKMARKS)));
256 EXPECT_CALL(*dtc_mock_.get(), RecordAssociationTime(_));
257 SetStartFailExpectations(DataTypeController::ASSOCIATION_FAILED);
258 // Set up association to fail with an association failed error.
259 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
262 EXPECT_EQ(DataTypeController::DISABLED, non_frontend_dtc_->state());
265 TEST_F(SyncNonFrontendDataTypeControllerTest,
266 StartAssociationTriggersUnrecoverableError) {
267 SetStartExpectations();
268 SetStartFailExpectations(DataTypeController::UNRECOVERABLE_ERROR);
269 // Set up association to fail with an unrecoverable error.
270 EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
271 WillRepeatedly(Return(true));
272 EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
273 WillRepeatedly(DoAll(SetArgumentPointee<0>(false), Return(false)));
274 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
277 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
280 TEST_F(SyncNonFrontendDataTypeControllerTest, StartAssociationCryptoNotReady) {
281 SetStartExpectations();
282 SetStartFailExpectations(DataTypeController::NEEDS_CRYPTO);
283 // Set up association to fail with a NEEDS_CRYPTO error.
284 EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
285 WillRepeatedly(Return(false));
286 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
289 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
292 // Trigger a Stop() call when we check if the model associator has user created
294 TEST_F(SyncNonFrontendDataTypeControllerTest, AbortDuringAssociationInactive) {
295 WaitableEvent wait_for_db_thread_pause(false, false);
296 WaitableEvent pause_db_thread(false, false);
298 SetStartExpectations();
299 EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
300 WillOnce(Return(true));
301 EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
303 SignalEvent(&wait_for_db_thread_pause),
304 WaitOnEvent(&pause_db_thread),
305 SetArgumentPointee<0>(true),
307 EXPECT_CALL(*model_associator_, AbortAssociation()).WillOnce(
308 SignalEvent(&pause_db_thread));
309 EXPECT_CALL(*model_associator_, AssociateModels(_, _)).
310 WillOnce(Return(syncer::SyncError()));
311 SetStopExpectations();
312 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
314 wait_for_db_thread_pause.Wait();
315 non_frontend_dtc_->Stop();
317 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
320 // Same as above but abort during the Activate call.
321 TEST_F(SyncNonFrontendDataTypeControllerTest, AbortDuringAssociationActivated) {
322 WaitableEvent wait_for_association_starts(false, false);
323 WaitableEvent wait_for_dtc_stop(false, false);
325 SetStartExpectations();
326 EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
327 WillOnce(Return(true));
328 EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
330 SetArgumentPointee<0>(true),
332 EXPECT_CALL(*model_associator_, AbortAssociation());
333 EXPECT_CALL(*model_associator_, AssociateModels(_, _)).
335 SignalEvent(&wait_for_association_starts),
336 WaitOnEvent(&wait_for_dtc_stop),
337 Return(syncer::SyncError())));
338 SetStopExpectations();
339 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
341 wait_for_association_starts.Wait();
342 non_frontend_dtc_->Stop();
343 wait_for_dtc_stop.Signal();
345 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
348 TEST_F(SyncNonFrontendDataTypeControllerTest, Stop) {
349 SetStartExpectations();
350 SetAssociateExpectations();
351 SetActivateExpectations(DataTypeController::OK);
352 SetStopExpectations();
353 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
356 EXPECT_EQ(DataTypeController::RUNNING, non_frontend_dtc_->state());
357 non_frontend_dtc_->Stop();
358 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
361 // Disabled due to http://crbug.com/388367
362 TEST_F(SyncNonFrontendDataTypeControllerTest,
363 DISABLED_OnSingleDataTypeUnrecoverableError) {
364 SetStartExpectations();
365 SetAssociateExpectations();
366 SetActivateExpectations(DataTypeController::OK);
367 EXPECT_CALL(*dtc_mock_.get(), RecordUnrecoverableError(_, "Test"));
368 EXPECT_CALL(service_, DisableDatatype(_))
369 .WillOnce(InvokeWithoutArgs(non_frontend_dtc_.get(),
370 &NonFrontendDataTypeController::Stop));
371 SetStopExpectations();
372 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
375 EXPECT_EQ(DataTypeController::RUNNING, non_frontend_dtc_->state());
376 // This should cause non_frontend_dtc_->Stop() to be called.
377 syncer::SyncError error(FROM_HERE,
378 syncer::SyncError::DATATYPE_ERROR,
380 non_frontend_dtc_->type());
381 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, base::Bind(
382 &NonFrontendDataTypeControllerFake::OnSingleDataTypeUnrecoverableError,
383 non_frontend_dtc_.get(),
386 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());