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 "chrome/browser/sync/glue/data_type_manager_impl.h"
7 #include "base/compiler_specific.h"
8 #include "base/message_loop/message_loop.h"
9 #include "chrome/browser/chrome_notification_types.h"
10 #include "components/sync_driver/backend_data_type_configurer.h"
11 #include "components/sync_driver/data_type_controller.h"
12 #include "components/sync_driver/data_type_encryption_handler.h"
13 #include "components/sync_driver/data_type_manager_observer.h"
14 #include "components/sync_driver/failed_data_types_handler.h"
15 #include "components/sync_driver/fake_data_type_controller.h"
16 #include "content/public/test/test_browser_thread.h"
17 #include "sync/internal_api/public/base/model_type.h"
18 #include "sync/internal_api/public/configure_reason.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20 #include "testing/gtest/include/gtest/gtest.h"
22 namespace browser_sync {
24 using syncer::ModelType;
25 using syncer::ModelTypeSet;
26 using syncer::ModelTypeToString;
27 using syncer::BOOKMARKS;
29 using syncer::PASSWORDS;
30 using syncer::PREFERENCES;
34 using testing::ResultOf;
38 // Used by SetConfigureDoneExpectation.
39 DataTypeManager::ConfigureStatus GetStatus(
40 const DataTypeManager::ConfigureResult& result) {
44 // Helper for unioning with priority types.
45 syncer::ModelTypeSet AddHighPriorityTypesTo(syncer::ModelTypeSet types) {
46 syncer::ModelTypeSet result = syncer::ControlTypes();
51 // Fake BackendDataTypeConfigurer implementation that simply stores away the
52 // callback passed into ConfigureDataTypes.
53 class FakeBackendDataTypeConfigurer : public BackendDataTypeConfigurer {
55 FakeBackendDataTypeConfigurer() {}
56 virtual ~FakeBackendDataTypeConfigurer() {}
58 virtual void ConfigureDataTypes(
59 syncer::ConfigureReason reason,
60 const DataTypeConfigStateMap& config_state_map,
61 const base::Callback<void(ModelTypeSet,
62 ModelTypeSet)>& ready_task,
63 const base::Callback<void()>& retry_callback) OVERRIDE {
64 last_ready_task_ = ready_task;
66 if (!expected_configure_types_.Empty()) {
68 expected_configure_types_.Equals(
69 GetDataTypesInState(CONFIGURE_ACTIVE, config_state_map)))
70 << syncer::ModelTypeSetToString(expected_configure_types_)
72 << syncer::ModelTypeSetToString(
73 GetDataTypesInState(CONFIGURE_ACTIVE, config_state_map));
77 base::Callback<void(ModelTypeSet, ModelTypeSet)> last_ready_task() const {
78 return last_ready_task_;
81 void set_expected_configure_types(syncer::ModelTypeSet types) {
82 expected_configure_types_ = types;
86 base::Callback<void(ModelTypeSet, ModelTypeSet)> last_ready_task_;
87 syncer::ModelTypeSet expected_configure_types_;
90 // Mock DataTypeManagerObserver implementation.
91 class DataTypeManagerObserverMock : public DataTypeManagerObserver {
93 DataTypeManagerObserverMock() {}
94 virtual ~DataTypeManagerObserverMock() {}
96 MOCK_METHOD1(OnConfigureDone,
97 void(const browser_sync::DataTypeManager::ConfigureResult&));
98 MOCK_METHOD0(OnConfigureRetry, void());
99 MOCK_METHOD0(OnConfigureStart, void());
102 class FakeDataTypeEncryptionHandler : public DataTypeEncryptionHandler {
104 FakeDataTypeEncryptionHandler();
105 virtual ~FakeDataTypeEncryptionHandler();
107 virtual bool IsPassphraseRequired() const OVERRIDE;
108 virtual syncer::ModelTypeSet GetEncryptedDataTypes() const OVERRIDE;
110 void set_passphrase_required(bool passphrase_required) {
111 passphrase_required_ = passphrase_required;
113 void set_encrypted_types(syncer::ModelTypeSet encrypted_types) {
114 encrypted_types_ = encrypted_types;
117 bool passphrase_required_;
118 syncer::ModelTypeSet encrypted_types_;
121 FakeDataTypeEncryptionHandler::FakeDataTypeEncryptionHandler()
122 : passphrase_required_(false) {}
123 FakeDataTypeEncryptionHandler::~FakeDataTypeEncryptionHandler() {}
125 bool FakeDataTypeEncryptionHandler::IsPassphraseRequired() const {
126 return passphrase_required_;
130 FakeDataTypeEncryptionHandler::GetEncryptedDataTypes() const {
131 return encrypted_types_;
136 class TestDataTypeManager : public DataTypeManagerImpl {
139 const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
141 BackendDataTypeConfigurer* configurer,
142 const DataTypeController::TypeMap* controllers,
143 const DataTypeEncryptionHandler* encryption_handler,
144 DataTypeManagerObserver* observer,
145 FailedDataTypesHandler* failed_data_types_handler)
146 : DataTypeManagerImpl(debug_info_listener,
151 failed_data_types_handler),
152 custom_priority_types_(syncer::ControlTypes()) {}
154 void set_priority_types(const syncer::ModelTypeSet& priority_types) {
155 custom_priority_types_ = priority_types;
158 DataTypeManager::ConfigureResult configure_result() const {
159 return configure_result_;
162 virtual void OnModelAssociationDone(
163 const DataTypeManager::ConfigureResult& result) OVERRIDE {
164 configure_result_ = result;
165 DataTypeManagerImpl::OnModelAssociationDone(result);
169 virtual syncer::ModelTypeSet GetPriorityTypes() const OVERRIDE {
170 return custom_priority_types_;
173 syncer::ModelTypeSet custom_priority_types_;
174 DataTypeManager::ConfigureResult configure_result_;
177 // The actual test harness class, parametrized on nigori state (i.e., tests are
178 // run both configuring with nigori, and configuring without).
179 class SyncDataTypeManagerImplTest : public testing::Test {
181 SyncDataTypeManagerImplTest()
182 : ui_thread_(content::BrowserThread::UI, &ui_loop_) {}
184 virtual ~SyncDataTypeManagerImplTest() {
188 virtual void SetUp() {
190 new TestDataTypeManager(
191 syncer::WeakHandle<syncer::DataTypeDebugInfoListener>(),
194 &encryption_handler_,
196 &failed_data_types_handler_));
199 void SetConfigureStartExpectation() {
200 EXPECT_CALL(observer_, OnConfigureStart());
203 void SetConfigureDoneExpectation(DataTypeManager::ConfigureStatus status) {
204 EXPECT_CALL(observer_, OnConfigureDone(ResultOf(&GetStatus, status)));
207 // Configure the given DTM with the given desired types.
208 void Configure(DataTypeManagerImpl* dtm,
209 const syncer::ModelTypeSet& desired_types) {
210 dtm->Configure(desired_types, syncer::CONFIGURE_REASON_RECONFIGURATION);
213 // Finish downloading for the given DTM. Should be done only after
214 // a call to Configure().
215 void FinishDownload(const DataTypeManager& dtm,
216 ModelTypeSet types_to_configure,
217 ModelTypeSet failed_download_types) {
218 EXPECT_TRUE(DataTypeManager::DOWNLOAD_PENDING == dtm.state() ||
219 DataTypeManager::CONFIGURING == dtm.state());
220 ASSERT_FALSE(configurer_.last_ready_task().is_null());
221 configurer_.last_ready_task().Run(
222 syncer::Difference(types_to_configure, failed_download_types),
223 failed_download_types);
226 // Adds a fake controller for the given type to |controllers_|.
227 // Should be called only before setting up the DTM.
228 void AddController(ModelType model_type) {
229 controllers_[model_type] = new FakeDataTypeController(model_type);
232 // Gets the fake controller for the given type, which should have
233 // been previously added via AddController().
234 scoped_refptr<FakeDataTypeController> GetController(
235 ModelType model_type) const {
236 DataTypeController::TypeMap::const_iterator it =
237 controllers_.find(model_type);
238 if (it == controllers_.end()) {
241 return make_scoped_refptr(
242 static_cast<FakeDataTypeController*>(it->second.get()));
245 void FailEncryptionFor(syncer::ModelTypeSet encrypted_types) {
246 encryption_handler_.set_passphrase_required(true);
247 encryption_handler_.set_encrypted_types(encrypted_types);
250 base::MessageLoopForUI ui_loop_;
251 content::TestBrowserThread ui_thread_;
252 DataTypeController::TypeMap controllers_;
253 FakeBackendDataTypeConfigurer configurer_;
254 DataTypeManagerObserverMock observer_;
255 scoped_ptr<TestDataTypeManager> dtm_;
256 FailedDataTypesHandler failed_data_types_handler_;
257 FakeDataTypeEncryptionHandler encryption_handler_;
260 // Set up a DTM with no controllers, configure it, finish downloading,
262 TEST_F(SyncDataTypeManagerImplTest, NoControllers) {
263 SetConfigureStartExpectation();
264 SetConfigureDoneExpectation(DataTypeManager::OK);
266 Configure(dtm_.get(), ModelTypeSet());
267 EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
269 FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
270 EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
273 EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
276 // Set up a DTM with a single controller, configure it, finish
277 // downloading, finish starting the controller, and then stop the DTM.
278 TEST_F(SyncDataTypeManagerImplTest, ConfigureOne) {
279 AddController(BOOKMARKS);
281 SetConfigureStartExpectation();
282 SetConfigureDoneExpectation(DataTypeManager::OK);
284 Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
285 EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
287 FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
288 FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
289 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
291 GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
292 EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
295 EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
298 // Set up a DTM with a single controller, configure it, but stop it
299 // before finishing the download. It should still be safe to run the
300 // download callback even after the DTM is stopped and destroyed.
301 TEST_F(SyncDataTypeManagerImplTest, ConfigureOneStopWhileDownloadPending) {
302 AddController(BOOKMARKS);
305 SetConfigureStartExpectation();
306 SetConfigureDoneExpectation(DataTypeManager::ABORTED);
308 Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
309 EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
312 EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
315 configurer_.last_ready_task().Run(ModelTypeSet(BOOKMARKS), ModelTypeSet());
318 // Set up a DTM with a single controller, configure it, finish
319 // downloading, but stop the DTM before the controller finishes
320 // starting up. It should still be safe to finish starting up the
321 // controller even after the DTM is stopped and destroyed.
322 TEST_F(SyncDataTypeManagerImplTest, ConfigureOneStopWhileStartingModel) {
323 AddController(BOOKMARKS);
326 SetConfigureStartExpectation();
327 SetConfigureDoneExpectation(DataTypeManager::ABORTED);
329 Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
330 EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
332 FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
333 FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
334 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
337 EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
341 GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
344 // Set up a DTM with a single controller, configure it, finish
345 // downloading, start the controller's model, but stop the DTM before
346 // the controller finishes starting up. It should still be safe to
347 // finish starting up the controller even after the DTM is stopped and
349 TEST_F(SyncDataTypeManagerImplTest, ConfigureOneStopWhileAssociating) {
350 AddController(BOOKMARKS);
353 SetConfigureStartExpectation();
354 SetConfigureDoneExpectation(DataTypeManager::ABORTED);
356 Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
357 EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
359 FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
360 FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
361 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
364 EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
368 GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
371 // Set up a DTM with a single controller. Then:
374 // 2) Finish the download for step 1.
375 // 3) Finish starting the controller with the NEEDS_CRYPTO status.
376 // 4) Complete download for the reconfiguration without the controller.
378 TEST_F(SyncDataTypeManagerImplTest, OneWaitingForCrypto) {
379 AddController(PASSWORDS);
381 SetConfigureStartExpectation();
382 SetConfigureDoneExpectation(DataTypeManager::PARTIAL_SUCCESS);
384 const ModelTypeSet types(PASSWORDS);
385 dtm_->set_priority_types(AddHighPriorityTypesTo(types));
388 Configure(dtm_.get(), types);
389 EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
392 FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
393 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
396 FailEncryptionFor(types);
397 GetController(PASSWORDS)->FinishStart(DataTypeController::NEEDS_CRYPTO);
398 EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
401 FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
402 EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
406 EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
409 // Set up a DTM with two controllers. Then:
411 // 1) Configure with first controller.
412 // 2) Finish the download for step 1.
413 // 3) Finish starting the first controller.
414 // 4) Configure with both controllers.
415 // 5) Finish the download for step 4.
416 // 6) Finish starting the second controller.
418 TEST_F(SyncDataTypeManagerImplTest, ConfigureOneThenBoth) {
419 AddController(BOOKMARKS);
420 AddController(PREFERENCES);
422 SetConfigureStartExpectation();
423 SetConfigureDoneExpectation(DataTypeManager::OK);
426 Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
427 EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
430 FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
431 FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
432 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
435 GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
436 EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
438 Mock::VerifyAndClearExpectations(&observer_);
439 SetConfigureStartExpectation();
440 SetConfigureDoneExpectation(DataTypeManager::OK);
443 Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
444 EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
447 FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
448 FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS, PREFERENCES), ModelTypeSet());
449 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
452 GetController(PREFERENCES)->FinishStart(DataTypeController::OK);
453 EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
457 EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
460 // Set up a DTM with two controllers. Then:
462 // 1) Configure with first controller.
463 // 2) Finish the download for step 1.
464 // 3) Finish starting the first controller.
465 // 4) Configure with second controller.
466 // 5) Finish the download for step 4.
467 // 6) Finish starting the second controller.
469 TEST_F(SyncDataTypeManagerImplTest, ConfigureOneThenSwitch) {
470 AddController(BOOKMARKS);
471 AddController(PREFERENCES);
473 SetConfigureStartExpectation();
474 SetConfigureDoneExpectation(DataTypeManager::OK);
477 Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
478 EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
481 FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
482 FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
483 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
486 GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
487 EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
489 Mock::VerifyAndClearExpectations(&observer_);
490 SetConfigureStartExpectation();
491 SetConfigureDoneExpectation(DataTypeManager::OK);
494 Configure(dtm_.get(), ModelTypeSet(PREFERENCES));
495 EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
498 FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
499 FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
500 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
503 GetController(PREFERENCES)->FinishStart(DataTypeController::OK);
504 EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
508 EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
511 // Set up a DTM with two controllers. Then:
513 // 1) Configure with first controller.
514 // 2) Finish the download for step 1.
515 // 3) Configure with both controllers.
516 // 4) Finish starting the first controller.
517 // 5) Finish the download for step 3.
518 // 6) Finish starting the second controller.
520 TEST_F(SyncDataTypeManagerImplTest, ConfigureWhileOneInFlight) {
521 AddController(BOOKMARKS);
522 AddController(PREFERENCES);
524 SetConfigureStartExpectation();
525 SetConfigureDoneExpectation(DataTypeManager::OK);
528 Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
529 EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
532 FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
533 FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
534 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
537 Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
538 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
541 GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
542 EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
545 FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
546 FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS, PREFERENCES), ModelTypeSet());
547 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
550 GetController(PREFERENCES)->FinishStart(DataTypeController::OK);
551 EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
555 EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
558 // Set up a DTM with one controller. Then configure, finish
559 // downloading, and start the controller with an unrecoverable error.
560 // The unrecoverable error should cause the DTM to stop.
561 TEST_F(SyncDataTypeManagerImplTest, OneFailingController) {
562 AddController(BOOKMARKS);
564 SetConfigureStartExpectation();
565 SetConfigureDoneExpectation(DataTypeManager::UNRECOVERABLE_ERROR);
567 Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
568 EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
570 FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
571 FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
572 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
574 GetController(BOOKMARKS)->FinishStart(
575 DataTypeController::UNRECOVERABLE_ERROR);
576 EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
579 // Set up a DTM with two controllers. Then:
581 // 1) Configure with both controllers.
582 // 2) Finish the download for step 1.
583 // 3) Finish starting the first controller successfully.
584 // 4) Finish starting the second controller with an unrecoverable error.
586 // The failure from step 4 should cause the DTM to stop.
587 TEST_F(SyncDataTypeManagerImplTest, SecondControllerFails) {
588 AddController(BOOKMARKS);
589 AddController(PREFERENCES);
591 SetConfigureStartExpectation();
592 SetConfigureDoneExpectation(DataTypeManager::UNRECOVERABLE_ERROR);
595 Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
596 EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
599 FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
600 FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS, PREFERENCES), ModelTypeSet());
601 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
604 GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
605 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
608 GetController(PREFERENCES)->FinishStart(
609 DataTypeController::UNRECOVERABLE_ERROR);
610 EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
613 // Set up a DTM with two controllers. Then:
615 // 1) Configure with both controllers.
616 // 2) Finish the download for step 1.
617 // 3) Finish starting the first controller successfully.
618 // 4) Finish starting the second controller with an association failure.
619 // 5) Finish the purge/reconfigure without the failed type.
622 // The association failure from step 3 should be ignored.
624 // TODO(akalin): Check that the data type that failed association is
625 // recorded in the CONFIGURE_DONE notification.
626 TEST_F(SyncDataTypeManagerImplTest, OneControllerFailsAssociation) {
627 AddController(BOOKMARKS);
628 AddController(PREFERENCES);
630 SetConfigureStartExpectation();
631 SetConfigureDoneExpectation(DataTypeManager::PARTIAL_SUCCESS);
634 Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
635 EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
638 FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
639 FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS, PREFERENCES), ModelTypeSet());
640 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
643 GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
644 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
647 GetController(PREFERENCES)->FinishStart(
648 DataTypeController::ASSOCIATION_FAILED);
649 EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
652 FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
653 FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
654 EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
658 EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
661 // Set up a DTM with two controllers. Then:
663 // 1) Configure with first controller.
664 // 2) Configure with both controllers.
665 // 3) Finish the download for step 1.
666 // 4) Finish the download for step 2.
667 // 5) Finish starting both controllers.
669 TEST_F(SyncDataTypeManagerImplTest, ConfigureWhileDownloadPending) {
670 AddController(BOOKMARKS);
671 AddController(PREFERENCES);
673 SetConfigureStartExpectation();
674 SetConfigureDoneExpectation(DataTypeManager::OK);
677 Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
678 EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
681 Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
682 EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
685 FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
686 EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
689 FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
690 FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS, PREFERENCES), ModelTypeSet());
691 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
694 GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
695 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
696 GetController(PREFERENCES)->FinishStart(DataTypeController::OK);
697 EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
701 EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
704 // Set up a DTM with two controllers. Then:
706 // 1) Configure with first controller.
707 // 2) Configure with both controllers.
708 // 3) Finish the download for step 1 with a failed data type.
709 // 4) Finish the download for step 2 successfully.
710 // 5) Finish starting both controllers.
713 // The failure from step 3 should be ignored since there's a
714 // reconfigure pending from step 2.
715 TEST_F(SyncDataTypeManagerImplTest, ConfigureWhileDownloadPendingWithFailure) {
716 AddController(BOOKMARKS);
717 AddController(PREFERENCES);
719 SetConfigureStartExpectation();
720 SetConfigureDoneExpectation(DataTypeManager::OK);
723 Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
724 FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
725 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
728 Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
729 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
732 FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
733 FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
734 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
737 FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS, PREFERENCES), ModelTypeSet());
738 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
741 GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
742 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
743 GetController(PREFERENCES)->FinishStart(DataTypeController::OK);
744 EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
748 EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
751 // Tests a Purge then Configure. This is similar to the sequence of
752 // operations that would be invoked by the BackendMigrator.
753 TEST_F(SyncDataTypeManagerImplTest, MigrateAll) {
754 AddController(BOOKMARKS);
755 dtm_->set_priority_types(AddHighPriorityTypesTo(ModelTypeSet(BOOKMARKS)));
757 SetConfigureStartExpectation();
758 SetConfigureDoneExpectation(DataTypeManager::OK);
761 Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
762 FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
763 GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
765 // We've now configured bookmarks and (implicitly) the control types.
766 EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
767 Mock::VerifyAndClearExpectations(&observer_);
769 // Pretend we were told to migrate all types.
770 ModelTypeSet to_migrate;
771 to_migrate.Put(BOOKMARKS);
772 to_migrate.PutAll(syncer::ControlTypes());
774 SetConfigureStartExpectation();
775 SetConfigureDoneExpectation(DataTypeManager::OK);
776 dtm_->PurgeForMigration(to_migrate,
777 syncer::CONFIGURE_REASON_MIGRATION);
778 EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
780 // The DTM will call ConfigureDataTypes(), even though it is unnecessary.
781 FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
782 EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
783 Mock::VerifyAndClearExpectations(&observer_);
785 // Re-enable the migrated types.
786 SetConfigureStartExpectation();
787 SetConfigureDoneExpectation(DataTypeManager::OK);
788 Configure(dtm_.get(), to_migrate);
789 FinishDownload(*dtm_, to_migrate, ModelTypeSet());
790 GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
791 EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
794 // Test receipt of a Configure request while a purge is in flight.
795 TEST_F(SyncDataTypeManagerImplTest, ConfigureDuringPurge) {
796 AddController(BOOKMARKS);
797 AddController(PREFERENCES);
799 // Initial configure.
800 SetConfigureStartExpectation();
801 SetConfigureDoneExpectation(DataTypeManager::OK);
802 Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
803 FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
804 FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
805 GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
806 EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
807 Mock::VerifyAndClearExpectations(&observer_);
809 // Purge the Nigori type.
810 SetConfigureStartExpectation();
811 dtm_->PurgeForMigration(ModelTypeSet(NIGORI),
812 syncer::CONFIGURE_REASON_MIGRATION);
813 EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
814 Mock::VerifyAndClearExpectations(&observer_);
816 // Before the backend configuration completes, ask for a different
817 // set of types. This request asks for
818 // - BOOKMARKS: which is redundant because it was already enabled,
819 // - PREFERENCES: which is new and will need to be downloaded, and
820 // - NIGORI: (added implicitly because it is a control type) which
821 // the DTM is part-way through purging.
822 Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
823 EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
825 // Invoke the callback we've been waiting for since we asked to purge NIGORI.
826 FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
827 Mock::VerifyAndClearExpectations(&observer_);
829 SetConfigureDoneExpectation(DataTypeManager::OK);
830 EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
832 // Now invoke the callback for the second configure request.
833 FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
834 FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS, PREFERENCES), ModelTypeSet());
835 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
837 // Start the preferences controller. We don't need to start controller for
838 // the NIGORI because it has none. We don't need to start the controller for
839 // the BOOKMARKS because it was never stopped.
840 GetController(PREFERENCES)->FinishStart(DataTypeController::OK);
841 EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
844 TEST_F(SyncDataTypeManagerImplTest, PrioritizedConfiguration) {
845 AddController(BOOKMARKS);
846 AddController(PREFERENCES);
848 dtm_->set_priority_types(
849 AddHighPriorityTypesTo(syncer::ModelTypeSet(PREFERENCES)));
851 // Initial configure.
852 SetConfigureStartExpectation();
853 SetConfigureDoneExpectation(DataTypeManager::OK);
855 // Initially only PREFERENCES is configured.
856 configurer_.set_expected_configure_types(
857 AddHighPriorityTypesTo(ModelTypeSet(PREFERENCES)));
858 Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
859 EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
861 // BOOKMARKS is configured after download of PREFERENCES finishes.
862 configurer_.set_expected_configure_types(ModelTypeSet(BOOKMARKS));
863 FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
864 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
866 FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
867 GetController(PREFERENCES)->FinishStart(DataTypeController::OK);
868 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
870 GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
871 EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
874 TEST_F(SyncDataTypeManagerImplTest, PrioritizedConfigurationReconfigure) {
875 AddController(BOOKMARKS);
876 AddController(PREFERENCES);
879 dtm_->set_priority_types(
880 AddHighPriorityTypesTo(syncer::ModelTypeSet(PREFERENCES)));
882 // Initial configure.
883 SetConfigureStartExpectation();
884 SetConfigureDoneExpectation(DataTypeManager::OK);
886 // Reconfigure while associating PREFERENCES and downloading BOOKMARKS.
887 configurer_.set_expected_configure_types(
888 AddHighPriorityTypesTo(ModelTypeSet(PREFERENCES)));
889 Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
890 EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
892 configurer_.set_expected_configure_types(ModelTypeSet(BOOKMARKS));
893 FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
894 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
896 // Enable syncing for APPS.
897 Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES, APPS));
898 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
900 // Reconfiguration starts after downloading and association of previous
902 configurer_.set_expected_configure_types(
903 AddHighPriorityTypesTo(ModelTypeSet(PREFERENCES)));
904 FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
905 GetController(PREFERENCES)->FinishStart(DataTypeController::OK);
906 EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
908 configurer_.set_expected_configure_types(ModelTypeSet(BOOKMARKS, APPS));
909 FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
910 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
912 FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS, APPS), ModelTypeSet());
913 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
915 // Skip calling FinishStart() for PREFENCES because it's already started in
916 // first configuration.
917 GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
918 GetController(APPS)->FinishStart(DataTypeController::OK);
919 EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
922 TEST_F(SyncDataTypeManagerImplTest, PrioritizedConfigurationStop) {
923 AddController(BOOKMARKS);
924 AddController(PREFERENCES);
926 dtm_->set_priority_types(
927 AddHighPriorityTypesTo(syncer::ModelTypeSet(PREFERENCES)));
929 // Initial configure.
930 SetConfigureStartExpectation();
931 SetConfigureDoneExpectation(DataTypeManager::ABORTED);
933 // Initially only PREFERENCES is configured.
934 configurer_.set_expected_configure_types(
935 AddHighPriorityTypesTo(ModelTypeSet(PREFERENCES)));
936 Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
937 EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
939 // BOOKMARKS is configured after download of PREFERENCES finishes.
940 configurer_.set_expected_configure_types(ModelTypeSet(BOOKMARKS));
941 FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
942 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
944 // PERFERENCES controller is associating while BOOKMARKS is downloading.
945 EXPECT_EQ(DataTypeController::ASSOCIATING,
946 GetController(PREFERENCES)->state());
947 EXPECT_EQ(DataTypeController::MODEL_LOADED,
948 GetController(BOOKMARKS)->state());
951 EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
952 EXPECT_EQ(DataTypeController::NOT_RUNNING,
953 GetController(PREFERENCES)->state());
954 EXPECT_EQ(DataTypeController::NOT_RUNNING, GetController(BOOKMARKS)->state());
957 TEST_F(SyncDataTypeManagerImplTest, PrioritizedConfigurationDownloadError) {
958 AddController(BOOKMARKS);
959 AddController(PREFERENCES);
961 dtm_->set_priority_types(
962 AddHighPriorityTypesTo(syncer::ModelTypeSet(PREFERENCES)));
964 // Initial configure.
965 SetConfigureStartExpectation();
966 SetConfigureDoneExpectation(DataTypeManager::UNRECOVERABLE_ERROR);
968 // Initially only PREFERENCES is configured.
969 configurer_.set_expected_configure_types(
970 AddHighPriorityTypesTo(ModelTypeSet(PREFERENCES)));
971 Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
972 EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
974 // BOOKMARKS is configured after download of PREFERENCES finishes.
975 configurer_.set_expected_configure_types(ModelTypeSet(BOOKMARKS));
976 FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
977 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
979 // PERFERENCES controller is associating while BOOKMARKS is downloading.
980 EXPECT_EQ(DataTypeController::ASSOCIATING,
981 GetController(PREFERENCES)->state());
982 EXPECT_EQ(DataTypeController::MODEL_LOADED,
983 GetController(BOOKMARKS)->state());
985 // Make BOOKMARKS download fail.
986 FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet(BOOKMARKS));
987 EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
988 EXPECT_EQ(DataTypeController::NOT_RUNNING,
989 GetController(PREFERENCES)->state());
990 EXPECT_EQ(DataTypeController::NOT_RUNNING, GetController(BOOKMARKS)->state());
993 TEST_F(SyncDataTypeManagerImplTest, HighPriorityAssociationFailure) {
994 AddController(PREFERENCES); // Will fail.
995 AddController(BOOKMARKS); // Will succeed.
997 dtm_->set_priority_types(
998 AddHighPriorityTypesTo(syncer::ModelTypeSet(PREFERENCES)));
1000 // Initial configure.
1001 SetConfigureStartExpectation();
1002 SetConfigureDoneExpectation(DataTypeManager::PARTIAL_SUCCESS);
1004 // Initially only PREFERENCES is configured.
1005 configurer_.set_expected_configure_types(
1006 AddHighPriorityTypesTo(ModelTypeSet(PREFERENCES)));
1007 Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
1008 EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
1010 // BOOKMARKS is configured after download of PREFERENCES finishes.
1011 configurer_.set_expected_configure_types(ModelTypeSet(BOOKMARKS));
1012 FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
1013 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
1015 // PERFERENCES controller is associating while BOOKMARKS is downloading.
1016 EXPECT_EQ(DataTypeController::ASSOCIATING,
1017 GetController(PREFERENCES)->state());
1018 EXPECT_EQ(DataTypeController::MODEL_LOADED,
1019 GetController(BOOKMARKS)->state());
1021 // Make PREFERENCES association fail.
1022 GetController(PREFERENCES)->FinishStart(
1023 DataTypeController::ASSOCIATION_FAILED);
1024 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
1026 // Reconfigure without PREFERENCES after the BOOKMARKS download completes,
1027 // then reconfigure with BOOKMARKS.
1028 configurer_.set_expected_configure_types(syncer::ControlTypes());
1029 FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
1030 configurer_.set_expected_configure_types(ModelTypeSet(BOOKMARKS));
1031 FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
1033 // Reconfigure with BOOKMARKS.
1034 FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
1035 EXPECT_EQ(DataTypeController::ASSOCIATING,
1036 GetController(BOOKMARKS)->state());
1037 GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
1039 EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
1040 EXPECT_EQ(DataTypeController::NOT_RUNNING,
1041 GetController(PREFERENCES)->state());
1042 EXPECT_EQ(DataTypeController::RUNNING, GetController(BOOKMARKS)->state());
1045 TEST_F(SyncDataTypeManagerImplTest, LowPriorityAssociationFailure) {
1046 AddController(PREFERENCES); // Will succeed.
1047 AddController(BOOKMARKS); // Will fail.
1049 dtm_->set_priority_types(
1050 AddHighPriorityTypesTo(syncer::ModelTypeSet(PREFERENCES)));
1052 // Initial configure.
1053 SetConfigureStartExpectation();
1054 SetConfigureDoneExpectation(DataTypeManager::PARTIAL_SUCCESS);
1056 // Initially only PREFERENCES is configured.
1057 configurer_.set_expected_configure_types(
1058 AddHighPriorityTypesTo(ModelTypeSet(PREFERENCES)));
1059 Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
1060 EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
1062 // BOOKMARKS is configured after download of PREFERENCES finishes.
1063 configurer_.set_expected_configure_types(ModelTypeSet(BOOKMARKS));
1064 FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
1065 EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
1067 // PERFERENCES controller is associating while BOOKMARKS is downloading.
1068 EXPECT_EQ(DataTypeController::ASSOCIATING,
1069 GetController(PREFERENCES)->state());
1070 EXPECT_EQ(DataTypeController::MODEL_LOADED,
1071 GetController(BOOKMARKS)->state());
1073 // BOOKMARKS finishes downloading and PREFERENCES finishes associating.
1074 FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
1075 GetController(PREFERENCES)->FinishStart(DataTypeController::OK);
1076 EXPECT_EQ(DataTypeController::RUNNING, GetController(PREFERENCES)->state());
1078 // Make BOOKMARKS association fail, which triggers reconfigure with only
1080 configurer_.set_expected_configure_types(
1081 AddHighPriorityTypesTo(ModelTypeSet(PREFERENCES)));
1082 GetController(BOOKMARKS)->FinishStart(DataTypeController::ASSOCIATION_FAILED);
1083 EXPECT_EQ(DataTypeController::NOT_RUNNING,
1084 GetController(BOOKMARKS)->state());
1085 EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
1087 // Finish configuration with only PREFERENCES.
1088 configurer_.set_expected_configure_types(ModelTypeSet());
1089 FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
1090 EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
1091 EXPECT_EQ(DataTypeController::RUNNING, GetController(PREFERENCES)->state());
1092 EXPECT_EQ(DataTypeController::NOT_RUNNING,
1093 GetController(BOOKMARKS)->state());
1096 TEST_F(SyncDataTypeManagerImplTest, FilterDesiredTypes) {
1097 AddController(BOOKMARKS);
1099 ModelTypeSet types(BOOKMARKS, APPS);
1100 dtm_->set_priority_types(AddHighPriorityTypesTo(types));
1102 SetConfigureStartExpectation();
1103 SetConfigureDoneExpectation(DataTypeManager::OK);
1105 syncer::ModelTypeSet expected_types = syncer::ControlTypes();
1106 expected_types.Put(BOOKMARKS);
1107 // APPS is filtered out because there's no controller for it.
1108 configurer_.set_expected_configure_types(expected_types);
1109 Configure(dtm_.get(), types);
1110 FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
1111 GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
1114 EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
1117 } // namespace browser_sync