- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / sync / glue / non_ui_data_type_controller_unittest.cc
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.
4
5 #include "chrome/browser/sync/glue/non_ui_data_type_controller.h"
6
7 #include "base/bind.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"
26
27 namespace browser_sync {
28
29 namespace {
30
31 using base::WaitableEvent;
32 using content::BrowserThread;
33 using syncer::AUTOFILL_PROFILE;
34 using testing::_;
35 using testing::AtLeast;
36 using testing::DoAll;
37 using testing::InvokeWithoutArgs;
38 using testing::Mock;
39 using testing::Return;
40 using testing::SetArgumentPointee;
41 using testing::StrictMock;
42
43 ACTION_P(WaitOnEvent, event) {
44   event->Wait();
45 }
46
47 ACTION_P(SignalEvent, event) {
48   event->Signal();
49 }
50
51 ACTION_P(SaveChangeProcessor, scoped_change_processor) {
52   scoped_change_processor->reset(arg2);
53 }
54
55 ACTION_P(GetWeakPtrToSyncableService, syncable_service) {
56   // Have to do this within an Action to ensure it's not evaluated on the wrong
57   // thread.
58   return syncable_service->AsWeakPtr();
59 }
60
61 class NonUIDataTypeControllerFake
62     : public NonUIDataTypeController {
63  public:
64   NonUIDataTypeControllerFake(
65       ProfileSyncComponentsFactory* profile_sync_factory,
66       Profile* profile,
67       ProfileSyncService* sync_service,
68       NonUIDataTypeControllerMock* mock)
69       : NonUIDataTypeController(profile_sync_factory,
70                                          profile,
71                                          sync_service),
72         blocked_(false),
73         mock_(mock) {}
74
75   virtual syncer::ModelType type() const OVERRIDE {
76     return AUTOFILL_PROFILE;
77   }
78   virtual syncer::ModelSafeGroup model_safe_group() const OVERRIDE {
79     return syncer::GROUP_DB;
80   }
81
82   // Prevent tasks from being posted on the backend thread until
83   // UnblockBackendTasks() is called.
84   void BlockBackendTasks() {
85     blocked_ = true;
86   }
87
88   // Post pending tasks on the backend thread and start allowing tasks
89   // to be posted on the backend thread again.
90   void UnblockBackendTasks() {
91     blocked_ = false;
92     for (std::vector<PendingTask>::const_iterator it = pending_tasks_.begin();
93          it != pending_tasks_.end(); ++it) {
94       PostTaskOnBackendThread(it->from_here, it->task);
95     }
96     pending_tasks_.clear();
97   }
98
99  protected:
100   virtual bool PostTaskOnBackendThread(
101       const tracked_objects::Location& from_here,
102       const base::Closure& task) OVERRIDE {
103     if (blocked_) {
104       pending_tasks_.push_back(PendingTask(from_here, task));
105       return true;
106     } else {
107       return BrowserThread::PostTask(BrowserThread::DB, from_here, task);
108     }
109   }
110
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();
115   }
116   virtual void StopModels() OVERRIDE {
117     mock_->StopModels();
118   }
119   virtual void RecordUnrecoverableError(
120       const tracked_objects::Location& from_here,
121       const std::string& message) OVERRIDE {
122     mock_->RecordUnrecoverableError(from_here, message);
123   }
124   virtual void RecordAssociationTime(base::TimeDelta time) OVERRIDE {
125     mock_->RecordAssociationTime(time);
126   }
127   virtual void RecordStartFailure(DataTypeController::StartResult result)
128       OVERRIDE {
129     mock_->RecordStartFailure(result);
130   }
131
132  private:
133   virtual ~NonUIDataTypeControllerFake() {}
134
135   DISALLOW_COPY_AND_ASSIGN(NonUIDataTypeControllerFake);
136
137   struct PendingTask {
138     PendingTask(const tracked_objects::Location& from_here,
139                 const base::Closure& task)
140         : from_here(from_here), task(task) {}
141
142     tracked_objects::Location from_here;
143     base::Closure task;
144   };
145
146   bool blocked_;
147   std::vector<PendingTask> pending_tasks_;
148   NonUIDataTypeControllerMock* mock_;
149 };
150
151 class SyncNonUIDataTypeControllerTest : public testing::Test {
152  public:
153   SyncNonUIDataTypeControllerTest()
154       : ui_thread_(BrowserThread::UI, &message_loop_),
155         db_thread_(BrowserThread::DB) {}
156
157   virtual void SetUp() OVERRIDE {
158     EXPECT_CALL(service_, GetUserShare()).WillRepeatedly(
159         Return((syncer::UserShare*)NULL));
160     db_thread_.Start();
161     profile_sync_factory_.reset(
162         new StrictMock<ProfileSyncComponentsFactoryMock>());
163     change_processor_ = new SharedChangeProcessorMock();
164
165     // All of these are refcounted, so don't need to be released.
166     dtc_mock_ = new StrictMock<NonUIDataTypeControllerMock>();
167     non_ui_dtc_ =
168         new NonUIDataTypeControllerFake(profile_sync_factory_.get(),
169                                         &profile_,
170                                         &service_,
171                                         dtc_mock_.get());
172   }
173
174   virtual void TearDown() OVERRIDE {
175     db_thread_.Stop();
176   }
177
178   void WaitForDTC() {
179     WaitableEvent done(true, false);
180     BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
181        base::Bind(&SyncNonUIDataTypeControllerTest::SignalDone,
182                   &done));
183     done.TimedWait(TestTimeouts::action_timeout());
184     if (!done.IsSignaled()) {
185       ADD_FAILURE() << "Timed out waiting for DB thread to finish.";
186     }
187     base::MessageLoop::current()->RunUntilIdle();
188   }
189
190  protected:
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()));
197   }
198
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(_));
211   }
212
213   void SetActivateExpectations(DataTypeController::StartResult result) {
214     EXPECT_CALL(start_callback_, Run(result,_,_));
215   }
216
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(_));
221   }
222
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, _, _));
229   }
230
231   void Start() {
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_)));
238   }
239
240   static void SignalDone(WaitableEvent* done) {
241     done->Signal();
242   }
243
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_;
258 };
259
260 TEST_F(SyncNonUIDataTypeControllerTest, StartOk) {
261   SetStartExpectations();
262   SetAssociateExpectations();
263   SetActivateExpectations(DataTypeController::OK);
264   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
265   Start();
266   WaitForDTC();
267   EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state());
268 }
269
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());
283   Start();
284   WaitForDTC();
285   EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state());
286 }
287
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_)));
301   WaitForDTC();
302   EXPECT_EQ(DataTypeController::MODEL_STARTING, non_ui_dtc_->state());
303   non_ui_dtc_->Stop();
304   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
305 }
306
307 // Start the DTC and have MergeDataAndStartSyncing() return an error.
308 // The DTC should become disabled, and the DTC should still stop
309 // cleanly.
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,
327                         "Sync Error",
328                         non_ui_dtc_->type()));
329   Start();
330   WaitForDTC();
331   EXPECT_EQ(DataTypeController::DISABLED, non_ui_dtc_->state());
332   non_ui_dtc_->Stop();
333   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
334 }
335
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());
348   Start();
349   WaitForDTC();
350   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
351 }
352
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());
363   Start();
364   WaitForDTC();
365   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
366 }
367
368 // Trigger a Stop() call when we check if the model associator has user created
369 // nodes.
370 TEST_F(SyncNonUIDataTypeControllerTest, AbortDuringAssociation) {
371   WaitableEvent wait_for_db_thread_pause(false, false);
372   WaitableEvent pause_db_thread(false, false);
373
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),
384                       Return(true)));
385   EXPECT_CALL(*change_processor_.get(), GetAllSyncDataReturnError(_,_))
386       .WillOnce(
387           Return(syncer::SyncError(FROM_HERE,
388                                    syncer::SyncError::DATATYPE_ERROR,
389                                    "Disconnected.",
390                                    AUTOFILL_PROFILE)));
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());
395   Start();
396   wait_for_db_thread_pause.Wait();
397   non_ui_dtc_->Stop();
398   WaitForDTC();
399   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
400 }
401
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();
407
408   SetStartExpectations();
409   // We don't expect StopSyncing to be called because local_service_ will never
410   // have been set.
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());
418   Start();
419   non_ui_dtc_->Stop();
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());
425
426   EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _))
427       .WillOnce(Return(base::WeakPtr<syncer::SyncableService>()));
428   non_ui_dtc_->UnblockBackendTasks();
429   WaitForDTC();
430 }
431
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());
438   Start();
439   WaitForDTC();
440   EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state());
441   non_ui_dtc_->Stop();
442   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
443 }
444
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());
455   Start();
456   WaitForDTC();
457   EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state());
458
459   non_ui_dtc_->BlockBackendTasks();
460   non_ui_dtc_->Stop();
461   Mock::VerifyAndClearExpectations(&profile_sync_factory_);
462   SetStartExpectations();
463   SetAssociateExpectations();
464   SetActivateExpectations(DataTypeController::OK);
465   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
466   Start();
467   non_ui_dtc_->UnblockBackendTasks();
468
469   WaitForDTC();
470   EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state());
471 }
472
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());
483   Start();
484   WaitForDTC();
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,
490       non_ui_dtc_.get(),
491       FROM_HERE,
492       std::string("Test")));
493   WaitForDTC();
494   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
495 }
496
497 }  // namespace
498
499 }  // namespace browser_sync