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: 17 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 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 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: 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. 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. 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. 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. 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. 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 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 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. 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