model_association_manager_unittest.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
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 "base/callback.h"
6#include "base/message_loop/message_loop.h"
7#include "components/sync_driver/fake_data_type_controller.h"
8#include "components/sync_driver/model_association_manager.h"
9#include "testing/gmock/include/gmock/gmock.h"
10#include "testing/gtest/include/gtest/gtest.h"
11
12using ::testing::_;
13
14namespace sync_driver {
15
16class MockModelAssociationManagerDelegate :
17    public ModelAssociationManagerDelegate {
18 public:
19  MockModelAssociationManagerDelegate() {}
20  ~MockModelAssociationManagerDelegate() {}
21  MOCK_METHOD2(OnSingleDataTypeAssociationDone,
22      void(syncer::ModelType type,
23      const syncer::DataTypeAssociationStats& association_stats));
24  MOCK_METHOD1(OnSingleDataTypeWillStop, void(syncer::ModelType));
25  MOCK_METHOD1(OnModelAssociationDone, void(
26      const DataTypeManager::ConfigureResult& result));
27};
28
29FakeDataTypeController* GetController(
30    const DataTypeController::TypeMap& controllers,
31    syncer::ModelType model_type) {
32  DataTypeController::TypeMap::const_iterator it =
33      controllers.find(model_type);
34  if (it == controllers.end()) {
35    return NULL;
36  }
37  return (FakeDataTypeController*)(it->second.get());
38}
39
40ACTION_P(VerifyResult, expected_result) {
41  EXPECT_EQ(arg0.status, expected_result.status);
42  EXPECT_TRUE(arg0.requested_types.Equals(expected_result.requested_types));
43  EXPECT_EQ(arg0.failed_data_types.size(),
44            expected_result.failed_data_types.size());
45
46  if (arg0.failed_data_types.size() ==
47          expected_result.failed_data_types.size()) {
48    std::map<syncer::ModelType, syncer::SyncError>::const_iterator it1, it2;
49    for (it1 = arg0.failed_data_types.begin(),
50         it2 = expected_result.failed_data_types.begin();
51         it1 != arg0.failed_data_types.end();
52         ++it1, ++it2) {
53      EXPECT_EQ((*it1).first, (*it2).first);
54    }
55  }
56
57  EXPECT_TRUE(arg0.unfinished_data_types.Equals(
58      expected_result.unfinished_data_types));
59}
60
61class SyncModelAssociationManagerTest : public testing::Test {
62 public:
63  SyncModelAssociationManagerTest() {
64  }
65
66 protected:
67  base::MessageLoopForUI ui_loop_;
68  MockModelAssociationManagerDelegate delegate_;
69  DataTypeController::TypeMap controllers_;
70};
71
72// Start a type and make sure ModelAssociationManager callst the |Start|
73// method and calls the callback when it is done.
74TEST_F(SyncModelAssociationManagerTest, SimpleModelStart) {
75  controllers_[syncer::BOOKMARKS] =
76      new FakeDataTypeController(syncer::BOOKMARKS);
77  controllers_[syncer::APPS] =
78      new FakeDataTypeController(syncer::APPS);
79  ModelAssociationManager model_association_manager(&controllers_,
80                                                    &delegate_);
81  syncer::ModelTypeSet types(syncer::BOOKMARKS, syncer::APPS);
82  DataTypeManager::ConfigureResult expected_result(
83      DataTypeManager::OK,
84      types,
85      std::map<syncer::ModelType, syncer::SyncError>(),
86      syncer::ModelTypeSet(),
87      syncer::ModelTypeSet());
88  EXPECT_CALL(delegate_, OnModelAssociationDone(_)).
89              WillOnce(VerifyResult(expected_result));
90
91  EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
92            DataTypeController::NOT_RUNNING);
93  EXPECT_EQ(GetController(controllers_, syncer::APPS)->state(),
94            DataTypeController::NOT_RUNNING);
95
96  // Initialize() kicks off model loading.
97  model_association_manager.Initialize(types);
98
99  EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
100            DataTypeController::MODEL_LOADED);
101  EXPECT_EQ(GetController(controllers_, syncer::APPS)->state(),
102            DataTypeController::MODEL_LOADED);
103
104  model_association_manager.StartAssociationAsync(types);
105
106  EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
107            DataTypeController::ASSOCIATING);
108  EXPECT_EQ(GetController(controllers_, syncer::APPS)->state(),
109            DataTypeController::ASSOCIATING);
110  GetController(controllers_, syncer::BOOKMARKS)->FinishStart(
111      DataTypeController::OK);
112  GetController(controllers_, syncer::APPS)->FinishStart(
113      DataTypeController::OK);
114}
115
116// Start a type and call stop before it finishes associating.
117TEST_F(SyncModelAssociationManagerTest, StopModelBeforeFinish) {
118  controllers_[syncer::BOOKMARKS] =
119      new FakeDataTypeController(syncer::BOOKMARKS);
120  ModelAssociationManager model_association_manager(
121      &controllers_,
122      &delegate_);
123
124  syncer::ModelTypeSet types;
125  types.Put(syncer::BOOKMARKS);
126
127  std::map<syncer::ModelType, syncer::SyncError> errors;
128  syncer::SyncError error(FROM_HERE,
129                          syncer::SyncError::DATATYPE_ERROR,
130                          "Failed",
131                          syncer::BOOKMARKS);
132  errors[syncer::BOOKMARKS] = error;
133
134  DataTypeManager::ConfigureResult expected_result(
135      DataTypeManager::ABORTED,
136      types,
137      errors,
138      syncer::ModelTypeSet(syncer::BOOKMARKS),
139      syncer::ModelTypeSet());
140
141  EXPECT_CALL(delegate_, OnModelAssociationDone(_)).
142              WillOnce(VerifyResult(expected_result));
143  EXPECT_CALL(delegate_,
144              OnSingleDataTypeWillStop(syncer::BOOKMARKS));
145
146  model_association_manager.Initialize(types);
147  model_association_manager.StartAssociationAsync(types);
148
149  EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
150            DataTypeController::ASSOCIATING);
151  model_association_manager.Stop();
152  EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
153            DataTypeController::NOT_RUNNING);
154}
155
156// Start a type, let it finish and then call stop.
157TEST_F(SyncModelAssociationManagerTest, StopAfterFinish) {
158  controllers_[syncer::BOOKMARKS] =
159      new FakeDataTypeController(syncer::BOOKMARKS);
160  ModelAssociationManager model_association_manager(
161      &controllers_,
162      &delegate_);
163  syncer::ModelTypeSet types;
164  types.Put(syncer::BOOKMARKS);
165  DataTypeManager::ConfigureResult expected_result(
166      DataTypeManager::OK,
167      types,
168      std::map<syncer::ModelType, syncer::SyncError>(),
169      syncer::ModelTypeSet(),
170      syncer::ModelTypeSet());
171  EXPECT_CALL(delegate_, OnModelAssociationDone(_)).
172              WillOnce(VerifyResult(expected_result));
173  EXPECT_CALL(delegate_,
174              OnSingleDataTypeWillStop(syncer::BOOKMARKS));
175
176  model_association_manager.Initialize(types);
177  model_association_manager.StartAssociationAsync(types);
178
179  EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
180            DataTypeController::ASSOCIATING);
181  GetController(controllers_, syncer::BOOKMARKS)->FinishStart(
182      DataTypeController::OK);
183
184  model_association_manager.Stop();
185  EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
186            DataTypeController::NOT_RUNNING);
187}
188
189// Make a type fail model association and verify correctness.
190TEST_F(SyncModelAssociationManagerTest, TypeFailModelAssociation) {
191  controllers_[syncer::BOOKMARKS] =
192      new FakeDataTypeController(syncer::BOOKMARKS);
193  ModelAssociationManager model_association_manager(
194      &controllers_,
195      &delegate_);
196  syncer::ModelTypeSet types;
197  types.Put(syncer::BOOKMARKS);
198  std::map<syncer::ModelType, syncer::SyncError> errors;
199  syncer::SyncError error(FROM_HERE,
200                          syncer::SyncError::DATATYPE_ERROR,
201                          "Failed",
202                          syncer::BOOKMARKS);
203  errors[syncer::BOOKMARKS] = error;
204  DataTypeManager::ConfigureResult expected_result(
205      DataTypeManager::PARTIAL_SUCCESS,
206      types,
207      errors,
208      syncer::ModelTypeSet(),
209      syncer::ModelTypeSet());
210  EXPECT_CALL(delegate_, OnModelAssociationDone(_)).
211              WillOnce(VerifyResult(expected_result));
212
213  model_association_manager.Initialize(types);
214  model_association_manager.StartAssociationAsync(types);
215
216  EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
217            DataTypeController::ASSOCIATING);
218  GetController(controllers_, syncer::BOOKMARKS)->FinishStart(
219      DataTypeController::ASSOCIATION_FAILED);
220  EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
221            DataTypeController::NOT_RUNNING);
222}
223
224// Ensure configuring stops when a type returns a unrecoverable error.
225TEST_F(SyncModelAssociationManagerTest, TypeReturnUnrecoverableError) {
226  controllers_[syncer::BOOKMARKS] =
227      new FakeDataTypeController(syncer::BOOKMARKS);
228  ModelAssociationManager model_association_manager(
229      &controllers_,
230      &delegate_);
231  syncer::ModelTypeSet types;
232  types.Put(syncer::BOOKMARKS);
233  std::map<syncer::ModelType, syncer::SyncError> errors;
234  syncer::SyncError error(FROM_HERE,
235                          syncer::SyncError::DATATYPE_ERROR,
236                          "Failed",
237                          syncer::BOOKMARKS);
238  errors[syncer::BOOKMARKS] = error;
239  DataTypeManager::ConfigureResult expected_result(
240      DataTypeManager::UNRECOVERABLE_ERROR,
241      types,
242      errors,
243      syncer::ModelTypeSet(),
244      syncer::ModelTypeSet());
245  EXPECT_CALL(delegate_, OnModelAssociationDone(_)).
246              WillOnce(VerifyResult(expected_result));
247
248  model_association_manager.Initialize(types);
249
250  model_association_manager.StartAssociationAsync(types);
251
252  EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
253            DataTypeController::ASSOCIATING);
254  GetController(controllers_, syncer::BOOKMARKS)->FinishStart(
255      DataTypeController::UNRECOVERABLE_ERROR);
256}
257
258TEST_F(SyncModelAssociationManagerTest, SlowTypeAsFailedType) {
259  controllers_[syncer::BOOKMARKS] =
260      new FakeDataTypeController(syncer::BOOKMARKS);
261  controllers_[syncer::APPS] =
262      new FakeDataTypeController(syncer::APPS);
263  GetController(controllers_, syncer::BOOKMARKS)->SetDelayModelLoad();
264  ModelAssociationManager model_association_manager(&controllers_,
265                                                    &delegate_);
266  syncer::ModelTypeSet types;
267  types.Put(syncer::BOOKMARKS);
268  types.Put(syncer::APPS);
269
270  std::map<syncer::ModelType, syncer::SyncError> errors;
271  syncer::SyncError error(FROM_HERE,
272                          syncer::SyncError::DATATYPE_ERROR,
273                          "Association timed out.",
274                          syncer::BOOKMARKS);
275  errors[syncer::BOOKMARKS] = error;
276
277  syncer::ModelTypeSet expected_types_unfinished;
278  expected_types_unfinished.Put(syncer::BOOKMARKS);
279  DataTypeManager::ConfigureResult expected_result_partially_done(
280      DataTypeManager::PARTIAL_SUCCESS,
281      types,
282      errors,
283      expected_types_unfinished,
284      syncer::ModelTypeSet());
285
286  EXPECT_CALL(delegate_, OnModelAssociationDone(_)).
287              WillOnce(VerifyResult(expected_result_partially_done));
288
289  model_association_manager.Initialize(types);
290  model_association_manager.StartAssociationAsync(types);
291  GetController(controllers_, syncer::APPS)->FinishStart(
292      DataTypeController::OK);
293
294  model_association_manager.GetTimerForTesting()->user_task().Run();
295
296  EXPECT_EQ(DataTypeController::NOT_RUNNING,
297            GetController(controllers_, syncer::BOOKMARKS)->state());
298}
299
300TEST_F(SyncModelAssociationManagerTest, StartMultipleTimes) {
301  controllers_[syncer::BOOKMARKS] =
302      new FakeDataTypeController(syncer::BOOKMARKS);
303  controllers_[syncer::APPS] =
304      new FakeDataTypeController(syncer::APPS);
305  ModelAssociationManager model_association_manager(&controllers_,
306                                                    &delegate_);
307  syncer::ModelTypeSet types;
308  types.Put(syncer::BOOKMARKS);
309  types.Put(syncer::APPS);
310
311  DataTypeManager::ConfigureResult result_1st(
312      DataTypeManager::OK,
313      syncer::ModelTypeSet(syncer::BOOKMARKS),
314      std::map<syncer::ModelType, syncer::SyncError>(),
315      syncer::ModelTypeSet(),
316      syncer::ModelTypeSet());
317  DataTypeManager::ConfigureResult result_2nd(
318      DataTypeManager::OK,
319      syncer::ModelTypeSet(syncer::APPS),
320      std::map<syncer::ModelType, syncer::SyncError>(),
321      syncer::ModelTypeSet(),
322      syncer::ModelTypeSet());
323  EXPECT_CALL(delegate_, OnModelAssociationDone(_)).
324      Times(2).
325      WillOnce(VerifyResult(result_1st)).
326      WillOnce(VerifyResult(result_2nd));
327
328  model_association_manager.Initialize(types);
329
330  // Start BOOKMARKS first.
331  model_association_manager.StartAssociationAsync(
332      syncer::ModelTypeSet(syncer::BOOKMARKS));
333  EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
334            DataTypeController::ASSOCIATING);
335  EXPECT_EQ(GetController(controllers_, syncer::APPS)->state(),
336            DataTypeController::MODEL_LOADED);
337
338  // Finish BOOKMARKS association.
339  GetController(controllers_, syncer::BOOKMARKS)->FinishStart(
340      DataTypeController::OK);
341  EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
342            DataTypeController::RUNNING);
343  EXPECT_EQ(GetController(controllers_, syncer::APPS)->state(),
344            DataTypeController::MODEL_LOADED);
345
346  // Start APPS next.
347  model_association_manager.StartAssociationAsync(
348      syncer::ModelTypeSet(syncer::APPS));
349  EXPECT_EQ(GetController(controllers_, syncer::APPS)->state(),
350            DataTypeController::ASSOCIATING);
351  GetController(controllers_, syncer::APPS)->FinishStart(
352      DataTypeController::OK);
353  EXPECT_EQ(GetController(controllers_, syncer::APPS)->state(),
354            DataTypeController::RUNNING);
355}
356
357// Test that model that failed to load between initialization and association
358// is reported and stopped properly.
359TEST_F(SyncModelAssociationManagerTest, ModelLoadFailBeforeAssociationStart) {
360  controllers_[syncer::BOOKMARKS] =
361      new FakeDataTypeController(syncer::BOOKMARKS);
362  GetController(controllers_, syncer::BOOKMARKS)->SetModelLoadError(
363      syncer::SyncError(FROM_HERE, syncer::SyncError::DATATYPE_ERROR,
364                        "", syncer::BOOKMARKS));
365  ModelAssociationManager model_association_manager(
366      &controllers_,
367      &delegate_);
368  syncer::ModelTypeSet types;
369  types.Put(syncer::BOOKMARKS);
370  std::map<syncer::ModelType, syncer::SyncError> errors;
371  syncer::SyncError error(FROM_HERE,
372                          syncer::SyncError::DATATYPE_ERROR,
373                          "Failed",
374                          syncer::BOOKMARKS);
375  errors[syncer::BOOKMARKS] = error;
376  DataTypeManager::ConfigureResult expected_result(
377      DataTypeManager::PARTIAL_SUCCESS,
378      types,
379      errors,
380      syncer::ModelTypeSet(),
381      syncer::ModelTypeSet());
382  EXPECT_CALL(delegate_, OnModelAssociationDone(_)).
383              WillOnce(VerifyResult(expected_result));
384
385  model_association_manager.Initialize(types);
386  EXPECT_EQ(DataTypeController::DISABLED,
387            GetController(controllers_, syncer::BOOKMARKS)->state());
388  model_association_manager.StartAssociationAsync(types);
389  EXPECT_EQ(DataTypeController::NOT_RUNNING,
390            GetController(controllers_, syncer::BOOKMARKS)->state());
391}
392
393}  // namespace sync_driver
394