- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / sync / glue / model_association_manager_unittest.cc
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.
4
5 #include "base/callback.h"
6 #include "base/message_loop/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"
12
13 using ::testing::_;
14 namespace browser_sync {
15 class MockModelAssociationResultProcessor :
16     public ModelAssociationResultProcessor {
17  public:
18   MockModelAssociationResultProcessor() {}
19   ~MockModelAssociationResultProcessor() {}
20   MOCK_METHOD2(OnSingleDataTypeAssociationDone,
21                void(syncer::ModelType type,
22                     const syncer::DataTypeAssociationStats& association_stats));
23   MOCK_METHOD1(OnModelAssociationDone, void(
24       const DataTypeManager::ConfigureResult& result));
25   MOCK_METHOD0(OnTypesLoaded, void());
26 };
27
28 FakeDataTypeController* GetController(
29     const DataTypeController::TypeMap& controllers,
30     syncer::ModelType model_type) {
31   DataTypeController::TypeMap::const_iterator it =
32       controllers.find(model_type);
33   if (it == controllers.end()) {
34     return NULL;
35   }
36   return (FakeDataTypeController*)(it->second.get());
37 }
38
39 ACTION_P(VerifyResult, expected_result) {
40   EXPECT_EQ(arg0.status, expected_result.status);
41   EXPECT_TRUE(arg0.requested_types.Equals(expected_result.requested_types));
42   EXPECT_EQ(arg0.failed_data_types.size(),
43             expected_result.failed_data_types.size());
44
45   if (arg0.failed_data_types.size() ==
46           expected_result.failed_data_types.size()) {
47     std::map<syncer::ModelType, syncer::SyncError>::const_iterator it1, it2;
48     for (it1 = arg0.failed_data_types.begin(),
49          it2 = expected_result.failed_data_types.begin();
50          it1 != arg0.failed_data_types.end();
51          ++it1, ++it2) {
52       EXPECT_EQ((*it1).first, (*it2).first);
53     }
54   }
55
56   EXPECT_TRUE(arg0.waiting_to_start.Equals(expected_result.waiting_to_start));
57 }
58
59 class SyncModelAssociationManagerTest : public testing::Test {
60  public:
61   SyncModelAssociationManagerTest() :
62       ui_thread_(content::BrowserThread::UI, &ui_loop_) {
63   }
64
65  protected:
66   base::MessageLoopForUI ui_loop_;
67   content::TestBrowserThread ui_thread_;
68   MockModelAssociationResultProcessor result_processor_;
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.
74 TEST_F(SyncModelAssociationManagerTest, SimpleModelStart) {
75   controllers_[syncer::BOOKMARKS] =
76       new FakeDataTypeController(syncer::BOOKMARKS);
77   ModelAssociationManager model_association_manager(&controllers_,
78                                                     &result_processor_);
79   syncer::ModelTypeSet types;
80   types.Put(syncer::BOOKMARKS);
81   DataTypeManager::ConfigureResult expected_result(
82       DataTypeManager::OK,
83       types,
84       std::map<syncer::ModelType, syncer::SyncError>(),
85       syncer::ModelTypeSet(),
86       syncer::ModelTypeSet());
87   EXPECT_CALL(result_processor_, OnModelAssociationDone(_)).
88               WillOnce(VerifyResult(expected_result));
89
90   model_association_manager.Initialize(types);
91   model_association_manager.StopDisabledTypes();
92   model_association_manager.StartAssociationAsync(types);
93
94   EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
95             DataTypeController::ASSOCIATING);
96   GetController(controllers_, syncer::BOOKMARKS)->FinishStart(
97       DataTypeController::OK);
98 }
99
100 // Start a type and call stop before it finishes associating.
101 TEST_F(SyncModelAssociationManagerTest, StopModelBeforeFinish) {
102   controllers_[syncer::BOOKMARKS] =
103       new FakeDataTypeController(syncer::BOOKMARKS);
104   ModelAssociationManager model_association_manager(
105       &controllers_,
106       &result_processor_);
107
108   syncer::ModelTypeSet types;
109   types.Put(syncer::BOOKMARKS);
110
111   DataTypeManager::ConfigureResult expected_result(
112       DataTypeManager::ABORTED,
113       types,
114       std::map<syncer::ModelType, syncer::SyncError>(),
115       syncer::ModelTypeSet(),
116       syncer::ModelTypeSet());
117
118   EXPECT_CALL(result_processor_, OnModelAssociationDone(_)).
119               WillOnce(VerifyResult(expected_result));
120
121   model_association_manager.Initialize(types);
122   model_association_manager.StopDisabledTypes();
123   model_association_manager.StartAssociationAsync(types);
124
125   EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
126             DataTypeController::ASSOCIATING);
127   model_association_manager.Stop();
128   EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
129             DataTypeController::NOT_RUNNING);
130 }
131
132 // Start a type, let it finish and then call stop.
133 TEST_F(SyncModelAssociationManagerTest, StopAfterFinish) {
134   controllers_[syncer::BOOKMARKS] =
135       new FakeDataTypeController(syncer::BOOKMARKS);
136   ModelAssociationManager model_association_manager(
137       &controllers_,
138       &result_processor_);
139   syncer::ModelTypeSet types;
140   types.Put(syncer::BOOKMARKS);
141   DataTypeManager::ConfigureResult expected_result(
142       DataTypeManager::OK,
143       types,
144       std::map<syncer::ModelType, syncer::SyncError>(),
145       syncer::ModelTypeSet(),
146       syncer::ModelTypeSet());
147   EXPECT_CALL(result_processor_, OnModelAssociationDone(_)).
148               WillOnce(VerifyResult(expected_result));
149
150   model_association_manager.Initialize(types);
151   model_association_manager.StopDisabledTypes();
152   model_association_manager.StartAssociationAsync(types);
153
154   EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
155             DataTypeController::ASSOCIATING);
156   GetController(controllers_, syncer::BOOKMARKS)->FinishStart(
157       DataTypeController::OK);
158
159   model_association_manager.Stop();
160   EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
161             DataTypeController::NOT_RUNNING);
162 }
163
164 // Make a type fail model association and verify correctness.
165 TEST_F(SyncModelAssociationManagerTest, TypeFailModelAssociation) {
166   controllers_[syncer::BOOKMARKS] =
167       new FakeDataTypeController(syncer::BOOKMARKS);
168   ModelAssociationManager model_association_manager(
169       &controllers_,
170       &result_processor_);
171   syncer::ModelTypeSet types;
172   types.Put(syncer::BOOKMARKS);
173   std::map<syncer::ModelType, syncer::SyncError> errors;
174   syncer::SyncError error(FROM_HERE,
175                           syncer::SyncError::DATATYPE_ERROR,
176                           "Failed",
177                           syncer::BOOKMARKS);
178   errors[syncer::BOOKMARKS] = error;
179   DataTypeManager::ConfigureResult expected_result(
180       DataTypeManager::PARTIAL_SUCCESS,
181       types,
182       errors,
183       syncer::ModelTypeSet(),
184       syncer::ModelTypeSet());
185   EXPECT_CALL(result_processor_, OnModelAssociationDone(_)).
186               WillOnce(VerifyResult(expected_result));
187
188   model_association_manager.Initialize(types);
189   model_association_manager.StopDisabledTypes();
190   model_association_manager.StartAssociationAsync(types);
191
192   EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
193             DataTypeController::ASSOCIATING);
194   GetController(controllers_, syncer::BOOKMARKS)->FinishStart(
195       DataTypeController::ASSOCIATION_FAILED);
196   EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
197             DataTypeController::NOT_RUNNING);
198 }
199
200 // Ensure configuring stops when a type returns a unrecoverable error.
201 TEST_F(SyncModelAssociationManagerTest, TypeReturnUnrecoverableError) {
202   controllers_[syncer::BOOKMARKS] =
203       new FakeDataTypeController(syncer::BOOKMARKS);
204   ModelAssociationManager model_association_manager(
205       &controllers_,
206       &result_processor_);
207   syncer::ModelTypeSet types;
208   types.Put(syncer::BOOKMARKS);
209   std::map<syncer::ModelType, syncer::SyncError> errors;
210   syncer::SyncError error(FROM_HERE,
211                           syncer::SyncError::DATATYPE_ERROR,
212                           "Failed",
213                           syncer::BOOKMARKS);
214   errors[syncer::BOOKMARKS] = error;
215   DataTypeManager::ConfigureResult expected_result(
216       DataTypeManager::UNRECOVERABLE_ERROR,
217       types,
218       errors,
219       syncer::ModelTypeSet(),
220       syncer::ModelTypeSet());
221   EXPECT_CALL(result_processor_, OnModelAssociationDone(_)).
222               WillOnce(VerifyResult(expected_result));
223
224   model_association_manager.Initialize(types);
225   model_association_manager.StopDisabledTypes();
226   model_association_manager.StartAssociationAsync(types);
227
228   EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
229             DataTypeController::ASSOCIATING);
230   GetController(controllers_, syncer::BOOKMARKS)->FinishStart(
231       DataTypeController::UNRECOVERABLE_ERROR);
232 }
233
234 TEST_F(SyncModelAssociationManagerTest, InitializeAbortsLoad) {
235   controllers_[syncer::BOOKMARKS] =
236       new FakeDataTypeController(syncer::BOOKMARKS);
237   controllers_[syncer::THEMES] =
238       new FakeDataTypeController(syncer::THEMES);
239
240   GetController(controllers_, syncer::BOOKMARKS)->SetDelayModelLoad();
241   ModelAssociationManager model_association_manager(&controllers_,
242                                                     &result_processor_);
243   syncer::ModelTypeSet types(syncer::BOOKMARKS, syncer::THEMES);
244
245   syncer::ModelTypeSet expected_types_waiting_to_load;
246   expected_types_waiting_to_load.Put(syncer::BOOKMARKS);
247   DataTypeManager::ConfigureResult expected_result_partially_done(
248       DataTypeManager::PARTIAL_SUCCESS,
249       types,
250       std::map<syncer::ModelType, syncer::SyncError>(),
251       expected_types_waiting_to_load,
252       syncer::ModelTypeSet());
253
254   model_association_manager.Initialize(types);
255   model_association_manager.StopDisabledTypes();
256
257   model_association_manager.StartAssociationAsync(types);
258
259   EXPECT_CALL(result_processor_, OnModelAssociationDone(_)).
260               WillOnce(VerifyResult(expected_result_partially_done));
261
262   base::OneShotTimer<ModelAssociationManager>* timer =
263       model_association_manager.GetTimerForTesting();
264
265   base::Closure task = timer->user_task();
266   timer->Stop();
267   task.Run();  // Bookmark load times out here.
268
269   // Apps finishes associating here.
270   GetController(controllers_, syncer::THEMES)->FinishStart(
271       DataTypeController::OK);
272
273   // At this point, BOOKMARKS is still waiting to load (as evidenced by
274   // expected_result_partially_done). If we schedule another Initialize (which
275   // could happen in practice due to reconfiguration), this should abort
276   // BOOKMARKS. Aborting will call ModelLoadCallback, but the
277   // ModelAssociationManager should be smart enough to know that this is not due
278   // to the type having completed loading.
279   EXPECT_CALL(result_processor_, OnTypesLoaded()).Times(0);
280
281   EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
282             DataTypeController::MODEL_STARTING);
283
284   model_association_manager.Initialize(types);
285   EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
286             DataTypeController::NOT_RUNNING);
287
288   DataTypeManager::ConfigureResult expected_result_done(
289       DataTypeManager::OK,
290       types,
291       std::map<syncer::ModelType, syncer::SyncError>(),
292       syncer::ModelTypeSet(),
293       syncer::ModelTypeSet());
294   EXPECT_CALL(result_processor_, OnModelAssociationDone(_)).
295               WillOnce(VerifyResult(expected_result_done));
296
297   model_association_manager.StopDisabledTypes();
298   model_association_manager.StartAssociationAsync(types);
299
300   GetController(controllers_,
301                 syncer::BOOKMARKS)->SimulateModelLoadFinishing();
302   GetController(controllers_, syncer::BOOKMARKS)->FinishStart(
303       DataTypeController::OK);
304 }
305
306 // Start 2 types. One of which timeout loading. Ensure that type is
307 // fully configured eventually.
308 TEST_F(SyncModelAssociationManagerTest, ModelStartWithSlowLoadingType) {
309   controllers_[syncer::BOOKMARKS] =
310       new FakeDataTypeController(syncer::BOOKMARKS);
311   controllers_[syncer::APPS] =
312       new FakeDataTypeController(syncer::APPS);
313   GetController(controllers_, syncer::BOOKMARKS)->SetDelayModelLoad();
314   ModelAssociationManager model_association_manager(&controllers_,
315                                                     &result_processor_);
316   syncer::ModelTypeSet types;
317   types.Put(syncer::BOOKMARKS);
318   types.Put(syncer::APPS);
319
320   syncer::ModelTypeSet expected_types_waiting_to_load;
321   expected_types_waiting_to_load.Put(syncer::BOOKMARKS);
322   DataTypeManager::ConfigureResult expected_result_partially_done(
323       DataTypeManager::PARTIAL_SUCCESS,
324       types,
325       std::map<syncer::ModelType, syncer::SyncError>(),
326       expected_types_waiting_to_load,
327       syncer::ModelTypeSet());
328
329   DataTypeManager::ConfigureResult expected_result_done(
330       DataTypeManager::OK,
331       types,
332       std::map<syncer::ModelType, syncer::SyncError>(),
333       syncer::ModelTypeSet(),
334       syncer::ModelTypeSet());
335
336   EXPECT_CALL(result_processor_, OnModelAssociationDone(_)).
337               WillOnce(VerifyResult(expected_result_partially_done));
338   EXPECT_CALL(result_processor_, OnTypesLoaded());
339
340   model_association_manager.Initialize(types);
341   model_association_manager.StopDisabledTypes();
342   model_association_manager.StartAssociationAsync(types);
343
344   base::OneShotTimer<ModelAssociationManager>* timer =
345       model_association_manager.GetTimerForTesting();
346
347   // Note: Independent of the timeout value this test is not flaky.
348   // The reason is timer posts a task which would never be executed
349   // as we dont let the message loop run.
350   base::Closure task = timer->user_task();
351   timer->Stop();
352   task.Run();
353
354   // Simulate delayed loading of bookmark model.
355   GetController(controllers_, syncer::APPS)->FinishStart(
356       DataTypeController::OK);
357
358   GetController(controllers_,
359                 syncer::BOOKMARKS)->SimulateModelLoadFinishing();
360
361   EXPECT_CALL(result_processor_, OnModelAssociationDone(_)).
362               WillOnce(VerifyResult(expected_result_done));
363
364   // Do it once more to associate bookmarks.
365   model_association_manager.Initialize(types);
366   model_association_manager.StopDisabledTypes();
367   model_association_manager.StartAssociationAsync(types);
368
369   GetController(controllers_,
370                 syncer::BOOKMARKS)->SimulateModelLoadFinishing();
371
372   GetController(controllers_, syncer::BOOKMARKS)->FinishStart(
373       DataTypeController::OK);
374 }
375
376 TEST_F(SyncModelAssociationManagerTest, StartMultipleTimes) {
377   controllers_[syncer::BOOKMARKS] =
378       new FakeDataTypeController(syncer::BOOKMARKS);
379   controllers_[syncer::APPS] =
380       new FakeDataTypeController(syncer::APPS);
381   ModelAssociationManager model_association_manager(&controllers_,
382                                                     &result_processor_);
383   syncer::ModelTypeSet types;
384   types.Put(syncer::BOOKMARKS);
385   types.Put(syncer::APPS);
386
387   DataTypeManager::ConfigureResult result_1st(
388       DataTypeManager::OK,
389       syncer::ModelTypeSet(syncer::BOOKMARKS),
390       std::map<syncer::ModelType, syncer::SyncError>(),
391       syncer::ModelTypeSet(),
392       syncer::ModelTypeSet());
393   DataTypeManager::ConfigureResult result_2nd(
394       DataTypeManager::OK,
395       syncer::ModelTypeSet(syncer::APPS),
396       std::map<syncer::ModelType, syncer::SyncError>(),
397       syncer::ModelTypeSet(),
398       syncer::ModelTypeSet());
399   EXPECT_CALL(result_processor_, OnModelAssociationDone(_)).
400       Times(2).
401       WillOnce(VerifyResult(result_1st)).
402       WillOnce(VerifyResult(result_2nd));
403
404   model_association_manager.Initialize(types);
405   model_association_manager.StopDisabledTypes();
406
407   // Start BOOKMARKS first.
408   model_association_manager.StartAssociationAsync(
409       syncer::ModelTypeSet(syncer::BOOKMARKS));
410   EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
411             DataTypeController::ASSOCIATING);
412   EXPECT_EQ(GetController(controllers_, syncer::APPS)->state(),
413             DataTypeController::NOT_RUNNING);
414
415   // Finish BOOKMARKS association.
416   GetController(controllers_, syncer::BOOKMARKS)->FinishStart(
417       DataTypeController::OK);
418   EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
419             DataTypeController::RUNNING);
420   EXPECT_EQ(GetController(controllers_, syncer::APPS)->state(),
421             DataTypeController::NOT_RUNNING);
422
423   // Start APPS next.
424   model_association_manager.StartAssociationAsync(
425       syncer::ModelTypeSet(syncer::APPS));
426   EXPECT_EQ(GetController(controllers_, syncer::APPS)->state(),
427             DataTypeController::ASSOCIATING);
428   GetController(controllers_, syncer::APPS)->FinishStart(
429       DataTypeController::OK);
430   EXPECT_EQ(GetController(controllers_, syncer::APPS)->state(),
431             DataTypeController::RUNNING);
432 }
433
434 }  // namespace browser_sync