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 "testing/gtest/include/gtest/gtest.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/non_frontend_data_type_controller.h"
17#include "chrome/browser/sync/glue/non_frontend_data_type_controller_mock.h"
18#include "chrome/browser/sync/profile_sync_components_factory_mock.h"
19#include "chrome/browser/sync/profile_sync_service_mock.h"
20#include "chrome/test/base/profile_mock.h"
21#include "components/sync_driver/change_processor_mock.h"
22#include "components/sync_driver/data_type_controller_mock.h"
23#include "components/sync_driver/model_associator_mock.h"
24#include "content/public/test/test_browser_thread.h"
25#include "sync/internal_api/public/engine/model_safe_worker.h"
26
27using base::WaitableEvent;
28using syncer::GROUP_DB;
29using browser_sync::NonFrontendDataTypeController;
30using browser_sync::NonFrontendDataTypeControllerMock;
31using sync_driver::ChangeProcessorMock;
32using sync_driver::DataTypeController;
33using sync_driver::ModelAssociatorMock;
34using sync_driver::ModelLoadCallbackMock;
35using sync_driver::StartCallbackMock;
36using content::BrowserThread;
37using testing::_;
38using testing::DoAll;
39using testing::InvokeWithoutArgs;
40using testing::Return;
41using testing::SetArgumentPointee;
42using testing::StrictMock;
43
44ACTION_P(WaitOnEvent, event) {
45  event->Wait();
46}
47
48ACTION_P(SignalEvent, event) {
49  event->Signal();
50}
51
52class NonFrontendDataTypeControllerFake : public NonFrontendDataTypeController {
53 public:
54  NonFrontendDataTypeControllerFake(
55      ProfileSyncComponentsFactory* profile_sync_factory,
56      Profile* profile,
57      ProfileSyncService* sync_service,
58      NonFrontendDataTypeControllerMock* mock)
59      : NonFrontendDataTypeController(base::MessageLoopProxy::current(),
60                                      base::Closure(),
61                                      profile_sync_factory,
62                                      profile,
63                                      sync_service),
64        mock_(mock) {}
65
66  virtual syncer::ModelType type() const OVERRIDE { return syncer::BOOKMARKS; }
67  virtual syncer::ModelSafeGroup model_safe_group() const OVERRIDE {
68    return syncer::GROUP_DB;
69  }
70
71 private:
72  virtual ~NonFrontendDataTypeControllerFake() {}
73
74  virtual ProfileSyncComponentsFactory::SyncComponents
75  CreateSyncComponents() OVERRIDE {
76    return profile_sync_factory()->
77            CreateBookmarkSyncComponents(profile_sync_service(), this);
78  }
79
80  virtual bool PostTaskOnBackendThread(
81      const tracked_objects::Location& from_here,
82      const base::Closure& task) OVERRIDE {
83    return BrowserThread::PostTask(BrowserThread::DB, from_here, task);
84  }
85
86  // We mock the following methods because their default implementations do
87  // nothing, but we still want to make sure they're called appropriately.
88  virtual bool StartModels() OVERRIDE {
89    return mock_->StartModels();
90  }
91  virtual void RecordUnrecoverableError(
92      const tracked_objects::Location& from_here,
93      const std::string& message) OVERRIDE {
94    mock_->RecordUnrecoverableError(from_here, message);
95  }
96  virtual void RecordAssociationTime(base::TimeDelta time) OVERRIDE {
97    mock_->RecordAssociationTime(time);
98  }
99  virtual void RecordStartFailure(
100      DataTypeController::ConfigureResult result) OVERRIDE {
101    mock_->RecordStartFailure(result);
102  }
103  virtual void DisconnectProcessor(
104      sync_driver::ChangeProcessor* processor) OVERRIDE{
105    mock_->DisconnectProcessor(processor);
106  }
107
108 private:
109  NonFrontendDataTypeControllerMock* mock_;
110};
111
112class SyncNonFrontendDataTypeControllerTest : public testing::Test {
113 public:
114  SyncNonFrontendDataTypeControllerTest()
115      : ui_thread_(BrowserThread::UI, &message_loop_),
116        db_thread_(BrowserThread::DB),
117        service_(&profile_),
118        model_associator_(NULL),
119        change_processor_(NULL) {}
120
121  virtual void SetUp() {
122    db_thread_.Start();
123    profile_sync_factory_.reset(new ProfileSyncComponentsFactoryMock());
124
125    // All of these are refcounted, so don't need to be released.
126    dtc_mock_ = new StrictMock<NonFrontendDataTypeControllerMock>();
127    non_frontend_dtc_ =
128        new NonFrontendDataTypeControllerFake(profile_sync_factory_.get(),
129                                              &profile_,
130                                              &service_,
131                                              dtc_mock_.get());
132  }
133
134  virtual void TearDown() {
135    if (non_frontend_dtc_->state() !=
136        NonFrontendDataTypeController::NOT_RUNNING) {
137      non_frontend_dtc_->Stop();
138    }
139    db_thread_.Stop();
140  }
141
142 protected:
143  void SetStartExpectations() {
144    EXPECT_CALL(*dtc_mock_.get(), StartModels()).WillOnce(Return(true));
145    EXPECT_CALL(model_load_callback_, Run(_, _));
146    model_associator_ = new ModelAssociatorMock();
147    change_processor_ = new ChangeProcessorMock();
148    EXPECT_CALL(*profile_sync_factory_, CreateBookmarkSyncComponents(_, _)).
149        WillOnce(Return(ProfileSyncComponentsFactory::SyncComponents(
150            model_associator_, change_processor_)));
151  }
152
153  void SetAssociateExpectations() {
154    EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
155        WillOnce(Return(true));
156    EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
157        WillOnce(DoAll(SetArgumentPointee<0>(true), Return(true)));
158    EXPECT_CALL(*model_associator_, AssociateModels(_, _)).
159        WillOnce(Return(syncer::SyncError()));
160    EXPECT_CALL(*dtc_mock_.get(), RecordAssociationTime(_));
161  }
162
163  void SetActivateExpectations(DataTypeController::ConfigureResult result) {
164    EXPECT_CALL(start_callback_, Run(result, _, _));
165  }
166
167  void SetStopExpectations() {
168    EXPECT_CALL(*dtc_mock_.get(), DisconnectProcessor(_));
169    EXPECT_CALL(service_, DeactivateDataType(_));
170    EXPECT_CALL(*model_associator_, DisassociateModels()).
171                WillOnce(Return(syncer::SyncError()));
172  }
173
174  void SetStartFailExpectations(DataTypeController::ConfigureResult result) {
175    if (DataTypeController::IsUnrecoverableResult(result))
176      EXPECT_CALL(*dtc_mock_.get(), RecordUnrecoverableError(_, _));
177    if (model_associator_) {
178      EXPECT_CALL(*model_associator_, DisassociateModels()).
179                  WillOnce(Return(syncer::SyncError()));
180    }
181    EXPECT_CALL(*dtc_mock_.get(), RecordStartFailure(result));
182    EXPECT_CALL(start_callback_, Run(result, _, _));
183  }
184
185  static void SignalDone(WaitableEvent* done) {
186    done->Signal();
187  }
188
189  void WaitForDTC() {
190    WaitableEvent done(true, false);
191    BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
192        base::Bind(&SyncNonFrontendDataTypeControllerTest::SignalDone, &done));
193    done.TimedWait(TestTimeouts::action_timeout());
194    if (!done.IsSignaled()) {
195      ADD_FAILURE() << "Timed out waiting for DB thread to finish.";
196    }
197    base::MessageLoop::current()->RunUntilIdle();
198  }
199
200  void Start() {
201    non_frontend_dtc_->LoadModels(
202        base::Bind(&ModelLoadCallbackMock::Run,
203                   base::Unretained(&model_load_callback_)));
204    non_frontend_dtc_->StartAssociating(
205        base::Bind(&StartCallbackMock::Run,
206                   base::Unretained(&start_callback_)));
207  }
208
209  base::MessageLoopForUI message_loop_;
210  content::TestBrowserThread ui_thread_;
211  content::TestBrowserThread db_thread_;
212  scoped_refptr<NonFrontendDataTypeControllerFake> non_frontend_dtc_;
213  scoped_ptr<ProfileSyncComponentsFactoryMock> profile_sync_factory_;
214  scoped_refptr<NonFrontendDataTypeControllerMock> dtc_mock_;
215  ProfileMock profile_;
216  ProfileSyncServiceMock service_;
217  ModelAssociatorMock* model_associator_;
218  ChangeProcessorMock* change_processor_;
219  StartCallbackMock start_callback_;
220  ModelLoadCallbackMock model_load_callback_;
221};
222
223TEST_F(SyncNonFrontendDataTypeControllerTest, StartOk) {
224  SetStartExpectations();
225  SetAssociateExpectations();
226  SetActivateExpectations(DataTypeController::OK);
227  SetStopExpectations();
228  EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
229  Start();
230  WaitForDTC();
231  EXPECT_EQ(DataTypeController::RUNNING, non_frontend_dtc_->state());
232}
233
234TEST_F(SyncNonFrontendDataTypeControllerTest, StartFirstRun) {
235  SetStartExpectations();
236  EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
237      WillOnce(Return(true));
238  EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
239      WillOnce(DoAll(SetArgumentPointee<0>(false), Return(true)));
240  EXPECT_CALL(*model_associator_, AssociateModels(_, _)).
241      WillOnce(Return(syncer::SyncError()));
242  EXPECT_CALL(*dtc_mock_.get(), RecordAssociationTime(_));
243  SetActivateExpectations(DataTypeController::OK_FIRST_RUN);
244  SetStopExpectations();
245  EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
246  Start();
247  WaitForDTC();
248  EXPECT_EQ(DataTypeController::RUNNING, non_frontend_dtc_->state());
249}
250
251TEST_F(SyncNonFrontendDataTypeControllerTest, StartAssociationFailed) {
252  SetStartExpectations();
253  EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
254      WillOnce(Return(true));
255  EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
256      WillOnce(DoAll(SetArgumentPointee<0>(true), Return(true)));
257  EXPECT_CALL(*model_associator_, AssociateModels(_, _)).
258      WillOnce(
259          Return(syncer::SyncError(FROM_HERE,
260                                   syncer::SyncError::DATATYPE_ERROR,
261                                   "Error",
262                                   syncer::BOOKMARKS)));
263  EXPECT_CALL(*dtc_mock_.get(), RecordAssociationTime(_));
264  SetStartFailExpectations(DataTypeController::ASSOCIATION_FAILED);
265  // Set up association to fail with an association failed error.
266  EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
267  Start();
268  WaitForDTC();
269  EXPECT_EQ(DataTypeController::DISABLED, non_frontend_dtc_->state());
270}
271
272TEST_F(SyncNonFrontendDataTypeControllerTest,
273       StartAssociationTriggersUnrecoverableError) {
274  SetStartExpectations();
275  SetStartFailExpectations(DataTypeController::UNRECOVERABLE_ERROR);
276  // Set up association to fail with an unrecoverable error.
277  EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
278      WillRepeatedly(Return(true));
279  EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
280      WillRepeatedly(DoAll(SetArgumentPointee<0>(false), Return(false)));
281  EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
282  Start();
283  WaitForDTC();
284  EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
285}
286
287TEST_F(SyncNonFrontendDataTypeControllerTest, StartAssociationCryptoNotReady) {
288  SetStartExpectations();
289  SetStartFailExpectations(DataTypeController::NEEDS_CRYPTO);
290  // Set up association to fail with a NEEDS_CRYPTO error.
291  EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
292      WillRepeatedly(Return(false));
293  EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
294  Start();
295  WaitForDTC();
296  EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
297}
298
299// Trigger a Stop() call when we check if the model associator has user created
300// nodes.
301TEST_F(SyncNonFrontendDataTypeControllerTest, AbortDuringAssociationInactive) {
302  WaitableEvent wait_for_db_thread_pause(false, false);
303  WaitableEvent pause_db_thread(false, false);
304
305  SetStartExpectations();
306  EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
307      WillOnce(Return(true));
308  EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
309      WillOnce(DoAll(
310          SignalEvent(&wait_for_db_thread_pause),
311          WaitOnEvent(&pause_db_thread),
312          SetArgumentPointee<0>(true),
313          Return(true)));
314  EXPECT_CALL(*model_associator_, AbortAssociation()).WillOnce(
315      SignalEvent(&pause_db_thread));
316  EXPECT_CALL(*model_associator_, AssociateModels(_, _)).
317              WillOnce(Return(syncer::SyncError()));
318  SetStopExpectations();
319  EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
320  Start();
321  wait_for_db_thread_pause.Wait();
322  non_frontend_dtc_->Stop();
323  WaitForDTC();
324  EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
325}
326
327// Same as above but abort during the Activate call.
328TEST_F(SyncNonFrontendDataTypeControllerTest, AbortDuringAssociationActivated) {
329  WaitableEvent wait_for_association_starts(false, false);
330  WaitableEvent wait_for_dtc_stop(false, false);
331
332  SetStartExpectations();
333  EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
334      WillOnce(Return(true));
335  EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
336      WillOnce(DoAll(
337          SetArgumentPointee<0>(true),
338          Return(true)));
339  EXPECT_CALL(*model_associator_, AbortAssociation());
340  EXPECT_CALL(*model_associator_, AssociateModels(_, _)).
341      WillOnce(DoAll(
342          SignalEvent(&wait_for_association_starts),
343          WaitOnEvent(&wait_for_dtc_stop),
344          Return(syncer::SyncError())));
345  SetStopExpectations();
346  EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
347  Start();
348  wait_for_association_starts.Wait();
349  non_frontend_dtc_->Stop();
350  wait_for_dtc_stop.Signal();
351  WaitForDTC();
352  EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
353}
354
355TEST_F(SyncNonFrontendDataTypeControllerTest, Stop) {
356  SetStartExpectations();
357  SetAssociateExpectations();
358  SetActivateExpectations(DataTypeController::OK);
359  SetStopExpectations();
360  EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
361  Start();
362  WaitForDTC();
363  EXPECT_EQ(DataTypeController::RUNNING, non_frontend_dtc_->state());
364  non_frontend_dtc_->Stop();
365  EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
366}
367
368// Disabled due to http://crbug.com/388367
369TEST_F(SyncNonFrontendDataTypeControllerTest,
370       DISABLED_OnSingleDataTypeUnrecoverableError) {
371  SetStartExpectations();
372  SetAssociateExpectations();
373  SetActivateExpectations(DataTypeController::OK);
374  EXPECT_CALL(*dtc_mock_.get(), RecordUnrecoverableError(_, "Test"));
375  EXPECT_CALL(service_, DisableDatatype(_))
376      .WillOnce(InvokeWithoutArgs(non_frontend_dtc_.get(),
377                                  &NonFrontendDataTypeController::Stop));
378  SetStopExpectations();
379  EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
380  Start();
381  WaitForDTC();
382  EXPECT_EQ(DataTypeController::RUNNING, non_frontend_dtc_->state());
383  // This should cause non_frontend_dtc_->Stop() to be called.
384  syncer::SyncError error(FROM_HERE,
385                          syncer::SyncError::DATATYPE_ERROR,
386                          "error",
387                          non_frontend_dtc_->type());
388  BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, base::Bind(
389      &NonFrontendDataTypeControllerFake::OnSingleDataTypeUnrecoverableError,
390      non_frontend_dtc_.get(),
391      error));
392  WaitForDTC();
393  EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
394}
395