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