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