data_type_manager_impl2_unittest.cc revision dc0f95d653279beabeb9817299e2902918ba123e
1// Copyright (c) 2011 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/data_type_manager_impl2.h"
6
7#include <set>
8
9#include "base/message_loop.h"
10#include "base/scoped_ptr.h"
11#include "base/stl_util-inl.h"
12#include "base/task.h"
13#include "chrome/browser/sync/glue/data_type_controller.h"
14#include "chrome/browser/sync/glue/data_type_controller_mock.h"
15#include "chrome/browser/sync/glue/sync_backend_host_mock.h"
16#include "chrome/browser/sync/profile_sync_test_util.h"
17#include "chrome/browser/sync/syncable/model_type.h"
18#include "content/browser/browser_thread.h"
19#include "content/common/notification_details.h"
20#include "content/common/notification_observer_mock.h"
21#include "content/common/notification_registrar.h"
22#include "content/common/notification_service.h"
23#include "content/common/notification_type.h"
24#include "testing/gmock/include/gmock/gmock.h"
25#include "testing/gtest/include/gtest/gtest.h"
26
27using browser_sync::DataTypeManager;
28using browser_sync::DataTypeManagerImpl2;
29using browser_sync::DataTypeController;
30using browser_sync::DataTypeControllerMock;
31using browser_sync::SyncBackendHostMock;
32using testing::_;
33using testing::DoAll;
34using testing::DoDefault;
35using testing::InSequence;
36using testing::Property;
37using testing::Pointee;
38using testing::Return;
39using testing::SaveArg;
40
41ACTION_P(InvokeCallback, callback_result) {
42  arg0->Run(callback_result);
43  delete arg0;
44}
45
46class DataTypeManagerImpl2Test : public testing::Test {
47 public:
48  DataTypeManagerImpl2Test()
49      : ui_thread_(BrowserThread::UI, &message_loop_) {}
50
51  virtual ~DataTypeManagerImpl2Test() {
52  }
53
54 protected:
55  virtual void SetUp() {
56    registrar_.Add(&observer_,
57                   NotificationType::SYNC_CONFIGURE_START,
58                   NotificationService::AllSources());
59    registrar_.Add(&observer_,
60                   NotificationType::SYNC_CONFIGURE_DONE,
61                   NotificationService::AllSources());
62  }
63
64  DataTypeControllerMock* MakeBookmarkDTC() {
65    DataTypeControllerMock* dtc = new DataTypeControllerMock();
66    EXPECT_CALL(*dtc, enabled()).WillRepeatedly(Return(true));
67    EXPECT_CALL(*dtc, type()).WillRepeatedly(Return(syncable::BOOKMARKS));
68    EXPECT_CALL(*dtc, name()).WillRepeatedly(Return("bookmark"));
69    return dtc;
70  }
71
72  DataTypeControllerMock* MakePreferenceDTC() {
73    DataTypeControllerMock* dtc = new DataTypeControllerMock();
74    EXPECT_CALL(*dtc, enabled()).WillRepeatedly(Return(true));
75    EXPECT_CALL(*dtc, type()).WillRepeatedly(Return(syncable::PREFERENCES));
76    EXPECT_CALL(*dtc, name()).WillRepeatedly(Return("preference"));
77    return dtc;
78  }
79
80  DataTypeControllerMock* MakePasswordDTC() {
81    DataTypeControllerMock* dtc = new DataTypeControllerMock();
82    EXPECT_CALL(*dtc, enabled()).WillRepeatedly(Return(true));
83    EXPECT_CALL(*dtc, type()).WillRepeatedly(Return(syncable::PASSWORDS));
84    EXPECT_CALL(*dtc, name()).WillRepeatedly(Return("passwords"));
85    return dtc;
86  }
87
88  void SetStartStopExpectations(DataTypeControllerMock* mock_dtc) {
89    InSequence seq;
90    EXPECT_CALL(*mock_dtc, state()).
91        WillRepeatedly(Return(DataTypeController::NOT_RUNNING));
92    EXPECT_CALL(*mock_dtc, Start(_)).
93        WillOnce(InvokeCallback((DataTypeController::OK)));
94    EXPECT_CALL(*mock_dtc, state()).
95        WillRepeatedly(Return(DataTypeController::RUNNING));
96    EXPECT_CALL(*mock_dtc, Stop()).Times(1);
97    EXPECT_CALL(*mock_dtc, state()).
98        WillRepeatedly(Return(DataTypeController::NOT_RUNNING));
99  }
100
101  void SetBusyStartStopExpectations(DataTypeControllerMock* mock_dtc,
102                                    DataTypeController::State busy_state) {
103    InSequence seq;
104    EXPECT_CALL(*mock_dtc, state()).
105        WillRepeatedly(Return(DataTypeController::NOT_RUNNING));
106    EXPECT_CALL(*mock_dtc, Start(_)).
107        WillOnce(InvokeCallback((DataTypeController::OK)));
108    EXPECT_CALL(*mock_dtc, state()).
109        WillRepeatedly(Return(busy_state));
110    EXPECT_CALL(*mock_dtc, Stop()).Times(1);
111    EXPECT_CALL(*mock_dtc, state()).
112        WillRepeatedly(Return(DataTypeController::NOT_RUNNING));
113  }
114
115  void SetNotUsedExpectations(DataTypeControllerMock* mock_dtc) {
116    EXPECT_CALL(*mock_dtc, Start(_)).Times(0);
117    EXPECT_CALL(*mock_dtc, Stop()).Times(0);
118    EXPECT_CALL(*mock_dtc, state()).
119        WillRepeatedly(Return(DataTypeController::NOT_RUNNING));
120  }
121
122  void SetConfigureStartExpectation() {
123    EXPECT_CALL(
124        observer_,
125        Observe(NotificationType(NotificationType::SYNC_CONFIGURE_START),
126                _, _));
127  }
128
129  void SetConfigureDoneExpectation(DataTypeManager::ConfigureResult result) {
130    EXPECT_CALL(
131        observer_,
132        Observe(NotificationType(NotificationType::SYNC_CONFIGURE_DONE), _,
133                Property(&Details<DataTypeManager::ConfigureResult>::ptr,
134                         Pointee(result))));
135  }
136
137  MessageLoopForUI message_loop_;
138  BrowserThread ui_thread_;
139  DataTypeController::TypeMap controllers_;
140  SyncBackendHostMock backend_;
141  NotificationObserverMock observer_;
142  NotificationRegistrar registrar_;
143  std::set<syncable::ModelType> types_;
144};
145
146TEST_F(DataTypeManagerImpl2Test, NoControllers) {
147  DataTypeManagerImpl2 dtm(&backend_, controllers_);
148  SetConfigureStartExpectation();
149  SetConfigureDoneExpectation(DataTypeManager::OK);
150  dtm.Configure(types_);
151  EXPECT_EQ(DataTypeManager::CONFIGURED, dtm.state());
152  dtm.Stop();
153  EXPECT_EQ(DataTypeManager::STOPPED, dtm.state());
154}
155
156TEST_F(DataTypeManagerImpl2Test, ConfigureOne) {
157  DataTypeControllerMock* bookmark_dtc = MakeBookmarkDTC();
158  SetStartStopExpectations(bookmark_dtc);
159  controllers_[syncable::BOOKMARKS] = bookmark_dtc;
160  EXPECT_CALL(backend_, ConfigureDataTypes(_, _, _)).Times(1);
161  DataTypeManagerImpl2 dtm(&backend_, controllers_);
162  types_.insert(syncable::BOOKMARKS);
163  SetConfigureStartExpectation();
164  SetConfigureDoneExpectation(DataTypeManager::OK);
165  dtm.Configure(types_);
166  EXPECT_EQ(DataTypeManager::CONFIGURED, dtm.state());
167  dtm.Stop();
168  EXPECT_EQ(DataTypeManager::STOPPED, dtm.state());
169}
170
171TEST_F(DataTypeManagerImpl2Test, ConfigureOneStopWhileStarting) {
172  DataTypeControllerMock* bookmark_dtc = MakeBookmarkDTC();
173  SetBusyStartStopExpectations(bookmark_dtc,
174                               DataTypeController::MODEL_STARTING);
175  controllers_[syncable::BOOKMARKS] = bookmark_dtc;
176  EXPECT_CALL(backend_, ConfigureDataTypes(_, _, _)).Times(1);
177  DataTypeManagerImpl2 dtm(&backend_, controllers_);
178  types_.insert(syncable::BOOKMARKS);
179  SetConfigureStartExpectation();
180  SetConfigureDoneExpectation(DataTypeManager::OK);
181  dtm.Configure(types_);
182  EXPECT_EQ(DataTypeManager::CONFIGURED, dtm.state());
183  dtm.Stop();
184  EXPECT_EQ(DataTypeManager::STOPPED, dtm.state());
185}
186
187TEST_F(DataTypeManagerImpl2Test, ConfigureOneStopWhileAssociating) {
188  DataTypeControllerMock* bookmark_dtc = MakeBookmarkDTC();
189  SetBusyStartStopExpectations(bookmark_dtc, DataTypeController::ASSOCIATING);
190  controllers_[syncable::BOOKMARKS] = bookmark_dtc;
191  EXPECT_CALL(backend_, ConfigureDataTypes(_, _, _)).Times(1);
192  DataTypeManagerImpl2 dtm(&backend_, controllers_);
193  types_.insert(syncable::BOOKMARKS);
194  SetConfigureStartExpectation();
195  SetConfigureDoneExpectation(DataTypeManager::OK);
196  dtm.Configure(types_);
197  EXPECT_EQ(DataTypeManager::CONFIGURED, dtm.state());
198  dtm.Stop();
199  EXPECT_EQ(DataTypeManager::STOPPED, dtm.state());
200}
201
202TEST_F(DataTypeManagerImpl2Test, OneWaitingForCrypto) {
203  DataTypeControllerMock* password_dtc = MakePasswordDTC();
204  EXPECT_CALL(*password_dtc, state()).
205      WillRepeatedly(Return(DataTypeController::NOT_RUNNING));
206  EXPECT_CALL(*password_dtc, Start(_)).
207      WillOnce(InvokeCallback((DataTypeController::NEEDS_CRYPTO)));
208  EXPECT_CALL(*password_dtc, state()).
209      WillRepeatedly(Return(DataTypeController::NOT_RUNNING));
210
211  controllers_[syncable::PASSWORDS] = password_dtc;
212  EXPECT_CALL(backend_, ConfigureDataTypes(_, _, _)).Times(1);
213
214  DataTypeManagerImpl2 dtm(&backend_, controllers_);
215  types_.insert(syncable::PASSWORDS);
216  SetConfigureStartExpectation();
217  SetConfigureDoneExpectation(DataTypeManager::OK);
218  dtm.Configure(types_);
219  EXPECT_EQ(DataTypeManager::CONFIGURED, dtm.state());
220  dtm.Stop();
221  EXPECT_EQ(DataTypeManager::STOPPED, dtm.state());
222}
223
224TEST_F(DataTypeManagerImpl2Test, ConfigureOneThenAnother) {
225  DataTypeControllerMock* bookmark_dtc = MakeBookmarkDTC();
226  SetStartStopExpectations(bookmark_dtc);
227  controllers_[syncable::BOOKMARKS] = bookmark_dtc;
228  DataTypeControllerMock* preference_dtc = MakePreferenceDTC();
229  SetStartStopExpectations(preference_dtc);
230  controllers_[syncable::PREFERENCES] = preference_dtc;
231
232  EXPECT_CALL(backend_, ConfigureDataTypes(_, _, _)).Times(2);
233  DataTypeManagerImpl2 dtm(&backend_, controllers_);
234  types_.insert(syncable::BOOKMARKS);
235
236  SetConfigureStartExpectation();
237  SetConfigureDoneExpectation(DataTypeManager::OK);
238  dtm.Configure(types_);
239  EXPECT_EQ(DataTypeManager::CONFIGURED, dtm.state());
240
241  types_.insert(syncable::PREFERENCES);
242  SetConfigureStartExpectation();
243  SetConfigureDoneExpectation(DataTypeManager::OK);
244  dtm.Configure(types_);
245  EXPECT_EQ(DataTypeManager::CONFIGURED, dtm.state());
246
247  dtm.Stop();
248  EXPECT_EQ(DataTypeManager::STOPPED, dtm.state());
249}
250
251TEST_F(DataTypeManagerImpl2Test, ConfigureOneThenSwitch) {
252  DataTypeControllerMock* bookmark_dtc = MakeBookmarkDTC();
253  SetStartStopExpectations(bookmark_dtc);
254  controllers_[syncable::BOOKMARKS] = bookmark_dtc;
255  DataTypeControllerMock* preference_dtc = MakePreferenceDTC();
256  SetStartStopExpectations(preference_dtc);
257  controllers_[syncable::PREFERENCES] = preference_dtc;
258
259  EXPECT_CALL(backend_, ConfigureDataTypes(_, _, _)).Times(2);
260  DataTypeManagerImpl2 dtm(&backend_, controllers_);
261  types_.insert(syncable::BOOKMARKS);
262
263  SetConfigureStartExpectation();
264  SetConfigureDoneExpectation(DataTypeManager::OK);
265  dtm.Configure(types_);
266  EXPECT_EQ(DataTypeManager::CONFIGURED, dtm.state());
267
268  types_.clear();
269  types_.insert(syncable::PREFERENCES);
270  SetConfigureStartExpectation();
271  SetConfigureDoneExpectation(DataTypeManager::OK);
272  dtm.Configure(types_);
273  EXPECT_EQ(DataTypeManager::CONFIGURED, dtm.state());
274
275  dtm.Stop();
276  EXPECT_EQ(DataTypeManager::STOPPED, dtm.state());
277}
278
279TEST_F(DataTypeManagerImpl2Test, ConfigureWhileOneInFlight) {
280  DataTypeControllerMock* bookmark_dtc = MakeBookmarkDTC();
281  // Save the callback here so we can interrupt startup.
282  DataTypeController::StartCallback* callback;
283  {
284    InSequence seq;
285    EXPECT_CALL(*bookmark_dtc, state()).
286        WillRepeatedly(Return(DataTypeController::NOT_RUNNING));
287    EXPECT_CALL(*bookmark_dtc, Start(_)).
288        WillOnce(SaveArg<0>(&callback));
289    EXPECT_CALL(*bookmark_dtc, state()).
290        WillRepeatedly(Return(DataTypeController::RUNNING));
291    EXPECT_CALL(*bookmark_dtc, Stop()).Times(1);
292    EXPECT_CALL(*bookmark_dtc, state()).
293        WillRepeatedly(Return(DataTypeController::NOT_RUNNING));
294  }
295  controllers_[syncable::BOOKMARKS] = bookmark_dtc;
296
297  DataTypeControllerMock* preference_dtc = MakePreferenceDTC();
298  SetStartStopExpectations(preference_dtc);
299  controllers_[syncable::PREFERENCES] = preference_dtc;
300
301  EXPECT_CALL(backend_, ConfigureDataTypes(_, _, _)).Times(2);
302  DataTypeManagerImpl2 dtm(&backend_, controllers_);
303  types_.insert(syncable::BOOKMARKS);
304
305  SetConfigureStartExpectation();
306  SetConfigureDoneExpectation(DataTypeManager::OK);
307  dtm.Configure(types_);
308
309  // At this point, the bookmarks dtc should be in flight.  Add
310  // preferences and continue starting bookmarks.
311  types_.insert(syncable::PREFERENCES);
312  dtm.Configure(types_);
313  callback->Run(DataTypeController::OK);
314  delete callback;
315
316  EXPECT_EQ(DataTypeManager::CONFIGURED, dtm.state());
317
318  dtm.Stop();
319  EXPECT_EQ(DataTypeManager::STOPPED, dtm.state());
320}
321
322TEST_F(DataTypeManagerImpl2Test, OneFailingController) {
323  DataTypeControllerMock* bookmark_dtc = MakeBookmarkDTC();
324  EXPECT_CALL(*bookmark_dtc, Start(_)).
325      WillOnce(InvokeCallback((DataTypeController::ASSOCIATION_FAILED)));
326  EXPECT_CALL(*bookmark_dtc, Stop()).Times(0);
327  EXPECT_CALL(*bookmark_dtc, state()).
328      WillRepeatedly(Return(DataTypeController::NOT_RUNNING));
329  controllers_[syncable::BOOKMARKS] = bookmark_dtc;
330
331  DataTypeManagerImpl2 dtm(&backend_, controllers_);
332  SetConfigureStartExpectation();
333  SetConfigureDoneExpectation(DataTypeManager::ASSOCIATION_FAILED);
334  EXPECT_CALL(backend_, ConfigureDataTypes(_, _, _)).Times(1);
335
336  types_.insert(syncable::BOOKMARKS);
337  dtm.Configure(types_);
338  EXPECT_EQ(DataTypeManager::STOPPED, dtm.state());
339}
340
341TEST_F(DataTypeManagerImpl2Test, StopWhileInFlight) {
342  DataTypeControllerMock* bookmark_dtc = MakeBookmarkDTC();
343  SetStartStopExpectations(bookmark_dtc);
344  controllers_[syncable::BOOKMARKS] = bookmark_dtc;
345
346  DataTypeControllerMock* preference_dtc = MakePreferenceDTC();
347  // Save the callback here so we can interrupt startup.
348  DataTypeController::StartCallback* callback;
349  EXPECT_CALL(*preference_dtc, Start(_)).
350      WillOnce(SaveArg<0>(&callback));
351  EXPECT_CALL(*preference_dtc, Stop()).Times(1);
352  EXPECT_CALL(*preference_dtc, state()).
353      WillRepeatedly(Return(DataTypeController::NOT_RUNNING));
354  controllers_[syncable::PREFERENCES] = preference_dtc;
355
356  DataTypeManagerImpl2 dtm(&backend_, controllers_);
357  SetConfigureStartExpectation();
358  SetConfigureDoneExpectation(DataTypeManager::ABORTED);
359  EXPECT_CALL(backend_, ConfigureDataTypes(_, _, _)).Times(1);
360
361  types_.insert(syncable::BOOKMARKS);
362  types_.insert(syncable::PREFERENCES);
363  dtm.Configure(types_);
364  // Configure should stop in the CONFIGURING state because we are
365  // waiting for the preferences callback to be invoked.
366  EXPECT_EQ(DataTypeManager::CONFIGURING, dtm.state());
367
368  // Call stop before the preference callback is invoked.
369  dtm.Stop();
370  callback->Run(DataTypeController::ABORTED);
371  delete callback;
372  EXPECT_EQ(DataTypeManager::STOPPED, dtm.state());
373}
374
375TEST_F(DataTypeManagerImpl2Test, SecondControllerFails) {
376  DataTypeControllerMock* bookmark_dtc = MakeBookmarkDTC();
377  SetStartStopExpectations(bookmark_dtc);
378  controllers_[syncable::BOOKMARKS] = bookmark_dtc;
379
380  DataTypeControllerMock* preference_dtc = MakePreferenceDTC();
381  EXPECT_CALL(*preference_dtc, Start(_)).
382      WillOnce(InvokeCallback((DataTypeController::ASSOCIATION_FAILED)));
383  EXPECT_CALL(*preference_dtc, Stop()).Times(0);
384  EXPECT_CALL(*preference_dtc, state()).
385      WillRepeatedly(Return(DataTypeController::NOT_RUNNING));
386  controllers_[syncable::PREFERENCES] = preference_dtc;
387
388  DataTypeManagerImpl2 dtm(&backend_, controllers_);
389  SetConfigureStartExpectation();
390  SetConfigureDoneExpectation(DataTypeManager::ASSOCIATION_FAILED);
391  EXPECT_CALL(backend_, ConfigureDataTypes(_, _, _)).Times(1);
392
393  types_.insert(syncable::BOOKMARKS);
394  types_.insert(syncable::PREFERENCES);
395  dtm.Configure(types_);
396  EXPECT_EQ(DataTypeManager::STOPPED, dtm.state());
397}
398
399TEST_F(DataTypeManagerImpl2Test, ConfigureWhileDownloadPending) {
400  DataTypeControllerMock* bookmark_dtc = MakeBookmarkDTC();
401  SetStartStopExpectations(bookmark_dtc);
402  controllers_[syncable::BOOKMARKS] = bookmark_dtc;
403
404  DataTypeControllerMock* preference_dtc = MakePreferenceDTC();
405  SetStartStopExpectations(preference_dtc);
406  controllers_[syncable::PREFERENCES] = preference_dtc;
407
408  DataTypeManagerImpl2 dtm(&backend_, controllers_);
409  SetConfigureStartExpectation();
410  SetConfigureDoneExpectation(DataTypeManager::OK);
411  CancelableTask* task;
412  // Grab the task the first time this is called so we can configure
413  // before it is finished.
414  EXPECT_CALL(backend_, ConfigureDataTypes(_, _, _)).
415      WillOnce(SaveArg<2>(&task)).
416      WillOnce(DoDefault());
417
418  types_.insert(syncable::BOOKMARKS);
419  dtm.Configure(types_);
420  // Configure should stop in the DOWNLOAD_PENDING state because we
421  // are waiting for the download ready task to be run.
422  EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm.state());
423
424  types_.insert(syncable::PREFERENCES);
425  dtm.Configure(types_);
426
427  // Should now be RESTARTING.
428  EXPECT_EQ(DataTypeManager::RESTARTING, dtm.state());
429
430  // Running the task will queue a restart task to the message loop, and
431  // eventually get us configured.
432  task->Run();
433  delete task;
434  EXPECT_EQ(DataTypeManager::RESTARTING, dtm.state());
435  MessageLoop::current()->RunAllPending();
436  EXPECT_EQ(DataTypeManager::CONFIGURED, dtm.state());
437
438  dtm.Stop();
439  EXPECT_EQ(DataTypeManager::STOPPED, dtm.state());
440}
441
442TEST_F(DataTypeManagerImpl2Test, StopWhileDownloadPending) {
443  DataTypeControllerMock* bookmark_dtc = MakeBookmarkDTC();
444  SetNotUsedExpectations(bookmark_dtc);
445  controllers_[syncable::BOOKMARKS] = bookmark_dtc;
446
447  DataTypeManagerImpl2 dtm(&backend_, controllers_);
448  SetConfigureStartExpectation();
449  SetConfigureDoneExpectation(DataTypeManager::ABORTED);
450  CancelableTask* task;
451  // Grab the task the first time this is called so we can stop
452  // before it is finished.
453  EXPECT_CALL(backend_, ConfigureDataTypes(_, _, _)).
454      WillOnce(SaveArg<2>(&task));
455
456  types_.insert(syncable::BOOKMARKS);
457  dtm.Configure(types_);
458  // Configure should stop in the DOWNLOAD_PENDING state because we
459  // are waiting for the download ready task to be run.
460  EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm.state());
461
462  dtm.Stop();
463  EXPECT_EQ(DataTypeManager::STOPPED, dtm.state());
464
465  // It should be perfectly safe to run this task even though the DTM
466  // has been stopped.
467  task->Run();
468  delete task;
469}
470