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.
5 #include "base/callback.h"
6 #include "base/message_loop.h"
7 #include "chrome/browser/sync/glue/fake_data_type_controller.h"
8 #include "chrome/browser/sync/glue/model_association_manager.h"
9 #include "content/public/test/test_browser_thread.h"
10 #include "testing/gmock/include/gmock/gmock.h"
11 #include "testing/gtest/include/gtest/gtest.h"
14 namespace browser_sync
{
15 class MockModelAssociationResultProcessor
:
16 public ModelAssociationResultProcessor
{
18 MockModelAssociationResultProcessor() {}
19 ~MockModelAssociationResultProcessor() {}
20 MOCK_METHOD1(OnModelAssociationDone
, void(
21 const DataTypeManager::ConfigureResult
& result
));
22 MOCK_METHOD0(OnTypesLoaded
, void());
25 FakeDataTypeController
* GetController(
26 const DataTypeController::TypeMap
& controllers
,
27 syncer::ModelType model_type
) {
28 DataTypeController::TypeMap::const_iterator it
=
29 controllers
.find(model_type
);
30 if (it
== controllers
.end()) {
33 return (FakeDataTypeController
*)(it
->second
.get());
36 ACTION_P(VerifyResult
, expected_result
) {
37 EXPECT_EQ(arg0
.status
, expected_result
.status
);
38 EXPECT_TRUE(arg0
.requested_types
.Equals(expected_result
.requested_types
));
39 EXPECT_EQ(arg0
.failed_data_types
.size(),
40 expected_result
.failed_data_types
.size());
42 if (arg0
.failed_data_types
.size() ==
43 expected_result
.failed_data_types
.size()) {
44 std::list
<syncer::SyncError
>::const_iterator it1
, it2
;
45 for (it1
= arg0
.failed_data_types
.begin(),
46 it2
= expected_result
.failed_data_types
.begin();
47 it1
!= arg0
.failed_data_types
.end();
49 EXPECT_EQ((*it1
).type(), (*it2
).type());
53 EXPECT_TRUE(arg0
.waiting_to_start
.Equals(expected_result
.waiting_to_start
));
56 class SyncModelAssociationManagerTest
: public testing::Test
{
58 SyncModelAssociationManagerTest() :
59 ui_thread_(content::BrowserThread::UI
, &ui_loop_
) {
63 MessageLoopForUI ui_loop_
;
64 content::TestBrowserThread ui_thread_
;
65 MockModelAssociationResultProcessor result_processor_
;
66 DataTypeController::TypeMap controllers_
;
69 // Start a type and make sure ModelAssociationManager callst the |Start|
70 // method and calls the callback when it is done.
71 TEST_F(SyncModelAssociationManagerTest
, SimpleModelStart
) {
72 controllers_
[syncer::BOOKMARKS
] =
73 new FakeDataTypeController(syncer::BOOKMARKS
);
74 ModelAssociationManager
model_association_manager(
75 syncer::WeakHandle
<syncer::DataTypeDebugInfoListener
>(),
78 syncer::ModelTypeSet types
;
79 types
.Put(syncer::BOOKMARKS
);
80 DataTypeManager::ConfigureResult
expected_result(
83 std::list
<syncer::SyncError
>(),
84 syncer::ModelTypeSet());
85 EXPECT_CALL(result_processor_
, OnModelAssociationDone(_
)).
86 WillOnce(VerifyResult(expected_result
));
88 model_association_manager
.Initialize(types
);
89 model_association_manager
.StopDisabledTypes();
90 model_association_manager
.StartAssociationAsync();
92 EXPECT_EQ(GetController(controllers_
, syncer::BOOKMARKS
)->state(),
93 DataTypeController::MODEL_LOADED
);
94 GetController(controllers_
, syncer::BOOKMARKS
)->FinishStart(
95 DataTypeController::OK
);
98 // Start a type and call stop before it finishes associating.
99 TEST_F(SyncModelAssociationManagerTest
, StopModelBeforeFinish
) {
100 controllers_
[syncer::BOOKMARKS
] =
101 new FakeDataTypeController(syncer::BOOKMARKS
);
102 ModelAssociationManager
model_association_manager(
103 syncer::WeakHandle
<syncer::DataTypeDebugInfoListener
>(),
107 syncer::ModelTypeSet types
;
108 types
.Put(syncer::BOOKMARKS
);
110 DataTypeManager::ConfigureResult
expected_result(
111 DataTypeManager::ABORTED
,
113 std::list
<syncer::SyncError
>(),
114 syncer::ModelTypeSet());
116 EXPECT_CALL(result_processor_
, OnModelAssociationDone(_
)).
117 WillOnce(VerifyResult(expected_result
));
119 model_association_manager
.Initialize(types
);
120 model_association_manager
.StopDisabledTypes();
121 model_association_manager
.StartAssociationAsync();
123 EXPECT_EQ(GetController(controllers_
, syncer::BOOKMARKS
)->state(),
124 DataTypeController::MODEL_LOADED
);
125 model_association_manager
.Stop();
126 EXPECT_EQ(GetController(controllers_
, syncer::BOOKMARKS
)->state(),
127 DataTypeController::NOT_RUNNING
);
130 // Start a type, let it finish and then call stop.
131 TEST_F(SyncModelAssociationManagerTest
, StopAfterFinish
) {
132 controllers_
[syncer::BOOKMARKS
] =
133 new FakeDataTypeController(syncer::BOOKMARKS
);
134 ModelAssociationManager
model_association_manager(
135 syncer::WeakHandle
<syncer::DataTypeDebugInfoListener
>(),
138 syncer::ModelTypeSet types
;
139 types
.Put(syncer::BOOKMARKS
);
140 DataTypeManager::ConfigureResult
expected_result(
143 std::list
<syncer::SyncError
>(),
144 syncer::ModelTypeSet());
145 EXPECT_CALL(result_processor_
, OnModelAssociationDone(_
)).
146 WillOnce(VerifyResult(expected_result
));
148 model_association_manager
.Initialize(types
);
149 model_association_manager
.StopDisabledTypes();
150 model_association_manager
.StartAssociationAsync();
152 EXPECT_EQ(GetController(controllers_
, syncer::BOOKMARKS
)->state(),
153 DataTypeController::MODEL_LOADED
);
154 GetController(controllers_
, syncer::BOOKMARKS
)->FinishStart(
155 DataTypeController::OK
);
157 model_association_manager
.Stop();
158 EXPECT_EQ(GetController(controllers_
, syncer::BOOKMARKS
)->state(),
159 DataTypeController::NOT_RUNNING
);
162 // Make a type fail model association and verify correctness.
163 TEST_F(SyncModelAssociationManagerTest
, TypeFailModelAssociation
) {
164 controllers_
[syncer::BOOKMARKS
] =
165 new FakeDataTypeController(syncer::BOOKMARKS
);
166 ModelAssociationManager
model_association_manager(
167 syncer::WeakHandle
<syncer::DataTypeDebugInfoListener
>(),
170 syncer::ModelTypeSet types
;
171 types
.Put(syncer::BOOKMARKS
);
172 std::list
<syncer::SyncError
> errors
;
173 syncer::SyncError
error(FROM_HERE
, "Failed", syncer::BOOKMARKS
);
174 errors
.push_back(error
);
175 DataTypeManager::ConfigureResult
expected_result(
176 DataTypeManager::PARTIAL_SUCCESS
,
179 syncer::ModelTypeSet());
180 EXPECT_CALL(result_processor_
, OnModelAssociationDone(_
)).
181 WillOnce(VerifyResult(expected_result
));
183 model_association_manager
.Initialize(types
);
184 model_association_manager
.StopDisabledTypes();
185 model_association_manager
.StartAssociationAsync();
187 EXPECT_EQ(GetController(controllers_
, syncer::BOOKMARKS
)->state(),
188 DataTypeController::MODEL_LOADED
);
189 GetController(controllers_
, syncer::BOOKMARKS
)->FinishStart(
190 DataTypeController::ASSOCIATION_FAILED
);
193 // Ensure configuring stops when a type returns a unrecoverable error.
194 TEST_F(SyncModelAssociationManagerTest
, TypeReturnUnrecoverableError
) {
195 controllers_
[syncer::BOOKMARKS
] =
196 new FakeDataTypeController(syncer::BOOKMARKS
);
197 ModelAssociationManager
model_association_manager(
198 syncer::WeakHandle
<syncer::DataTypeDebugInfoListener
>(),
201 syncer::ModelTypeSet types
;
202 types
.Put(syncer::BOOKMARKS
);
203 std::list
<syncer::SyncError
> errors
;
204 syncer::SyncError
error(FROM_HERE
, "Failed", syncer::BOOKMARKS
);
205 errors
.push_back(error
);
206 DataTypeManager::ConfigureResult
expected_result(
207 DataTypeManager::UNRECOVERABLE_ERROR
,
210 syncer::ModelTypeSet());
211 EXPECT_CALL(result_processor_
, OnModelAssociationDone(_
)).
212 WillOnce(VerifyResult(expected_result
));
214 model_association_manager
.Initialize(types
);
215 model_association_manager
.StopDisabledTypes();
216 model_association_manager
.StartAssociationAsync();
218 EXPECT_EQ(GetController(controllers_
, syncer::BOOKMARKS
)->state(),
219 DataTypeController::MODEL_LOADED
);
220 GetController(controllers_
, syncer::BOOKMARKS
)->FinishStart(
221 DataTypeController::UNRECOVERABLE_ERROR
);
224 TEST_F(SyncModelAssociationManagerTest
, InitializeAbortsLoad
) {
225 controllers_
[syncer::BOOKMARKS
] =
226 new FakeDataTypeController(syncer::BOOKMARKS
);
227 controllers_
[syncer::THEMES
] =
228 new FakeDataTypeController(syncer::THEMES
);
230 GetController(controllers_
, syncer::BOOKMARKS
)->SetDelayModelLoad();
231 ModelAssociationManager
model_association_manager(
232 syncer::WeakHandle
<syncer::DataTypeDebugInfoListener
>(),
235 syncer::ModelTypeSet
types(syncer::BOOKMARKS
, syncer::THEMES
);
237 syncer::ModelTypeSet expected_types_waiting_to_load
;
238 expected_types_waiting_to_load
.Put(syncer::BOOKMARKS
);
239 DataTypeManager::ConfigureResult
expected_result_partially_done(
240 DataTypeManager::PARTIAL_SUCCESS
,
242 std::list
<syncer::SyncError
>(),
243 expected_types_waiting_to_load
);
245 model_association_manager
.Initialize(types
);
246 model_association_manager
.StopDisabledTypes();
248 model_association_manager
.StartAssociationAsync();
250 EXPECT_CALL(result_processor_
, OnModelAssociationDone(_
)).
251 WillOnce(VerifyResult(expected_result_partially_done
));
253 base::OneShotTimer
<ModelAssociationManager
>* timer
=
254 model_association_manager
.GetTimerForTesting();
256 base::Closure task
= timer
->user_task();
258 task
.Run(); // Bookmark load times out here.
260 // Apps finishes associating here.
261 GetController(controllers_
, syncer::THEMES
)->FinishStart(
262 DataTypeController::OK
);
264 // At this point, BOOKMARKS is still waiting to load (as evidenced by
265 // expected_result_partially_done). If we schedule another Initialize (which
266 // could happen in practice due to reconfiguration), this should abort
267 // BOOKMARKS. Aborting will call ModelLoadCallback, but the
268 // ModelAssociationManager should be smart enough to know that this is not due
269 // to the type having completed loading.
270 EXPECT_CALL(result_processor_
, OnTypesLoaded()).Times(0);
272 EXPECT_EQ(GetController(controllers_
, syncer::BOOKMARKS
)->state(),
273 DataTypeController::MODEL_STARTING
);
275 model_association_manager
.Initialize(types
);
276 EXPECT_EQ(GetController(controllers_
, syncer::BOOKMARKS
)->state(),
277 DataTypeController::NOT_RUNNING
);
279 DataTypeManager::ConfigureResult
expected_result_done(
282 std::list
<syncer::SyncError
>(),
283 syncer::ModelTypeSet());
284 EXPECT_CALL(result_processor_
, OnModelAssociationDone(_
)).
285 WillOnce(VerifyResult(expected_result_done
));
287 model_association_manager
.StopDisabledTypes();
288 model_association_manager
.StartAssociationAsync();
290 GetController(controllers_
,
291 syncer::BOOKMARKS
)->SimulateModelLoadFinishing();
292 GetController(controllers_
, syncer::BOOKMARKS
)->FinishStart(
293 DataTypeController::OK
);
296 // Start 2 types. One of which timeout loading. Ensure that type is
297 // fully configured eventually.
298 TEST_F(SyncModelAssociationManagerTest
, ModelStartWithSlowLoadingType
) {
299 controllers_
[syncer::BOOKMARKS
] =
300 new FakeDataTypeController(syncer::BOOKMARKS
);
301 controllers_
[syncer::APPS
] =
302 new FakeDataTypeController(syncer::APPS
);
303 GetController(controllers_
, syncer::BOOKMARKS
)->SetDelayModelLoad();
304 ModelAssociationManager
model_association_manager(
305 syncer::WeakHandle
<syncer::DataTypeDebugInfoListener
>(),
308 syncer::ModelTypeSet types
;
309 types
.Put(syncer::BOOKMARKS
);
310 types
.Put(syncer::APPS
);
312 syncer::ModelTypeSet expected_types_waiting_to_load
;
313 expected_types_waiting_to_load
.Put(syncer::BOOKMARKS
);
314 DataTypeManager::ConfigureResult
expected_result_partially_done(
315 DataTypeManager::PARTIAL_SUCCESS
,
317 std::list
<syncer::SyncError
>(),
318 expected_types_waiting_to_load
);
320 DataTypeManager::ConfigureResult
expected_result_done(
323 std::list
<syncer::SyncError
>(),
324 syncer::ModelTypeSet());
326 EXPECT_CALL(result_processor_
, OnModelAssociationDone(_
)).
327 WillOnce(VerifyResult(expected_result_partially_done
));
328 EXPECT_CALL(result_processor_
, OnTypesLoaded());
330 model_association_manager
.Initialize(types
);
331 model_association_manager
.StopDisabledTypes();
332 model_association_manager
.StartAssociationAsync();
334 base::OneShotTimer
<ModelAssociationManager
>* timer
=
335 model_association_manager
.GetTimerForTesting();
337 // Note: Independent of the timeout value this test is not flaky.
338 // The reason is timer posts a task which would never be executed
339 // as we dont let the message loop run.
340 base::Closure task
= timer
->user_task();
344 // Simulate delayed loading of bookmark model.
345 GetController(controllers_
, syncer::APPS
)->FinishStart(
346 DataTypeController::OK
);
348 GetController(controllers_
,
349 syncer::BOOKMARKS
)->SimulateModelLoadFinishing();
351 EXPECT_CALL(result_processor_
, OnModelAssociationDone(_
)).
352 WillOnce(VerifyResult(expected_result_done
));
354 // Do it once more to associate bookmarks.
355 model_association_manager
.Initialize(types
);
356 model_association_manager
.StopDisabledTypes();
357 model_association_manager
.StartAssociationAsync();
359 GetController(controllers_
,
360 syncer::BOOKMARKS
)->SimulateModelLoadFinishing();
362 GetController(controllers_
, syncer::BOOKMARKS
)->FinishStart(
363 DataTypeController::OK
);
367 } // namespace browser_sync