5eef2e3f8ca2768e99e9d6d437c6d11a258a56e2
[platform/framework/web/crosswalk.git] / src / components / sync_driver / non_ui_data_type_controller_unittest.cc
1 // Copyright 2014 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 "components/sync_driver/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/threading/thread.h"
16 #include "base/tracked_objects.h"
17 #include "components/sync_driver/data_type_controller_mock.h"
18 #include "components/sync_driver/generic_change_processor_factory.h"
19 #include "components/sync_driver/non_ui_data_type_controller_mock.h"
20 #include "sync/api/fake_syncable_service.h"
21 #include "sync/api/sync_change.h"
22 #include "sync/internal_api/public/engine/model_safe_worker.h"
23 #include "testing/gmock/include/gmock/gmock.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25
26 namespace sync_driver {
27
28 namespace {
29
30 using base::WaitableEvent;
31 using syncer::AUTOFILL_PROFILE;
32 using testing::_;
33 using testing::AtLeast;
34 using testing::DoAll;
35 using testing::InvokeWithoutArgs;
36 using testing::Mock;
37 using testing::Return;
38 using testing::SetArgumentPointee;
39 using testing::StrictMock;
40
41 ACTION_P(WaitOnEvent, event) {
42   event->Wait();
43 }
44
45 ACTION_P(SignalEvent, event) {
46   event->Signal();
47 }
48
49 ACTION_P(SaveChangeProcessor, scoped_change_processor) {
50   scoped_change_processor->reset(arg2);
51 }
52
53 ACTION_P(GetWeakPtrToSyncableService, syncable_service) {
54   // Have to do this within an Action to ensure it's not evaluated on the wrong
55   // thread.
56   return syncable_service->AsWeakPtr();
57 }
58
59 class SharedChangeProcessorMock : public SharedChangeProcessor {
60  public:
61   SharedChangeProcessorMock() {}
62
63   MOCK_METHOD6(Connect, base::WeakPtr<syncer::SyncableService>(
64       SyncApiComponentFactory*,
65       GenericChangeProcessorFactory*,
66       syncer::UserShare*,
67       DataTypeErrorHandler*,
68       syncer::ModelType,
69       const base::WeakPtr<syncer::SyncMergeResult>&));
70   MOCK_METHOD0(Disconnect, bool());
71   MOCK_METHOD2(ProcessSyncChanges,
72                syncer::SyncError(const tracked_objects::Location&,
73                          const syncer::SyncChangeList&));
74   MOCK_CONST_METHOD2(GetAllSyncDataReturnError,
75                      syncer::SyncError(syncer::ModelType,
76                                        syncer::SyncDataList*));
77   MOCK_METHOD0(GetSyncCount, int());
78   MOCK_METHOD1(SyncModelHasUserCreatedNodes,
79                bool(bool*));
80   MOCK_METHOD0(CryptoReadyIfNecessary, bool());
81   MOCK_CONST_METHOD1(GetDataTypeContext, bool(std::string*));
82
83  protected:
84   virtual ~SharedChangeProcessorMock() {}
85   MOCK_METHOD2(OnUnrecoverableError, void(const tracked_objects::Location&,
86                                           const std::string&));
87
88  private:
89   DISALLOW_COPY_AND_ASSIGN(SharedChangeProcessorMock);
90 };
91
92 class NonUIDataTypeControllerFake
93     : public NonUIDataTypeController {
94  public:
95   NonUIDataTypeControllerFake(
96       SyncApiComponentFactory* sync_factory,
97       NonUIDataTypeControllerMock* mock,
98       SharedChangeProcessor* change_processor,
99       scoped_refptr<base::MessageLoopProxy> backend_loop)
100       : NonUIDataTypeController(
101           base::MessageLoopProxy::current(),
102           base::Closure(),
103           sync_factory),
104         blocked_(false),
105         mock_(mock),
106         change_processor_(change_processor),
107         backend_loop_(backend_loop) {}
108
109   virtual syncer::ModelType type() const OVERRIDE {
110     return AUTOFILL_PROFILE;
111   }
112   virtual syncer::ModelSafeGroup model_safe_group() const OVERRIDE {
113     return syncer::GROUP_DB;
114   }
115
116   // Prevent tasks from being posted on the backend thread until
117   // UnblockBackendTasks() is called.
118   void BlockBackendTasks() {
119     blocked_ = true;
120   }
121
122   // Post pending tasks on the backend thread and start allowing tasks
123   // to be posted on the backend thread again.
124   void UnblockBackendTasks() {
125     blocked_ = false;
126     for (std::vector<PendingTask>::const_iterator it = pending_tasks_.begin();
127          it != pending_tasks_.end(); ++it) {
128       PostTaskOnBackendThread(it->from_here, it->task);
129     }
130     pending_tasks_.clear();
131   }
132
133   virtual SharedChangeProcessor* CreateSharedChangeProcessor() OVERRIDE {
134     return change_processor_.get();
135   }
136
137  protected:
138   virtual bool PostTaskOnBackendThread(
139       const tracked_objects::Location& from_here,
140       const base::Closure& task) OVERRIDE {
141     if (blocked_) {
142       pending_tasks_.push_back(PendingTask(from_here, task));
143       return true;
144     } else {
145       return backend_loop_->PostTask(from_here, task);
146     }
147   }
148
149   // We mock the following methods because their default implementations do
150   // nothing, but we still want to make sure they're called appropriately.
151   virtual bool StartModels() OVERRIDE {
152     return mock_->StartModels();
153   }
154   virtual void StopModels() OVERRIDE {
155     mock_->StopModels();
156   }
157   virtual void RecordAssociationTime(base::TimeDelta time) OVERRIDE {
158     mock_->RecordAssociationTime(time);
159   }
160   virtual void RecordStartFailure(DataTypeController::ConfigureResult result)
161       OVERRIDE {
162     mock_->RecordStartFailure(result);
163   }
164
165  private:
166   virtual ~NonUIDataTypeControllerFake() {}
167
168   DISALLOW_COPY_AND_ASSIGN(NonUIDataTypeControllerFake);
169
170   struct PendingTask {
171     PendingTask(const tracked_objects::Location& from_here,
172                 const base::Closure& task)
173         : from_here(from_here), task(task) {}
174
175     tracked_objects::Location from_here;
176     base::Closure task;
177   };
178
179   bool blocked_;
180   std::vector<PendingTask> pending_tasks_;
181   NonUIDataTypeControllerMock* mock_;
182   scoped_refptr<SharedChangeProcessor> change_processor_;
183   scoped_refptr<base::MessageLoopProxy> backend_loop_;
184 };
185
186 class SyncNonUIDataTypeControllerTest : public testing::Test {
187  public:
188   SyncNonUIDataTypeControllerTest()
189       : backend_thread_("dbthread") {}
190
191   virtual void SetUp() OVERRIDE {
192     backend_thread_.Start();
193     change_processor_ = new SharedChangeProcessorMock();
194     // All of these are refcounted, so don't need to be released.
195     dtc_mock_ = new StrictMock<NonUIDataTypeControllerMock>();
196     non_ui_dtc_ =
197         new NonUIDataTypeControllerFake(NULL,
198                                         dtc_mock_.get(),
199                                         change_processor_.get(),
200                                         backend_thread_.message_loop_proxy());
201   }
202
203   virtual void TearDown() OVERRIDE {
204     backend_thread_.Stop();
205   }
206
207   void WaitForDTC() {
208     WaitableEvent done(true, false);
209     backend_thread_.message_loop_proxy()->PostTask(
210        FROM_HERE,
211        base::Bind(&SyncNonUIDataTypeControllerTest::SignalDone,
212                   &done));
213     done.TimedWait(TestTimeouts::action_timeout());
214     if (!done.IsSignaled()) {
215       ADD_FAILURE() << "Timed out waiting for DB thread to finish.";
216     }
217     base::MessageLoop::current()->RunUntilIdle();
218   }
219
220  protected:
221   void SetStartExpectations() {
222     EXPECT_CALL(*dtc_mock_.get(), StartModels()).WillOnce(Return(true));
223     EXPECT_CALL(model_load_callback_, Run(_, _));
224   }
225
226   void SetAssociateExpectations() {
227     EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _, _))
228         .WillOnce(GetWeakPtrToSyncableService(&syncable_service_));
229     EXPECT_CALL(*change_processor_.get(), CryptoReadyIfNecessary())
230         .WillOnce(Return(true));
231     EXPECT_CALL(*change_processor_.get(), SyncModelHasUserCreatedNodes(_))
232         .WillOnce(DoAll(SetArgumentPointee<0>(true), Return(true)));
233     EXPECT_CALL(*change_processor_.get(), GetAllSyncDataReturnError(_,_))
234         .WillOnce(Return(syncer::SyncError()));
235     EXPECT_CALL(*change_processor_.get(), GetSyncCount()).WillOnce(Return(0));
236     EXPECT_CALL(*dtc_mock_.get(), RecordAssociationTime(_));
237   }
238
239   void SetActivateExpectations(DataTypeController::ConfigureResult result) {
240     EXPECT_CALL(start_callback_, Run(result,_,_));
241   }
242
243   void SetStopExpectations() {
244     EXPECT_CALL(*dtc_mock_.get(), StopModels());
245     EXPECT_CALL(*change_processor_.get(), Disconnect()).WillOnce(Return(true));
246   }
247
248   void SetStartFailExpectations(DataTypeController::ConfigureResult result) {
249     EXPECT_CALL(*dtc_mock_.get(), StopModels()).Times(AtLeast(1));
250     EXPECT_CALL(*dtc_mock_.get(), RecordStartFailure(result));
251     EXPECT_CALL(start_callback_, Run(result, _, _));
252   }
253
254   void Start() {
255     non_ui_dtc_->LoadModels(
256         base::Bind(&ModelLoadCallbackMock::Run,
257                    base::Unretained(&model_load_callback_)));
258     non_ui_dtc_->StartAssociating(
259         base::Bind(&StartCallbackMock::Run,
260                    base::Unretained(&start_callback_)));
261   }
262
263   static void SignalDone(WaitableEvent* done) {
264     done->Signal();
265   }
266
267   base::MessageLoopForUI message_loop_;
268   base::Thread backend_thread_;
269
270   StartCallbackMock start_callback_;
271   ModelLoadCallbackMock model_load_callback_;
272   // Must be destroyed after non_ui_dtc_.
273   syncer::FakeSyncableService syncable_service_;
274   scoped_refptr<NonUIDataTypeControllerFake> non_ui_dtc_;
275   scoped_refptr<NonUIDataTypeControllerMock> dtc_mock_;
276   scoped_refptr<SharedChangeProcessorMock> change_processor_;
277   scoped_ptr<syncer::SyncChangeProcessor> saved_change_processor_;
278 };
279
280 TEST_F(SyncNonUIDataTypeControllerTest, StartOk) {
281   SetStartExpectations();
282   SetAssociateExpectations();
283   SetActivateExpectations(DataTypeController::OK);
284   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
285   Start();
286   WaitForDTC();
287   EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state());
288 }
289
290 TEST_F(SyncNonUIDataTypeControllerTest, StartFirstRun) {
291   SetStartExpectations();
292   EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _, _))
293       .WillOnce(GetWeakPtrToSyncableService(&syncable_service_));
294   EXPECT_CALL(*change_processor_.get(), CryptoReadyIfNecessary())
295       .WillOnce(Return(true));
296   EXPECT_CALL(*change_processor_.get(), SyncModelHasUserCreatedNodes(_))
297       .WillOnce(DoAll(SetArgumentPointee<0>(false), Return(true)));
298   EXPECT_CALL(*change_processor_.get(), GetAllSyncDataReturnError(_,_))
299       .WillOnce(Return(syncer::SyncError()));
300   EXPECT_CALL(*dtc_mock_.get(), RecordAssociationTime(_));
301   SetActivateExpectations(DataTypeController::OK_FIRST_RUN);
302   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
303   Start();
304   WaitForDTC();
305   EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state());
306 }
307
308 // Start the DTC and have StartModels() return false.  Then, stop the
309 // DTC without finishing model startup.  It should stop cleanly.
310 TEST_F(SyncNonUIDataTypeControllerTest, AbortDuringStartModels) {
311   EXPECT_CALL(*dtc_mock_.get(), StartModels()).WillOnce(Return(false));
312   EXPECT_CALL(*dtc_mock_.get(), StopModels());
313   EXPECT_CALL(model_load_callback_, Run(_, _));
314   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
315   non_ui_dtc_->LoadModels(
316       base::Bind(&ModelLoadCallbackMock::Run,
317                  base::Unretained(&model_load_callback_)));
318   WaitForDTC();
319   EXPECT_EQ(DataTypeController::MODEL_STARTING, non_ui_dtc_->state());
320   non_ui_dtc_->Stop();
321   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
322 }
323
324 // Start the DTC and have MergeDataAndStartSyncing() return an error.
325 // The DTC should become disabled, and the DTC should still stop
326 // cleanly.
327 TEST_F(SyncNonUIDataTypeControllerTest, StartAssociationFailed) {
328   SetStartExpectations();
329   EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _, _))
330       .WillOnce(GetWeakPtrToSyncableService(&syncable_service_));
331   EXPECT_CALL(*change_processor_.get(), CryptoReadyIfNecessary())
332       .WillOnce(Return(true));
333   EXPECT_CALL(*change_processor_.get(), SyncModelHasUserCreatedNodes(_))
334       .WillOnce(DoAll(SetArgumentPointee<0>(true), Return(true)));
335   EXPECT_CALL(*change_processor_.get(), GetAllSyncDataReturnError(_,_))
336       .WillOnce(Return(syncer::SyncError()));
337   EXPECT_CALL(*dtc_mock_.get(), RecordAssociationTime(_));
338   SetStartFailExpectations(DataTypeController::ASSOCIATION_FAILED);
339   // Set up association to fail with an association failed error.
340   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
341   syncable_service_.set_merge_data_and_start_syncing_error(
342       syncer::SyncError(FROM_HERE,
343                         syncer::SyncError::DATATYPE_ERROR,
344                         "Sync Error",
345                         non_ui_dtc_->type()));
346   Start();
347   WaitForDTC();
348   EXPECT_EQ(DataTypeController::DISABLED, non_ui_dtc_->state());
349   non_ui_dtc_->Stop();
350   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
351 }
352
353 TEST_F(SyncNonUIDataTypeControllerTest,
354        StartAssociationTriggersUnrecoverableError) {
355   SetStartExpectations();
356   SetStartFailExpectations(DataTypeController::UNRECOVERABLE_ERROR);
357   // Set up association to fail with an unrecoverable error.
358   EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _, _))
359       .WillOnce(GetWeakPtrToSyncableService(&syncable_service_));
360   EXPECT_CALL(*change_processor_.get(), CryptoReadyIfNecessary())
361       .WillRepeatedly(Return(true));
362   EXPECT_CALL(*change_processor_.get(), SyncModelHasUserCreatedNodes(_))
363       .WillRepeatedly(DoAll(SetArgumentPointee<0>(false), Return(false)));
364   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
365   Start();
366   WaitForDTC();
367   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
368 }
369
370 TEST_F(SyncNonUIDataTypeControllerTest,
371        StartAssociationCryptoNotReady) {
372   SetStartExpectations();
373   SetStartFailExpectations(DataTypeController::NEEDS_CRYPTO);
374   // Set up association to fail with a NEEDS_CRYPTO error.
375   EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _, _))
376       .WillOnce(GetWeakPtrToSyncableService(&syncable_service_));
377   EXPECT_CALL(*change_processor_.get(), CryptoReadyIfNecessary())
378       .WillRepeatedly(Return(false));
379   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
380   Start();
381   WaitForDTC();
382   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
383 }
384
385 // Trigger a Stop() call when we check if the model associator has user created
386 // nodes.
387 TEST_F(SyncNonUIDataTypeControllerTest, AbortDuringAssociation) {
388   WaitableEvent wait_for_db_thread_pause(false, false);
389   WaitableEvent pause_db_thread(false, false);
390
391   SetStartExpectations();
392   EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _, _))
393       .WillOnce(GetWeakPtrToSyncableService(&syncable_service_));
394   EXPECT_CALL(*change_processor_.get(), CryptoReadyIfNecessary())
395       .WillOnce(Return(true));
396   EXPECT_CALL(*change_processor_.get(), SyncModelHasUserCreatedNodes(_))
397       .WillOnce(DoAll(SignalEvent(&wait_for_db_thread_pause),
398                       WaitOnEvent(&pause_db_thread),
399                       SetArgumentPointee<0>(true),
400                       Return(true)));
401   EXPECT_CALL(*change_processor_.get(), GetAllSyncDataReturnError(_,_))
402       .WillOnce(
403           Return(syncer::SyncError(FROM_HERE,
404                                    syncer::SyncError::DATATYPE_ERROR,
405                                    "Disconnected.",
406                                    AUTOFILL_PROFILE)));
407   EXPECT_CALL(*change_processor_.get(), Disconnect())
408       .WillOnce(DoAll(SignalEvent(&pause_db_thread), Return(true)));
409   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
410   Start();
411   wait_for_db_thread_pause.Wait();
412   non_ui_dtc_->Stop();
413   WaitForDTC();
414   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
415 }
416
417 // Start the DTC while the backend tasks are blocked. Then stop the DTC before
418 // the backend tasks get a chance to run.
419 TEST_F(SyncNonUIDataTypeControllerTest, StartAfterSyncShutdown) {
420   non_ui_dtc_->BlockBackendTasks();
421
422   SetStartExpectations();
423   // We don't expect StopSyncing to be called because local_service_ will never
424   // have been set.
425   EXPECT_CALL(*change_processor_.get(), Disconnect()).WillOnce(Return(true));
426   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
427   Start();
428   non_ui_dtc_->Stop();
429   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
430   Mock::VerifyAndClearExpectations(change_processor_.get());
431   Mock::VerifyAndClearExpectations(dtc_mock_.get());
432
433   EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _, _))
434       .WillOnce(Return(base::WeakPtr<syncer::SyncableService>()));
435   non_ui_dtc_->UnblockBackendTasks();
436   WaitForDTC();
437 }
438
439 TEST_F(SyncNonUIDataTypeControllerTest, Stop) {
440   SetStartExpectations();
441   SetAssociateExpectations();
442   SetActivateExpectations(DataTypeController::OK);
443   SetStopExpectations();
444   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
445   Start();
446   WaitForDTC();
447   EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state());
448   non_ui_dtc_->Stop();
449   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
450 }
451
452 // Start the DTC then block its backend tasks.  While its backend
453 // tasks are blocked, stop and start it again, then unblock its
454 // backend tasks.  The (delayed) running of the backend tasks from the
455 // stop after the restart shouldn't cause any problems.
456 TEST_F(SyncNonUIDataTypeControllerTest, StopStart) {
457   SetStartExpectations();
458   SetAssociateExpectations();
459   SetActivateExpectations(DataTypeController::OK);
460   SetStopExpectations();
461   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
462   Start();
463   WaitForDTC();
464   EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state());
465
466   non_ui_dtc_->BlockBackendTasks();
467   non_ui_dtc_->Stop();
468   SetStartExpectations();
469   SetAssociateExpectations();
470   SetActivateExpectations(DataTypeController::OK);
471   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
472   Start();
473   non_ui_dtc_->UnblockBackendTasks();
474
475   WaitForDTC();
476   EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state());
477 }
478
479 TEST_F(SyncNonUIDataTypeControllerTest, OnSingleDataTypeUnrecoverableError) {
480   SetStartExpectations();
481   SetAssociateExpectations();
482   SetActivateExpectations(DataTypeController::OK);
483   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
484   Start();
485   WaitForDTC();
486   EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state());
487
488   testing::Mock::VerifyAndClearExpectations(&start_callback_);
489   EXPECT_CALL(model_load_callback_, Run(_, _));
490   syncer::SyncError error(FROM_HERE,
491                           syncer::SyncError::DATATYPE_ERROR,
492                           "error",
493                           non_ui_dtc_->type());
494   backend_thread_.message_loop_proxy()->PostTask(FROM_HERE, base::Bind(
495       &NonUIDataTypeControllerFake::
496           OnSingleDataTypeUnrecoverableError,
497       non_ui_dtc_.get(),
498       error));
499   WaitForDTC();
500 }
501
502 }  // namespace
503
504 }  // namespace sync_driver