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/non_ui_data_type_controller.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_ui_data_type_controller_mock.h"
17 #include "chrome/browser/sync/profile_sync_components_factory_mock.h"
18 #include "chrome/browser/sync/profile_sync_service_mock.h"
19 #include "components/sync_driver/data_type_controller_mock.h"
20 #include "components/sync_driver/generic_change_processor_factory.h"
21 #include "content/public/test/test_browser_thread.h"
22 #include "sync/api/fake_syncable_service.h"
23 #include "sync/internal_api/public/engine/model_safe_worker.h"
24 #include "testing/gtest/include/gtest/gtest.h"
26 namespace browser_sync {
30 using base::WaitableEvent;
31 using content::BrowserThread;
32 using syncer::AUTOFILL_PROFILE;
34 using testing::AtLeast;
36 using testing::InvokeWithoutArgs;
38 using testing::Return;
39 using testing::SetArgumentPointee;
40 using testing::StrictMock;
42 ACTION_P(WaitOnEvent, event) {
46 ACTION_P(SignalEvent, event) {
50 ACTION_P(SaveChangeProcessor, scoped_change_processor) {
51 scoped_change_processor->reset(arg2);
54 ACTION_P(GetWeakPtrToSyncableService, syncable_service) {
55 // Have to do this within an Action to ensure it's not evaluated on the wrong
57 return syncable_service->AsWeakPtr();
60 class SharedChangeProcessorMock : public SharedChangeProcessor {
62 SharedChangeProcessorMock() {}
64 MOCK_METHOD6(Connect, base::WeakPtr<syncer::SyncableService>(
65 browser_sync::SyncApiComponentFactory*,
66 GenericChangeProcessorFactory*,
68 DataTypeErrorHandler*,
70 const base::WeakPtr<syncer::SyncMergeResult>&));
71 MOCK_METHOD0(Disconnect, bool());
72 MOCK_METHOD2(ProcessSyncChanges,
73 syncer::SyncError(const tracked_objects::Location&,
74 const syncer::SyncChangeList&));
75 MOCK_CONST_METHOD2(GetAllSyncDataReturnError,
76 syncer::SyncError(syncer::ModelType,
77 syncer::SyncDataList*));
78 MOCK_METHOD0(GetSyncCount, int());
79 MOCK_METHOD1(SyncModelHasUserCreatedNodes,
81 MOCK_METHOD0(CryptoReadyIfNecessary, bool());
82 MOCK_CONST_METHOD1(GetDataTypeContext, bool(std::string*));
85 virtual ~SharedChangeProcessorMock() {}
86 MOCK_METHOD2(OnUnrecoverableError, void(const tracked_objects::Location&,
90 DISALLOW_COPY_AND_ASSIGN(SharedChangeProcessorMock);
93 class NonUIDataTypeControllerFake
94 : public NonUIDataTypeController {
96 NonUIDataTypeControllerFake(
97 ProfileSyncComponentsFactory* profile_sync_factory,
99 ProfileSyncService* sync_service,
100 NonUIDataTypeControllerMock* mock,
101 SharedChangeProcessor* change_processor)
102 : NonUIDataTypeController(
103 base::MessageLoopProxy::current(),
105 profile_sync_factory,
110 change_processor_(change_processor) {}
112 virtual syncer::ModelType type() const OVERRIDE {
113 return AUTOFILL_PROFILE;
115 virtual syncer::ModelSafeGroup model_safe_group() const OVERRIDE {
116 return syncer::GROUP_DB;
119 // Prevent tasks from being posted on the backend thread until
120 // UnblockBackendTasks() is called.
121 void BlockBackendTasks() {
125 // Post pending tasks on the backend thread and start allowing tasks
126 // to be posted on the backend thread again.
127 void UnblockBackendTasks() {
129 for (std::vector<PendingTask>::const_iterator it = pending_tasks_.begin();
130 it != pending_tasks_.end(); ++it) {
131 PostTaskOnBackendThread(it->from_here, it->task);
133 pending_tasks_.clear();
136 virtual SharedChangeProcessor* CreateSharedChangeProcessor() OVERRIDE {
137 return change_processor_;
141 virtual bool PostTaskOnBackendThread(
142 const tracked_objects::Location& from_here,
143 const base::Closure& task) OVERRIDE {
145 pending_tasks_.push_back(PendingTask(from_here, task));
148 return BrowserThread::PostTask(BrowserThread::DB, from_here, task);
152 // We mock the following methods because their default implementations do
153 // nothing, but we still want to make sure they're called appropriately.
154 virtual bool StartModels() OVERRIDE {
155 return mock_->StartModels();
157 virtual void StopModels() OVERRIDE {
160 virtual void RecordUnrecoverableError(
161 const tracked_objects::Location& from_here,
162 const std::string& message) OVERRIDE {
163 mock_->RecordUnrecoverableError(from_here, message);
165 virtual void RecordAssociationTime(base::TimeDelta time) OVERRIDE {
166 mock_->RecordAssociationTime(time);
168 virtual void RecordStartFailure(DataTypeController::StartResult result)
170 mock_->RecordStartFailure(result);
174 virtual ~NonUIDataTypeControllerFake() {}
176 DISALLOW_COPY_AND_ASSIGN(NonUIDataTypeControllerFake);
179 PendingTask(const tracked_objects::Location& from_here,
180 const base::Closure& task)
181 : from_here(from_here), task(task) {}
183 tracked_objects::Location from_here;
188 std::vector<PendingTask> pending_tasks_;
189 NonUIDataTypeControllerMock* mock_;
190 scoped_refptr<SharedChangeProcessor> change_processor_;
193 class SyncNonUIDataTypeControllerTest : public testing::Test {
195 SyncNonUIDataTypeControllerTest()
196 : ui_thread_(BrowserThread::UI, &message_loop_),
197 db_thread_(BrowserThread::DB), service_(&profile_) {}
199 virtual void SetUp() OVERRIDE {
200 EXPECT_CALL(service_, GetUserShare()).WillRepeatedly(
201 Return((syncer::UserShare*)NULL));
203 profile_sync_factory_.reset(
204 new StrictMock<ProfileSyncComponentsFactoryMock>());
205 change_processor_ = new SharedChangeProcessorMock();
206 // All of these are refcounted, so don't need to be released.
207 dtc_mock_ = new StrictMock<NonUIDataTypeControllerMock>();
209 new NonUIDataTypeControllerFake(profile_sync_factory_.get(),
216 virtual void TearDown() OVERRIDE {
221 WaitableEvent done(true, false);
222 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
223 base::Bind(&SyncNonUIDataTypeControllerTest::SignalDone,
225 done.TimedWait(TestTimeouts::action_timeout());
226 if (!done.IsSignaled()) {
227 ADD_FAILURE() << "Timed out waiting for DB thread to finish.";
229 base::MessageLoop::current()->RunUntilIdle();
233 void SetStartExpectations() {
234 EXPECT_CALL(*dtc_mock_.get(), StartModels()).WillOnce(Return(true));
235 EXPECT_CALL(model_load_callback_, Run(_, _));
238 void SetAssociateExpectations() {
239 EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _, _))
240 .WillOnce(GetWeakPtrToSyncableService(&syncable_service_));
241 EXPECT_CALL(*change_processor_.get(), CryptoReadyIfNecessary())
242 .WillOnce(Return(true));
243 EXPECT_CALL(*change_processor_.get(), SyncModelHasUserCreatedNodes(_))
244 .WillOnce(DoAll(SetArgumentPointee<0>(true), Return(true)));
245 EXPECT_CALL(*change_processor_.get(), GetAllSyncDataReturnError(_,_))
246 .WillOnce(Return(syncer::SyncError()));
247 EXPECT_CALL(*change_processor_.get(), GetSyncCount()).WillOnce(Return(0));
248 EXPECT_CALL(*dtc_mock_.get(), RecordAssociationTime(_));
251 void SetActivateExpectations(DataTypeController::StartResult result) {
252 EXPECT_CALL(start_callback_, Run(result,_,_));
255 void SetStopExpectations() {
256 EXPECT_CALL(*dtc_mock_.get(), StopModels());
257 EXPECT_CALL(*change_processor_.get(), Disconnect()).WillOnce(Return(true));
258 EXPECT_CALL(service_, DeactivateDataType(_));
261 void SetStartFailExpectations(DataTypeController::StartResult result) {
262 EXPECT_CALL(*dtc_mock_.get(), StopModels()).Times(AtLeast(1));
263 if (DataTypeController::IsUnrecoverableResult(result))
264 EXPECT_CALL(*dtc_mock_.get(), RecordUnrecoverableError(_, _));
265 EXPECT_CALL(*dtc_mock_.get(), RecordStartFailure(result));
266 EXPECT_CALL(start_callback_, Run(result, _, _));
270 non_ui_dtc_->LoadModels(
271 base::Bind(&ModelLoadCallbackMock::Run,
272 base::Unretained(&model_load_callback_)));
273 non_ui_dtc_->StartAssociating(
274 base::Bind(&StartCallbackMock::Run,
275 base::Unretained(&start_callback_)));
278 static void SignalDone(WaitableEvent* done) {
282 base::MessageLoopForUI message_loop_;
283 content::TestBrowserThread ui_thread_;
284 content::TestBrowserThread db_thread_;
285 TestingProfile profile_;
286 scoped_ptr<ProfileSyncComponentsFactoryMock> profile_sync_factory_;
287 StrictMock<ProfileSyncServiceMock> service_;
288 StartCallbackMock start_callback_;
289 ModelLoadCallbackMock model_load_callback_;
290 // Must be destroyed after non_ui_dtc_.
291 syncer::FakeSyncableService syncable_service_;
292 scoped_refptr<NonUIDataTypeControllerFake> non_ui_dtc_;
293 scoped_refptr<NonUIDataTypeControllerMock> dtc_mock_;
294 scoped_refptr<SharedChangeProcessorMock> change_processor_;
295 scoped_ptr<syncer::SyncChangeProcessor> saved_change_processor_;
298 TEST_F(SyncNonUIDataTypeControllerTest, StartOk) {
299 SetStartExpectations();
300 SetAssociateExpectations();
301 SetActivateExpectations(DataTypeController::OK);
302 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
305 EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state());
308 TEST_F(SyncNonUIDataTypeControllerTest, StartFirstRun) {
309 SetStartExpectations();
310 EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _, _))
311 .WillOnce(GetWeakPtrToSyncableService(&syncable_service_));
312 EXPECT_CALL(*change_processor_.get(), CryptoReadyIfNecessary())
313 .WillOnce(Return(true));
314 EXPECT_CALL(*change_processor_.get(), SyncModelHasUserCreatedNodes(_))
315 .WillOnce(DoAll(SetArgumentPointee<0>(false), Return(true)));
316 EXPECT_CALL(*change_processor_.get(), GetAllSyncDataReturnError(_,_))
317 .WillOnce(Return(syncer::SyncError()));
318 EXPECT_CALL(*dtc_mock_.get(), RecordAssociationTime(_));
319 SetActivateExpectations(DataTypeController::OK_FIRST_RUN);
320 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
323 EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state());
326 // Start the DTC and have StartModels() return false. Then, stop the
327 // DTC without finishing model startup. It should stop cleanly.
328 TEST_F(SyncNonUIDataTypeControllerTest, AbortDuringStartModels) {
329 EXPECT_CALL(*dtc_mock_.get(), StartModels()).WillOnce(Return(false));
330 EXPECT_CALL(*dtc_mock_.get(), StopModels());
331 EXPECT_CALL(model_load_callback_, Run(_, _));
332 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
333 non_ui_dtc_->LoadModels(
334 base::Bind(&ModelLoadCallbackMock::Run,
335 base::Unretained(&model_load_callback_)));
337 EXPECT_EQ(DataTypeController::MODEL_STARTING, non_ui_dtc_->state());
339 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
342 // Start the DTC and have MergeDataAndStartSyncing() return an error.
343 // The DTC should become disabled, and the DTC should still stop
345 TEST_F(SyncNonUIDataTypeControllerTest, StartAssociationFailed) {
346 SetStartExpectations();
347 EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _, _))
348 .WillOnce(GetWeakPtrToSyncableService(&syncable_service_));
349 EXPECT_CALL(*change_processor_.get(), CryptoReadyIfNecessary())
350 .WillOnce(Return(true));
351 EXPECT_CALL(*change_processor_.get(), SyncModelHasUserCreatedNodes(_))
352 .WillOnce(DoAll(SetArgumentPointee<0>(true), Return(true)));
353 EXPECT_CALL(*change_processor_.get(), GetAllSyncDataReturnError(_,_))
354 .WillOnce(Return(syncer::SyncError()));
355 EXPECT_CALL(*dtc_mock_.get(), RecordAssociationTime(_));
356 SetStartFailExpectations(DataTypeController::ASSOCIATION_FAILED);
357 // Set up association to fail with an association failed error.
358 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
359 syncable_service_.set_merge_data_and_start_syncing_error(
360 syncer::SyncError(FROM_HERE,
361 syncer::SyncError::DATATYPE_ERROR,
363 non_ui_dtc_->type()));
366 EXPECT_EQ(DataTypeController::DISABLED, non_ui_dtc_->state());
368 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
371 TEST_F(SyncNonUIDataTypeControllerTest,
372 StartAssociationTriggersUnrecoverableError) {
373 SetStartExpectations();
374 SetStartFailExpectations(DataTypeController::UNRECOVERABLE_ERROR);
375 // Set up association to fail with an unrecoverable error.
376 EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _, _))
377 .WillOnce(GetWeakPtrToSyncableService(&syncable_service_));
378 EXPECT_CALL(*change_processor_.get(), CryptoReadyIfNecessary())
379 .WillRepeatedly(Return(true));
380 EXPECT_CALL(*change_processor_.get(), SyncModelHasUserCreatedNodes(_))
381 .WillRepeatedly(DoAll(SetArgumentPointee<0>(false), Return(false)));
382 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
385 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
388 TEST_F(SyncNonUIDataTypeControllerTest,
389 StartAssociationCryptoNotReady) {
390 SetStartExpectations();
391 SetStartFailExpectations(DataTypeController::NEEDS_CRYPTO);
392 // Set up association to fail with a NEEDS_CRYPTO error.
393 EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _, _))
394 .WillOnce(GetWeakPtrToSyncableService(&syncable_service_));
395 EXPECT_CALL(*change_processor_.get(), CryptoReadyIfNecessary())
396 .WillRepeatedly(Return(false));
397 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
400 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
403 // Trigger a Stop() call when we check if the model associator has user created
405 TEST_F(SyncNonUIDataTypeControllerTest, AbortDuringAssociation) {
406 WaitableEvent wait_for_db_thread_pause(false, false);
407 WaitableEvent pause_db_thread(false, false);
409 SetStartExpectations();
410 SetStartFailExpectations(DataTypeController::ABORTED);
411 EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _, _))
412 .WillOnce(GetWeakPtrToSyncableService(&syncable_service_));
413 EXPECT_CALL(*change_processor_.get(), CryptoReadyIfNecessary())
414 .WillOnce(Return(true));
415 EXPECT_CALL(*change_processor_.get(), SyncModelHasUserCreatedNodes(_))
416 .WillOnce(DoAll(SignalEvent(&wait_for_db_thread_pause),
417 WaitOnEvent(&pause_db_thread),
418 SetArgumentPointee<0>(true),
420 EXPECT_CALL(*change_processor_.get(), GetAllSyncDataReturnError(_,_))
422 Return(syncer::SyncError(FROM_HERE,
423 syncer::SyncError::DATATYPE_ERROR,
426 EXPECT_CALL(*change_processor_.get(), Disconnect())
427 .WillOnce(DoAll(SignalEvent(&pause_db_thread), Return(true)));
428 EXPECT_CALL(service_, DeactivateDataType(_));
429 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
431 wait_for_db_thread_pause.Wait();
434 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
437 // Start the DTC while the backend tasks are blocked. Then stop the DTC before
438 // the backend tasks get a chance to run. The DTC should have no interaction
439 // with the profile sync factory or profile sync service once stopped.
440 TEST_F(SyncNonUIDataTypeControllerTest, StartAfterSyncShutdown) {
441 non_ui_dtc_->BlockBackendTasks();
443 SetStartExpectations();
444 // We don't expect StopSyncing to be called because local_service_ will never
446 EXPECT_CALL(*change_processor_.get(), Disconnect()).WillOnce(Return(true));
447 EXPECT_CALL(*dtc_mock_.get(), StopModels());
448 EXPECT_CALL(service_, DeactivateDataType(_));
449 EXPECT_CALL(*dtc_mock_.get(),
450 RecordStartFailure(DataTypeController::ABORTED));
451 EXPECT_CALL(start_callback_, Run(DataTypeController::ABORTED, _, _));
452 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
455 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
456 Mock::VerifyAndClearExpectations(&profile_sync_factory_);
457 Mock::VerifyAndClearExpectations(&service_);
458 Mock::VerifyAndClearExpectations(change_processor_.get());
459 Mock::VerifyAndClearExpectations(dtc_mock_.get());
461 EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _, _))
462 .WillOnce(Return(base::WeakPtr<syncer::SyncableService>()));
463 non_ui_dtc_->UnblockBackendTasks();
467 TEST_F(SyncNonUIDataTypeControllerTest, Stop) {
468 SetStartExpectations();
469 SetAssociateExpectations();
470 SetActivateExpectations(DataTypeController::OK);
471 SetStopExpectations();
472 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
475 EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state());
477 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
480 // Start the DTC then block its backend tasks. While its backend
481 // tasks are blocked, stop and start it again, then unblock its
482 // backend tasks. The (delayed) running of the backend tasks from the
483 // stop after the restart shouldn't cause any problems.
484 TEST_F(SyncNonUIDataTypeControllerTest, StopStart) {
485 SetStartExpectations();
486 SetAssociateExpectations();
487 SetActivateExpectations(DataTypeController::OK);
488 SetStopExpectations();
489 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
492 EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state());
494 non_ui_dtc_->BlockBackendTasks();
496 Mock::VerifyAndClearExpectations(&profile_sync_factory_);
497 SetStartExpectations();
498 SetAssociateExpectations();
499 SetActivateExpectations(DataTypeController::OK);
500 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
502 non_ui_dtc_->UnblockBackendTasks();
505 EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state());
508 TEST_F(SyncNonUIDataTypeControllerTest,
509 OnSingleDatatypeUnrecoverableError) {
510 SetStartExpectations();
511 SetAssociateExpectations();
512 SetActivateExpectations(DataTypeController::OK);
513 EXPECT_CALL(*dtc_mock_.get(), RecordUnrecoverableError(_, "Test"));
514 EXPECT_CALL(service_, DisableBrokenDatatype(_, _, _)).WillOnce(
515 InvokeWithoutArgs(non_ui_dtc_.get(), &NonUIDataTypeController::Stop));
516 SetStopExpectations();
517 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
520 EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state());
521 // This should cause non_ui_dtc_->Stop() to be called.
522 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, base::Bind(
523 &NonUIDataTypeControllerFake::
524 OnSingleDatatypeUnrecoverableError,
527 std::string("Test")));
529 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
534 } // namespace browser_sync