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