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/data_type_controller_mock.h"
17 #include "chrome/browser/sync/glue/non_ui_data_type_controller_mock.h"
18 #include "chrome/browser/sync/glue/shared_change_processor_mock.h"
19 #include "chrome/browser/sync/profile_sync_components_factory_mock.h"
20 #include "chrome/browser/sync/profile_sync_service_mock.h"
21 #include "chrome/test/base/profile_mock.h"
22 #include "content/public/test/test_browser_thread.h"
23 #include "sync/api/fake_syncable_service.h"
24 #include "sync/internal_api/public/engine/model_safe_worker.h"
25 #include "testing/gtest/include/gtest/gtest.h"
27 namespace browser_sync {
31 using base::WaitableEvent;
32 using content::BrowserThread;
33 using syncer::AUTOFILL_PROFILE;
35 using testing::AtLeast;
37 using testing::InvokeWithoutArgs;
39 using testing::Return;
40 using testing::SetArgumentPointee;
41 using testing::StrictMock;
43 ACTION_P(WaitOnEvent, event) {
47 ACTION_P(SignalEvent, event) {
51 ACTION_P(SaveChangeProcessor, scoped_change_processor) {
52 scoped_change_processor->reset(arg2);
55 ACTION_P(GetWeakPtrToSyncableService, syncable_service) {
56 // Have to do this within an Action to ensure it's not evaluated on the wrong
58 return syncable_service->AsWeakPtr();
61 class NonUIDataTypeControllerFake
62 : public NonUIDataTypeController {
64 NonUIDataTypeControllerFake(
65 ProfileSyncComponentsFactory* profile_sync_factory,
67 ProfileSyncService* sync_service,
68 NonUIDataTypeControllerMock* mock)
69 : NonUIDataTypeController(profile_sync_factory,
75 virtual syncer::ModelType type() const OVERRIDE {
76 return AUTOFILL_PROFILE;
78 virtual syncer::ModelSafeGroup model_safe_group() const OVERRIDE {
79 return syncer::GROUP_DB;
82 // Prevent tasks from being posted on the backend thread until
83 // UnblockBackendTasks() is called.
84 void BlockBackendTasks() {
88 // Post pending tasks on the backend thread and start allowing tasks
89 // to be posted on the backend thread again.
90 void UnblockBackendTasks() {
92 for (std::vector<PendingTask>::const_iterator it = pending_tasks_.begin();
93 it != pending_tasks_.end(); ++it) {
94 PostTaskOnBackendThread(it->from_here, it->task);
96 pending_tasks_.clear();
100 virtual bool PostTaskOnBackendThread(
101 const tracked_objects::Location& from_here,
102 const base::Closure& task) OVERRIDE {
104 pending_tasks_.push_back(PendingTask(from_here, task));
107 return BrowserThread::PostTask(BrowserThread::DB, from_here, task);
111 // We mock the following methods because their default implementations do
112 // nothing, but we still want to make sure they're called appropriately.
113 virtual bool StartModels() OVERRIDE {
114 return mock_->StartModels();
116 virtual void StopModels() OVERRIDE {
119 virtual void RecordUnrecoverableError(
120 const tracked_objects::Location& from_here,
121 const std::string& message) OVERRIDE {
122 mock_->RecordUnrecoverableError(from_here, message);
124 virtual void RecordAssociationTime(base::TimeDelta time) OVERRIDE {
125 mock_->RecordAssociationTime(time);
127 virtual void RecordStartFailure(DataTypeController::StartResult result)
129 mock_->RecordStartFailure(result);
133 virtual ~NonUIDataTypeControllerFake() {}
135 DISALLOW_COPY_AND_ASSIGN(NonUIDataTypeControllerFake);
138 PendingTask(const tracked_objects::Location& from_here,
139 const base::Closure& task)
140 : from_here(from_here), task(task) {}
142 tracked_objects::Location from_here;
147 std::vector<PendingTask> pending_tasks_;
148 NonUIDataTypeControllerMock* mock_;
151 class SyncNonUIDataTypeControllerTest : public testing::Test {
153 SyncNonUIDataTypeControllerTest()
154 : ui_thread_(BrowserThread::UI, &message_loop_),
155 db_thread_(BrowserThread::DB) {}
157 virtual void SetUp() OVERRIDE {
158 EXPECT_CALL(service_, GetUserShare()).WillRepeatedly(
159 Return((syncer::UserShare*)NULL));
161 profile_sync_factory_.reset(
162 new StrictMock<ProfileSyncComponentsFactoryMock>());
163 change_processor_ = new SharedChangeProcessorMock();
165 // All of these are refcounted, so don't need to be released.
166 dtc_mock_ = new StrictMock<NonUIDataTypeControllerMock>();
168 new NonUIDataTypeControllerFake(profile_sync_factory_.get(),
174 virtual void TearDown() OVERRIDE {
179 WaitableEvent done(true, false);
180 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
181 base::Bind(&SyncNonUIDataTypeControllerTest::SignalDone,
183 done.TimedWait(TestTimeouts::action_timeout());
184 if (!done.IsSignaled()) {
185 ADD_FAILURE() << "Timed out waiting for DB thread to finish.";
187 base::MessageLoop::current()->RunUntilIdle();
191 void SetStartExpectations() {
192 EXPECT_CALL(*dtc_mock_.get(), StartModels()).WillOnce(Return(true));
193 EXPECT_CALL(model_load_callback_, Run(_, _));
194 EXPECT_CALL(*profile_sync_factory_,
195 CreateSharedChangeProcessor()).
196 WillOnce(Return(change_processor_.get()));
199 void SetAssociateExpectations() {
200 EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _))
201 .WillOnce(GetWeakPtrToSyncableService(&syncable_service_));
202 EXPECT_CALL(*change_processor_.get(), CryptoReadyIfNecessary())
203 .WillOnce(Return(true));
204 EXPECT_CALL(*change_processor_.get(), ActivateDataType(_));
205 EXPECT_CALL(*change_processor_.get(), SyncModelHasUserCreatedNodes(_))
206 .WillOnce(DoAll(SetArgumentPointee<0>(true), Return(true)));
207 EXPECT_CALL(*change_processor_.get(), GetAllSyncDataReturnError(_,_))
208 .WillOnce(Return(syncer::SyncError()));
209 EXPECT_CALL(*change_processor_.get(), GetSyncCount()).WillOnce(Return(0));
210 EXPECT_CALL(*dtc_mock_.get(), RecordAssociationTime(_));
213 void SetActivateExpectations(DataTypeController::StartResult result) {
214 EXPECT_CALL(start_callback_, Run(result,_,_));
217 void SetStopExpectations() {
218 EXPECT_CALL(*dtc_mock_.get(), StopModels());
219 EXPECT_CALL(*change_processor_.get(), Disconnect()).WillOnce(Return(true));
220 EXPECT_CALL(service_, DeactivateDataType(_));
223 void SetStartFailExpectations(DataTypeController::StartResult result) {
224 EXPECT_CALL(*dtc_mock_.get(), StopModels()).Times(AtLeast(1));
225 if (DataTypeController::IsUnrecoverableResult(result))
226 EXPECT_CALL(*dtc_mock_.get(), RecordUnrecoverableError(_, _));
227 EXPECT_CALL(*dtc_mock_.get(), RecordStartFailure(result));
228 EXPECT_CALL(start_callback_, Run(result, _, _));
232 non_ui_dtc_->LoadModels(
233 base::Bind(&ModelLoadCallbackMock::Run,
234 base::Unretained(&model_load_callback_)));
235 non_ui_dtc_->StartAssociating(
236 base::Bind(&StartCallbackMock::Run,
237 base::Unretained(&start_callback_)));
240 static void SignalDone(WaitableEvent* done) {
244 base::MessageLoopForUI message_loop_;
245 content::TestBrowserThread ui_thread_;
246 content::TestBrowserThread db_thread_;
247 ProfileMock profile_;
248 scoped_ptr<ProfileSyncComponentsFactoryMock> profile_sync_factory_;
249 StrictMock<ProfileSyncServiceMock> service_;
250 StartCallbackMock start_callback_;
251 ModelLoadCallbackMock model_load_callback_;
252 // Must be destroyed after non_ui_dtc_.
253 syncer::FakeSyncableService syncable_service_;
254 scoped_refptr<NonUIDataTypeControllerFake> non_ui_dtc_;
255 scoped_refptr<NonUIDataTypeControllerMock> dtc_mock_;
256 scoped_refptr<SharedChangeProcessorMock> change_processor_;
257 scoped_ptr<syncer::SyncChangeProcessor> saved_change_processor_;
260 TEST_F(SyncNonUIDataTypeControllerTest, StartOk) {
261 SetStartExpectations();
262 SetAssociateExpectations();
263 SetActivateExpectations(DataTypeController::OK);
264 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
267 EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state());
270 TEST_F(SyncNonUIDataTypeControllerTest, StartFirstRun) {
271 SetStartExpectations();
272 EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _))
273 .WillOnce(GetWeakPtrToSyncableService(&syncable_service_));
274 EXPECT_CALL(*change_processor_.get(), CryptoReadyIfNecessary())
275 .WillOnce(Return(true));
276 EXPECT_CALL(*change_processor_.get(), SyncModelHasUserCreatedNodes(_))
277 .WillOnce(DoAll(SetArgumentPointee<0>(false), Return(true)));
278 EXPECT_CALL(*change_processor_.get(), GetAllSyncDataReturnError(_,_))
279 .WillOnce(Return(syncer::SyncError()));
280 EXPECT_CALL(*dtc_mock_.get(), RecordAssociationTime(_));
281 SetActivateExpectations(DataTypeController::OK_FIRST_RUN);
282 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
285 EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state());
288 // Start the DTC and have StartModels() return false. Then, stop the
289 // DTC without finishing model startup. It should stop cleanly.
290 TEST_F(SyncNonUIDataTypeControllerTest, AbortDuringStartModels) {
291 EXPECT_CALL(*profile_sync_factory_,
292 CreateSharedChangeProcessor()).
293 WillOnce(Return(change_processor_.get()));
294 EXPECT_CALL(*dtc_mock_.get(), StartModels()).WillOnce(Return(false));
295 EXPECT_CALL(*dtc_mock_.get(), StopModels());
296 EXPECT_CALL(model_load_callback_, Run(_, _));
297 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
298 non_ui_dtc_->LoadModels(
299 base::Bind(&ModelLoadCallbackMock::Run,
300 base::Unretained(&model_load_callback_)));
302 EXPECT_EQ(DataTypeController::MODEL_STARTING, non_ui_dtc_->state());
304 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
307 // Start the DTC and have MergeDataAndStartSyncing() return an error.
308 // The DTC should become disabled, and the DTC should still stop
310 TEST_F(SyncNonUIDataTypeControllerTest, StartAssociationFailed) {
311 SetStartExpectations();
312 EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _))
313 .WillOnce(GetWeakPtrToSyncableService(&syncable_service_));
314 EXPECT_CALL(*change_processor_.get(), CryptoReadyIfNecessary())
315 .WillOnce(Return(true));
316 EXPECT_CALL(*change_processor_.get(), SyncModelHasUserCreatedNodes(_))
317 .WillOnce(DoAll(SetArgumentPointee<0>(true), Return(true)));
318 EXPECT_CALL(*change_processor_.get(), GetAllSyncDataReturnError(_,_))
319 .WillOnce(Return(syncer::SyncError()));
320 EXPECT_CALL(*dtc_mock_.get(), RecordAssociationTime(_));
321 SetStartFailExpectations(DataTypeController::ASSOCIATION_FAILED);
322 // Set up association to fail with an association failed error.
323 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
324 syncable_service_.set_merge_data_and_start_syncing_error(
325 syncer::SyncError(FROM_HERE,
326 syncer::SyncError::DATATYPE_ERROR,
328 non_ui_dtc_->type()));
331 EXPECT_EQ(DataTypeController::DISABLED, non_ui_dtc_->state());
333 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
336 TEST_F(SyncNonUIDataTypeControllerTest,
337 StartAssociationTriggersUnrecoverableError) {
338 SetStartExpectations();
339 SetStartFailExpectations(DataTypeController::UNRECOVERABLE_ERROR);
340 // Set up association to fail with an unrecoverable error.
341 EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _))
342 .WillOnce(GetWeakPtrToSyncableService(&syncable_service_));
343 EXPECT_CALL(*change_processor_.get(), CryptoReadyIfNecessary())
344 .WillRepeatedly(Return(true));
345 EXPECT_CALL(*change_processor_.get(), SyncModelHasUserCreatedNodes(_))
346 .WillRepeatedly(DoAll(SetArgumentPointee<0>(false), Return(false)));
347 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
350 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
353 TEST_F(SyncNonUIDataTypeControllerTest,
354 StartAssociationCryptoNotReady) {
355 SetStartExpectations();
356 SetStartFailExpectations(DataTypeController::NEEDS_CRYPTO);
357 // Set up association to fail with a NEEDS_CRYPTO error.
358 EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _))
359 .WillOnce(GetWeakPtrToSyncableService(&syncable_service_));
360 EXPECT_CALL(*change_processor_.get(), CryptoReadyIfNecessary())
361 .WillRepeatedly(Return(false));
362 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
365 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
368 // Trigger a Stop() call when we check if the model associator has user created
370 TEST_F(SyncNonUIDataTypeControllerTest, AbortDuringAssociation) {
371 WaitableEvent wait_for_db_thread_pause(false, false);
372 WaitableEvent pause_db_thread(false, false);
374 SetStartExpectations();
375 SetStartFailExpectations(DataTypeController::ABORTED);
376 EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _))
377 .WillOnce(GetWeakPtrToSyncableService(&syncable_service_));
378 EXPECT_CALL(*change_processor_.get(), CryptoReadyIfNecessary())
379 .WillOnce(Return(true));
380 EXPECT_CALL(*change_processor_.get(), SyncModelHasUserCreatedNodes(_))
381 .WillOnce(DoAll(SignalEvent(&wait_for_db_thread_pause),
382 WaitOnEvent(&pause_db_thread),
383 SetArgumentPointee<0>(true),
385 EXPECT_CALL(*change_processor_.get(), GetAllSyncDataReturnError(_,_))
387 Return(syncer::SyncError(FROM_HERE,
388 syncer::SyncError::DATATYPE_ERROR,
391 EXPECT_CALL(*change_processor_.get(), Disconnect())
392 .WillOnce(DoAll(SignalEvent(&pause_db_thread), Return(true)));
393 EXPECT_CALL(service_, DeactivateDataType(_));
394 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
396 wait_for_db_thread_pause.Wait();
399 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
402 // Start the DTC while the backend tasks are blocked. Then stop the DTC before
403 // the backend tasks get a chance to run. The DTC should have no interaction
404 // with the profile sync factory or profile sync service once stopped.
405 TEST_F(SyncNonUIDataTypeControllerTest, StartAfterSyncShutdown) {
406 non_ui_dtc_->BlockBackendTasks();
408 SetStartExpectations();
409 // We don't expect StopSyncing to be called because local_service_ will never
411 EXPECT_CALL(*change_processor_.get(), Disconnect()).WillOnce(Return(true));
412 EXPECT_CALL(*dtc_mock_.get(), StopModels());
413 EXPECT_CALL(service_, DeactivateDataType(_));
414 EXPECT_CALL(*dtc_mock_.get(),
415 RecordStartFailure(DataTypeController::ABORTED));
416 EXPECT_CALL(start_callback_, Run(DataTypeController::ABORTED, _, _));
417 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
420 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
421 Mock::VerifyAndClearExpectations(&profile_sync_factory_);
422 Mock::VerifyAndClearExpectations(&service_);
423 Mock::VerifyAndClearExpectations(change_processor_.get());
424 Mock::VerifyAndClearExpectations(dtc_mock_.get());
426 EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _))
427 .WillOnce(Return(base::WeakPtr<syncer::SyncableService>()));
428 non_ui_dtc_->UnblockBackendTasks();
432 TEST_F(SyncNonUIDataTypeControllerTest, Stop) {
433 SetStartExpectations();
434 SetAssociateExpectations();
435 SetActivateExpectations(DataTypeController::OK);
436 SetStopExpectations();
437 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
440 EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state());
442 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
445 // Start the DTC then block its backend tasks. While its backend
446 // tasks are blocked, stop and start it again, then unblock its
447 // backend tasks. The (delayed) running of the backend tasks from the
448 // stop after the restart shouldn't cause any problems.
449 TEST_F(SyncNonUIDataTypeControllerTest, StopStart) {
450 SetStartExpectations();
451 SetAssociateExpectations();
452 SetActivateExpectations(DataTypeController::OK);
453 SetStopExpectations();
454 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
457 EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state());
459 non_ui_dtc_->BlockBackendTasks();
461 Mock::VerifyAndClearExpectations(&profile_sync_factory_);
462 SetStartExpectations();
463 SetAssociateExpectations();
464 SetActivateExpectations(DataTypeController::OK);
465 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
467 non_ui_dtc_->UnblockBackendTasks();
470 EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state());
473 TEST_F(SyncNonUIDataTypeControllerTest,
474 OnSingleDatatypeUnrecoverableError) {
475 SetStartExpectations();
476 SetAssociateExpectations();
477 SetActivateExpectations(DataTypeController::OK);
478 EXPECT_CALL(*dtc_mock_.get(), RecordUnrecoverableError(_, "Test"));
479 EXPECT_CALL(service_, DisableBrokenDatatype(_, _, _)).WillOnce(
480 InvokeWithoutArgs(non_ui_dtc_.get(), &NonUIDataTypeController::Stop));
481 SetStopExpectations();
482 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
485 EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state());
486 // This should cause non_ui_dtc_->Stop() to be called.
487 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, base::Bind(
488 &NonUIDataTypeControllerFake::
489 OnSingleDatatypeUnrecoverableError,
492 std::string("Test")));
494 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
499 } // namespace browser_sync