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
26namespace sync_driver {
27
28namespace {
29
30using base::WaitableEvent;
31using syncer::AUTOFILL_PROFILE;
32using testing::_;
33using testing::AtLeast;
34using testing::DoAll;
35using testing::InvokeWithoutArgs;
36using testing::Mock;
37using testing::Return;
38using testing::SetArgumentPointee;
39using testing::StrictMock;
40
41ACTION_P(WaitOnEvent, event) {
42  event->Wait();
43}
44
45ACTION_P(SignalEvent, event) {
46  event->Signal();
47}
48
49ACTION_P(SaveChangeProcessor, scoped_change_processor) {
50  scoped_change_processor->reset(arg2);
51}
52
53ACTION_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
59class 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
92class 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
186class 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
280TEST_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
290TEST_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.
310TEST_F(SyncNonUIDataTypeControllerTest, AbortDuringStartModels) {
311  EXPECT_CALL(*dtc_mock_.get(), StartModels()).WillOnce(Return(false));
312  EXPECT_CALL(*dtc_mock_.get(), StopModels());
313  EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
314  non_ui_dtc_->LoadModels(
315      base::Bind(&ModelLoadCallbackMock::Run,
316                 base::Unretained(&model_load_callback_)));
317  WaitForDTC();
318  EXPECT_EQ(DataTypeController::MODEL_STARTING, non_ui_dtc_->state());
319  non_ui_dtc_->Stop();
320  EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
321}
322
323// Start the DTC and have MergeDataAndStartSyncing() return an error.
324// The DTC should become disabled, and the DTC should still stop
325// cleanly.
326TEST_F(SyncNonUIDataTypeControllerTest, StartAssociationFailed) {
327  SetStartExpectations();
328  EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _, _))
329      .WillOnce(GetWeakPtrToSyncableService(&syncable_service_));
330  EXPECT_CALL(*change_processor_.get(), CryptoReadyIfNecessary())
331      .WillOnce(Return(true));
332  EXPECT_CALL(*change_processor_.get(), SyncModelHasUserCreatedNodes(_))
333      .WillOnce(DoAll(SetArgumentPointee<0>(true), Return(true)));
334  EXPECT_CALL(*change_processor_.get(), GetAllSyncDataReturnError(_,_))
335      .WillOnce(Return(syncer::SyncError()));
336  EXPECT_CALL(*dtc_mock_.get(), RecordAssociationTime(_));
337  SetStartFailExpectations(DataTypeController::ASSOCIATION_FAILED);
338  // Set up association to fail with an association failed error.
339  EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
340  syncable_service_.set_merge_data_and_start_syncing_error(
341      syncer::SyncError(FROM_HERE,
342                        syncer::SyncError::DATATYPE_ERROR,
343                        "Sync Error",
344                        non_ui_dtc_->type()));
345  Start();
346  WaitForDTC();
347  EXPECT_EQ(DataTypeController::DISABLED, non_ui_dtc_->state());
348  non_ui_dtc_->Stop();
349  EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
350}
351
352TEST_F(SyncNonUIDataTypeControllerTest,
353       StartAssociationTriggersUnrecoverableError) {
354  SetStartExpectations();
355  SetStartFailExpectations(DataTypeController::UNRECOVERABLE_ERROR);
356  // Set up association to fail with an unrecoverable error.
357  EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _, _))
358      .WillOnce(GetWeakPtrToSyncableService(&syncable_service_));
359  EXPECT_CALL(*change_processor_.get(), CryptoReadyIfNecessary())
360      .WillRepeatedly(Return(true));
361  EXPECT_CALL(*change_processor_.get(), SyncModelHasUserCreatedNodes(_))
362      .WillRepeatedly(DoAll(SetArgumentPointee<0>(false), Return(false)));
363  EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
364  Start();
365  WaitForDTC();
366  EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
367}
368
369TEST_F(SyncNonUIDataTypeControllerTest,
370       StartAssociationCryptoNotReady) {
371  SetStartExpectations();
372  SetStartFailExpectations(DataTypeController::NEEDS_CRYPTO);
373  // Set up association to fail with a NEEDS_CRYPTO error.
374  EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _, _))
375      .WillOnce(GetWeakPtrToSyncableService(&syncable_service_));
376  EXPECT_CALL(*change_processor_.get(), CryptoReadyIfNecessary())
377      .WillRepeatedly(Return(false));
378  EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
379  Start();
380  WaitForDTC();
381  EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
382}
383
384// Trigger a Stop() call when we check if the model associator has user created
385// nodes.
386TEST_F(SyncNonUIDataTypeControllerTest, AbortDuringAssociation) {
387  WaitableEvent wait_for_db_thread_pause(false, false);
388  WaitableEvent pause_db_thread(false, false);
389
390  SetStartExpectations();
391  EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _, _))
392      .WillOnce(GetWeakPtrToSyncableService(&syncable_service_));
393  EXPECT_CALL(*change_processor_.get(), CryptoReadyIfNecessary())
394      .WillOnce(Return(true));
395  EXPECT_CALL(*change_processor_.get(), SyncModelHasUserCreatedNodes(_))
396      .WillOnce(DoAll(SignalEvent(&wait_for_db_thread_pause),
397                      WaitOnEvent(&pause_db_thread),
398                      SetArgumentPointee<0>(true),
399                      Return(true)));
400  EXPECT_CALL(*change_processor_.get(), GetAllSyncDataReturnError(_,_))
401      .WillOnce(
402          Return(syncer::SyncError(FROM_HERE,
403                                   syncer::SyncError::DATATYPE_ERROR,
404                                   "Disconnected.",
405                                   AUTOFILL_PROFILE)));
406  EXPECT_CALL(*change_processor_.get(), Disconnect())
407      .WillOnce(DoAll(SignalEvent(&pause_db_thread), Return(true)));
408  EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
409  Start();
410  wait_for_db_thread_pause.Wait();
411  non_ui_dtc_->Stop();
412  WaitForDTC();
413  EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
414}
415
416// Start the DTC while the backend tasks are blocked. Then stop the DTC before
417// the backend tasks get a chance to run.
418TEST_F(SyncNonUIDataTypeControllerTest, StartAfterSyncShutdown) {
419  non_ui_dtc_->BlockBackendTasks();
420
421  SetStartExpectations();
422  // We don't expect StopSyncing to be called because local_service_ will never
423  // have been set.
424  EXPECT_CALL(*change_processor_.get(), Disconnect()).WillOnce(Return(true));
425  EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
426  Start();
427  non_ui_dtc_->Stop();
428  EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
429  Mock::VerifyAndClearExpectations(change_processor_.get());
430  Mock::VerifyAndClearExpectations(dtc_mock_.get());
431
432  EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _, _))
433      .WillOnce(Return(base::WeakPtr<syncer::SyncableService>()));
434  non_ui_dtc_->UnblockBackendTasks();
435  WaitForDTC();
436}
437
438TEST_F(SyncNonUIDataTypeControllerTest, Stop) {
439  SetStartExpectations();
440  SetAssociateExpectations();
441  SetActivateExpectations(DataTypeController::OK);
442  SetStopExpectations();
443  EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
444  Start();
445  WaitForDTC();
446  EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state());
447  non_ui_dtc_->Stop();
448  EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
449}
450
451// Start the DTC then block its backend tasks.  While its backend
452// tasks are blocked, stop and start it again, then unblock its
453// backend tasks.  The (delayed) running of the backend tasks from the
454// stop after the restart shouldn't cause any problems.
455TEST_F(SyncNonUIDataTypeControllerTest, StopStart) {
456  SetStartExpectations();
457  SetAssociateExpectations();
458  SetActivateExpectations(DataTypeController::OK);
459  SetStopExpectations();
460  EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
461  Start();
462  WaitForDTC();
463  EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state());
464
465  non_ui_dtc_->BlockBackendTasks();
466  non_ui_dtc_->Stop();
467  SetStartExpectations();
468  SetAssociateExpectations();
469  SetActivateExpectations(DataTypeController::OK);
470  EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
471  Start();
472  non_ui_dtc_->UnblockBackendTasks();
473
474  WaitForDTC();
475  EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state());
476}
477
478TEST_F(SyncNonUIDataTypeControllerTest, OnSingleDataTypeUnrecoverableError) {
479  SetStartExpectations();
480  SetAssociateExpectations();
481  SetActivateExpectations(DataTypeController::OK);
482  EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
483  Start();
484  WaitForDTC();
485  EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state());
486
487  testing::Mock::VerifyAndClearExpectations(&start_callback_);
488  EXPECT_CALL(model_load_callback_, Run(_, _));
489  syncer::SyncError error(FROM_HERE,
490                          syncer::SyncError::DATATYPE_ERROR,
491                          "error",
492                          non_ui_dtc_->type());
493  backend_thread_.message_loop_proxy()->PostTask(FROM_HERE, base::Bind(
494      &NonUIDataTypeControllerFake::
495          OnSingleDataTypeUnrecoverableError,
496      non_ui_dtc_.get(),
497      error));
498  WaitForDTC();
499}
500
501}  // namespace
502
503}  // namespace sync_driver
504