Upstream version 11.39.250.0
[platform/framework/web/crosswalk.git] / src / components / sync_driver / data_type_manager_impl_unittest.cc
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 "components/sync_driver/data_type_manager_impl.h"
6
7 #include "base/compiler_specific.h"
8 #include "base/message_loop/message_loop.h"
9 #include "components/sync_driver/backend_data_type_configurer.h"
10 #include "components/sync_driver/data_type_controller.h"
11 #include "components/sync_driver/data_type_encryption_handler.h"
12 #include "components/sync_driver/data_type_manager_observer.h"
13 #include "components/sync_driver/data_type_status_table.h"
14 #include "components/sync_driver/fake_data_type_controller.h"
15 #include "sync/internal_api/public/base/model_type.h"
16 #include "sync/internal_api/public/configure_reason.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18
19 namespace sync_driver {
20
21 using syncer::SyncError;
22 using syncer::ModelType;
23 using syncer::ModelTypeSet;
24 using syncer::ModelTypeToString;
25 using syncer::BOOKMARKS;
26 using syncer::APPS;
27 using syncer::PASSWORDS;
28 using syncer::PREFERENCES;
29 using syncer::NIGORI;
30
31 namespace {
32
33 // Helper for unioning with priority types.
34 ModelTypeSet AddHighPriorityTypesTo(ModelTypeSet types) {
35   ModelTypeSet result = syncer::ControlTypes();
36   result.PutAll(types);
37   return result;
38 }
39
40 DataTypeStatusTable BuildStatusTable(ModelTypeSet crypto_errors,
41                                      ModelTypeSet association_errors,
42                                      ModelTypeSet unready_errors,
43                                      ModelTypeSet unrecoverable_errors) {
44   DataTypeStatusTable::TypeErrorMap error_map;
45   for (ModelTypeSet::Iterator iter = crypto_errors.First(); iter.Good();
46        iter.Inc()) {
47     error_map[iter.Get()] = SyncError(FROM_HERE,
48                                       SyncError::CRYPTO_ERROR,
49                                       "crypto error expected",
50                                       iter.Get());
51   }
52   for (ModelTypeSet::Iterator iter = association_errors.First(); iter.Good();
53        iter.Inc()) {
54     error_map[iter.Get()] = SyncError(FROM_HERE,
55                                       SyncError::DATATYPE_ERROR,
56                                       "association error expected",
57                                       iter.Get());
58   }
59   for (ModelTypeSet::Iterator iter = unready_errors.First(); iter.Good();
60        iter.Inc()) {
61     error_map[iter.Get()] = SyncError(FROM_HERE,
62                                       SyncError::UNREADY_ERROR,
63                                       "unready error expected",
64                                       iter.Get());
65   }
66   for (ModelTypeSet::Iterator iter = unrecoverable_errors.First(); iter.Good();
67        iter.Inc()) {
68     error_map[iter.Get()] = SyncError(FROM_HERE,
69                                       SyncError::UNRECOVERABLE_ERROR,
70                                       "unrecoverable error expected",
71                                       iter.Get());
72   }
73   DataTypeStatusTable status_table;
74   status_table.UpdateFailedDataTypes(error_map);
75   return status_table;
76 }
77
78 // Fake BackendDataTypeConfigurer implementation that simply stores away the
79 // callback passed into ConfigureDataTypes.
80 class FakeBackendDataTypeConfigurer : public BackendDataTypeConfigurer {
81  public:
82   FakeBackendDataTypeConfigurer() {}
83   virtual ~FakeBackendDataTypeConfigurer() {}
84
85   virtual void ConfigureDataTypes(
86       syncer::ConfigureReason reason,
87       const DataTypeConfigStateMap& config_state_map,
88       const base::Callback<void(ModelTypeSet,
89                                 ModelTypeSet)>& ready_task,
90       const base::Callback<void()>& retry_callback) OVERRIDE {
91     last_ready_task_ = ready_task;
92
93     if (!expected_configure_types_.Empty()) {
94       EXPECT_TRUE(
95           expected_configure_types_.Equals(
96               GetDataTypesInState(CONFIGURE_ACTIVE, config_state_map)))
97           << ModelTypeSetToString(expected_configure_types_)
98           << " v.s. "
99           << ModelTypeSetToString(
100               GetDataTypesInState(CONFIGURE_ACTIVE, config_state_map));
101     }
102   }
103
104   virtual void ActivateDataType(
105       syncer::ModelType type, syncer::ModelSafeGroup group,
106       ChangeProcessor* change_processor) OVERRIDE {
107     activated_types_.Put(type);
108   }
109   virtual void DeactivateDataType(syncer::ModelType type) OVERRIDE {
110     activated_types_.Remove(type);
111   }
112
113   base::Callback<void(ModelTypeSet, ModelTypeSet)> last_ready_task() const {
114     return last_ready_task_;
115   }
116
117   void set_expected_configure_types(ModelTypeSet types) {
118     expected_configure_types_ = types;
119   }
120
121   const ModelTypeSet activated_types() { return activated_types_; }
122
123  private:
124   base::Callback<void(ModelTypeSet, ModelTypeSet)> last_ready_task_;
125   ModelTypeSet expected_configure_types_;
126   ModelTypeSet activated_types_;
127 };
128
129 // DataTypeManagerObserver implementation.
130 class FakeDataTypeManagerObserver : public DataTypeManagerObserver {
131  public:
132   FakeDataTypeManagerObserver() { ResetExpectations(); }
133   virtual ~FakeDataTypeManagerObserver() {
134     EXPECT_FALSE(start_expected_);
135     DataTypeManager::ConfigureResult default_result;
136     EXPECT_EQ(done_expectation_.status, default_result.status);
137     EXPECT_TRUE(
138         done_expectation_.data_type_status_table.GetFailedTypes().Empty());
139   }
140
141   void ExpectStart() {
142     start_expected_ = true;
143   }
144   void ExpectDone(const DataTypeManager::ConfigureResult& result) {
145     done_expectation_ = result;
146   }
147   void ResetExpectations() {
148     start_expected_ = false;
149     done_expectation_ = DataTypeManager::ConfigureResult();
150   }
151
152   virtual void OnConfigureDone(
153       const DataTypeManager::ConfigureResult& result) OVERRIDE {
154     EXPECT_EQ(done_expectation_.status, result.status);
155     DataTypeStatusTable::TypeErrorMap errors =
156         result.data_type_status_table.GetAllErrors();
157     DataTypeStatusTable::TypeErrorMap expected_errors =
158         done_expectation_.data_type_status_table.GetAllErrors();
159     ASSERT_EQ(expected_errors.size(), errors.size());
160     for (DataTypeStatusTable::TypeErrorMap::const_iterator iter =
161              expected_errors.begin();
162          iter != expected_errors.end();
163          ++iter) {
164       ASSERT_TRUE(errors.find(iter->first) != errors.end());
165       ASSERT_EQ(iter->second.error_type(),
166                 errors.find(iter->first)->second.error_type());
167     }
168     done_expectation_ = DataTypeManager::ConfigureResult();
169   }
170
171   virtual void OnConfigureRetry() OVERRIDE{
172     // Not verified.
173   }
174
175   virtual void OnConfigureStart() OVERRIDE {
176     EXPECT_TRUE(start_expected_);
177     start_expected_ = false;
178   }
179
180  private:
181   bool start_expected_ = true;
182   DataTypeManager::ConfigureResult done_expectation_;
183 };
184
185 class FakeDataTypeEncryptionHandler : public DataTypeEncryptionHandler {
186  public:
187   FakeDataTypeEncryptionHandler();
188   virtual ~FakeDataTypeEncryptionHandler();
189
190   virtual bool IsPassphraseRequired() const OVERRIDE;
191   virtual ModelTypeSet GetEncryptedDataTypes() const OVERRIDE;
192
193   void set_passphrase_required(bool passphrase_required) {
194     passphrase_required_ = passphrase_required;
195   }
196   void set_encrypted_types(ModelTypeSet encrypted_types) {
197     encrypted_types_ = encrypted_types;
198   }
199  private:
200   bool passphrase_required_;
201   ModelTypeSet encrypted_types_;
202 };
203
204 FakeDataTypeEncryptionHandler::FakeDataTypeEncryptionHandler()
205     : passphrase_required_(false) {}
206 FakeDataTypeEncryptionHandler::~FakeDataTypeEncryptionHandler() {}
207
208 bool FakeDataTypeEncryptionHandler::IsPassphraseRequired() const {
209   return passphrase_required_;
210 }
211
212 ModelTypeSet
213 FakeDataTypeEncryptionHandler::GetEncryptedDataTypes() const {
214   return encrypted_types_;
215 }
216
217 } // namespace
218
219 class TestDataTypeManager : public DataTypeManagerImpl {
220  public:
221   TestDataTypeManager(
222       const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
223           debug_info_listener,
224       BackendDataTypeConfigurer* configurer,
225       const DataTypeController::TypeMap* controllers,
226       const DataTypeEncryptionHandler* encryption_handler,
227       DataTypeManagerObserver* observer)
228       : DataTypeManagerImpl(base::Closure(),
229                             debug_info_listener,
230                             controllers,
231                             encryption_handler,
232                             configurer,
233                             observer),
234         custom_priority_types_(syncer::ControlTypes()) {}
235
236   void set_priority_types(const ModelTypeSet& priority_types) {
237     custom_priority_types_ = priority_types;
238   }
239
240   DataTypeManager::ConfigureResult configure_result() const {
241     return configure_result_;
242   }
243
244   virtual void OnModelAssociationDone(
245       const DataTypeManager::ConfigureResult& result) OVERRIDE {
246     configure_result_ = result;
247     DataTypeManagerImpl::OnModelAssociationDone(result);
248   }
249
250  private:
251   virtual ModelTypeSet GetPriorityTypes() const OVERRIDE {
252     return custom_priority_types_;
253   }
254
255   ModelTypeSet custom_priority_types_;
256   DataTypeManager::ConfigureResult configure_result_;
257 };
258
259 // The actual test harness class, parametrized on nigori state (i.e., tests are
260 // run both configuring with nigori, and configuring without).
261 class SyncDataTypeManagerImplTest : public testing::Test {
262  public:
263   SyncDataTypeManagerImplTest() {}
264
265   virtual ~SyncDataTypeManagerImplTest() {
266   }
267
268  protected:
269   virtual void SetUp() {
270    dtm_.reset(
271        new TestDataTypeManager(
272            syncer::WeakHandle<syncer::DataTypeDebugInfoListener>(),
273            &configurer_,
274            &controllers_,
275            &encryption_handler_,
276            &observer_));
277   }
278
279   void SetConfigureStartExpectation() {
280     observer_.ExpectStart();
281   }
282
283   void SetConfigureDoneExpectation(DataTypeManager::ConfigureStatus status,
284                                    const DataTypeStatusTable& status_table) {
285     DataTypeManager::ConfigureResult result;
286     result.status = status;
287     result.data_type_status_table = status_table;
288     observer_.ExpectDone(result);
289   }
290
291   // Configure the given DTM with the given desired types.
292   void Configure(DataTypeManagerImpl* dtm,
293                  const ModelTypeSet& desired_types) {
294     dtm->Configure(desired_types, syncer::CONFIGURE_REASON_RECONFIGURATION);
295   }
296
297   // Finish downloading for the given DTM. Should be done only after
298   // a call to Configure().
299   void FinishDownload(const DataTypeManager& dtm,
300                       ModelTypeSet types_to_configure,
301                       ModelTypeSet failed_download_types) {
302     EXPECT_TRUE(DataTypeManager::DOWNLOAD_PENDING == dtm.state() ||
303                 DataTypeManager::CONFIGURING == dtm.state());
304     ASSERT_FALSE(configurer_.last_ready_task().is_null());
305     configurer_.last_ready_task().Run(
306         syncer::Difference(types_to_configure, failed_download_types),
307         failed_download_types);
308   }
309
310   // Adds a fake controller for the given type to |controllers_|.
311   // Should be called only before setting up the DTM.
312   void AddController(ModelType model_type) {
313     controllers_[model_type] = new FakeDataTypeController(model_type);
314   }
315
316   // Gets the fake controller for the given type, which should have
317   // been previously added via AddController().
318   scoped_refptr<FakeDataTypeController> GetController(
319       ModelType model_type) const {
320     DataTypeController::TypeMap::const_iterator it =
321         controllers_.find(model_type);
322     if (it == controllers_.end()) {
323       return NULL;
324     }
325     return make_scoped_refptr(
326         static_cast<FakeDataTypeController*>(it->second.get()));
327   }
328
329   void FailEncryptionFor(ModelTypeSet encrypted_types) {
330     encryption_handler_.set_passphrase_required(true);
331     encryption_handler_.set_encrypted_types(encrypted_types);
332   }
333
334   base::MessageLoopForUI ui_loop_;
335   DataTypeController::TypeMap controllers_;
336   FakeBackendDataTypeConfigurer configurer_;
337   FakeDataTypeManagerObserver observer_;
338   scoped_ptr<TestDataTypeManager> dtm_;
339   FakeDataTypeEncryptionHandler encryption_handler_;
340 };
341
342 // Set up a DTM with no controllers, configure it, finish downloading,
343 // and then stop it.
344 TEST_F(SyncDataTypeManagerImplTest, NoControllers) {
345   SetConfigureStartExpectation();
346   SetConfigureDoneExpectation(DataTypeManager::OK, DataTypeStatusTable());
347
348   Configure(dtm_.get(), ModelTypeSet());
349   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
350
351   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
352   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
353
354   dtm_->Stop();
355   EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
356 }
357
358 // Set up a DTM with a single controller, configure it, finish
359 // downloading, finish starting the controller, and then stop the DTM.
360 TEST_F(SyncDataTypeManagerImplTest, ConfigureOne) {
361   AddController(BOOKMARKS);
362
363   SetConfigureStartExpectation();
364   SetConfigureDoneExpectation(DataTypeManager::OK, DataTypeStatusTable());
365
366   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
367   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
368
369   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
370   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
371   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
372
373   GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
374   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
375   EXPECT_EQ(1U, configurer_.activated_types().Size());
376
377   dtm_->Stop();
378   EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
379   EXPECT_TRUE(configurer_.activated_types().Empty());
380 }
381
382 // Set up a DTM with a single controller, configure it, but stop it
383 // before finishing the download.  It should still be safe to run the
384 // download callback even after the DTM is stopped and destroyed.
385 TEST_F(SyncDataTypeManagerImplTest, ConfigureOneStopWhileDownloadPending) {
386   AddController(BOOKMARKS);
387
388   {
389     SetConfigureStartExpectation();
390     SetConfigureDoneExpectation(DataTypeManager::ABORTED,
391                                 DataTypeStatusTable());
392
393     Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
394     EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
395
396     dtm_->Stop();
397     EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
398   }
399
400   configurer_.last_ready_task().Run(ModelTypeSet(BOOKMARKS), ModelTypeSet());
401   EXPECT_TRUE(configurer_.activated_types().Empty());
402 }
403
404 // Set up a DTM with a single controller, configure it, finish
405 // downloading, but stop the DTM before the controller finishes
406 // starting up.  It should still be safe to finish starting up the
407 // controller even after the DTM is stopped and destroyed.
408 TEST_F(SyncDataTypeManagerImplTest, ConfigureOneStopWhileStartingModel) {
409   AddController(BOOKMARKS);
410
411   {
412     SetConfigureStartExpectation();
413     SetConfigureDoneExpectation(DataTypeManager::ABORTED,
414                                 DataTypeStatusTable());
415
416     Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
417     EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
418
419     FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
420     FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
421     EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
422
423     dtm_->Stop();
424     EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
425     dtm_.reset();
426   }
427
428   GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
429   EXPECT_TRUE(configurer_.activated_types().Empty());
430 }
431
432 // Set up a DTM with a single controller, configure it, finish
433 // downloading, start the controller's model, but stop the DTM before
434 // the controller finishes starting up.  It should still be safe to
435 // finish starting up the controller even after the DTM is stopped and
436 // destroyed.
437 TEST_F(SyncDataTypeManagerImplTest, ConfigureOneStopWhileAssociating) {
438   AddController(BOOKMARKS);
439
440   {
441     SetConfigureStartExpectation();
442     SetConfigureDoneExpectation(DataTypeManager::ABORTED,
443                                 DataTypeStatusTable());
444
445     Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
446     EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
447
448     FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
449     FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
450     EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
451     EXPECT_TRUE(configurer_.activated_types().Empty());
452
453     dtm_->Stop();
454     EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
455     dtm_.reset();
456   }
457
458   GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
459   EXPECT_TRUE(configurer_.activated_types().Empty());
460 }
461
462 // Set up a DTM with a single controller.  Then:
463 //
464 //   1) Configure.
465 //   2) Finish the download for step 1.
466 //   3) Finish starting the controller with the NEEDS_CRYPTO status.
467 //   4) Complete download for the reconfiguration without the controller.
468 //   5) Stop the DTM.
469 TEST_F(SyncDataTypeManagerImplTest, OneWaitingForCrypto) {
470   AddController(PASSWORDS);
471
472   SetConfigureStartExpectation();
473   SetConfigureDoneExpectation(DataTypeManager::OK,
474                               BuildStatusTable(ModelTypeSet(PASSWORDS),
475                                                ModelTypeSet(),
476                                                ModelTypeSet(),
477                                                ModelTypeSet()));
478
479   const ModelTypeSet types(PASSWORDS);
480   dtm_->set_priority_types(AddHighPriorityTypesTo(types));
481
482   // Step 1.
483   Configure(dtm_.get(), types);
484   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
485
486   // Step 2.
487   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
488   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
489
490   // Step 3.
491   FailEncryptionFor(types);
492   GetController(PASSWORDS)->FinishStart(DataTypeController::NEEDS_CRYPTO);
493   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
494
495   // Step 4.
496   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
497   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
498
499   // Step 5.
500   dtm_->Stop();
501   EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
502 }
503
504 // Set up a DTM with two controllers.  Then:
505 //
506 //   1) Configure with first controller.
507 //   2) Finish the download for step 1.
508 //   3) Finish starting the first controller.
509 //   4) Configure with both controllers.
510 //   5) Finish the download for step 4.
511 //   6) Finish starting the second controller.
512 //   7) Stop the DTM.
513 TEST_F(SyncDataTypeManagerImplTest, ConfigureOneThenBoth) {
514   AddController(BOOKMARKS);
515   AddController(PREFERENCES);
516
517   SetConfigureStartExpectation();
518   SetConfigureDoneExpectation(DataTypeManager::OK, DataTypeStatusTable());
519
520   // Step 1.
521   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
522   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
523
524   // Step 2.
525   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
526   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
527   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
528
529   // Step 3.
530   GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
531   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
532
533   observer_.ResetExpectations();
534   SetConfigureStartExpectation();
535   SetConfigureDoneExpectation(DataTypeManager::OK, DataTypeStatusTable());
536
537   // Step 4.
538   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
539   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
540
541   // Step 5.
542   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
543   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS, PREFERENCES), ModelTypeSet());
544   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
545
546   // Step 6.
547   GetController(PREFERENCES)->FinishStart(DataTypeController::OK);
548   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
549   EXPECT_EQ(2U, configurer_.activated_types().Size());
550
551   // Step 7.
552   dtm_->Stop();
553   EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
554   EXPECT_TRUE(configurer_.activated_types().Empty());
555 }
556
557 // Set up a DTM with two controllers.  Then:
558 //
559 //   1) Configure with first controller.
560 //   2) Finish the download for step 1.
561 //   3) Finish starting the first controller.
562 //   4) Configure with second controller.
563 //   5) Finish the download for step 4.
564 //   6) Finish starting the second controller.
565 //   7) Stop the DTM.
566 TEST_F(SyncDataTypeManagerImplTest, ConfigureOneThenSwitch) {
567   AddController(BOOKMARKS);
568   AddController(PREFERENCES);
569
570   SetConfigureStartExpectation();
571   SetConfigureDoneExpectation(DataTypeManager::OK, DataTypeStatusTable());
572
573   // Step 1.
574   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
575   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
576
577   // Step 2.
578   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
579   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
580   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
581
582   // Step 3.
583   GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
584   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
585
586   observer_.ResetExpectations();
587   SetConfigureStartExpectation();
588   SetConfigureDoneExpectation(DataTypeManager::OK, DataTypeStatusTable());
589
590   // Step 4.
591   Configure(dtm_.get(), ModelTypeSet(PREFERENCES));
592   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
593
594   // Step 5.
595   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
596   FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
597   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
598
599   // Step 6.
600   GetController(PREFERENCES)->FinishStart(DataTypeController::OK);
601   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
602   EXPECT_EQ(1U, configurer_.activated_types().Size());
603
604   // Step 7.
605   dtm_->Stop();
606   EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
607   EXPECT_TRUE(configurer_.activated_types().Empty());
608 }
609
610 // Set up a DTM with two controllers.  Then:
611 //
612 //   1) Configure with first controller.
613 //   2) Finish the download for step 1.
614 //   3) Configure with both controllers.
615 //   4) Finish starting the first controller.
616 //   5) Finish the download for step 3.
617 //   6) Finish starting the second controller.
618 //   7) Stop the DTM.
619 TEST_F(SyncDataTypeManagerImplTest, ConfigureWhileOneInFlight) {
620   AddController(BOOKMARKS);
621   AddController(PREFERENCES);
622
623   SetConfigureStartExpectation();
624   SetConfigureDoneExpectation(DataTypeManager::OK, DataTypeStatusTable());
625
626   // Step 1.
627   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
628   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
629
630   // Step 2.
631   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
632   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
633   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
634
635   // Step 3.
636   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
637   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
638
639   // Step 4.
640   GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
641   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
642
643   // Step 5.
644   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
645   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS, PREFERENCES), ModelTypeSet());
646   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
647
648   // Step 6.
649   GetController(PREFERENCES)->FinishStart(DataTypeController::OK);
650   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
651   EXPECT_EQ(2U, configurer_.activated_types().Size());
652
653   // Step 7.
654   dtm_->Stop();
655   EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
656   EXPECT_TRUE(configurer_.activated_types().Empty());
657 }
658
659 // Set up a DTM with one controller.  Then configure, finish
660 // downloading, and start the controller with an unrecoverable error.
661 // The unrecoverable error should cause the DTM to stop.
662 TEST_F(SyncDataTypeManagerImplTest, OneFailingController) {
663   AddController(BOOKMARKS);
664
665   SetConfigureStartExpectation();
666   SetConfigureDoneExpectation(DataTypeManager::UNRECOVERABLE_ERROR,
667                               BuildStatusTable(ModelTypeSet(),
668                                                ModelTypeSet(),
669                                                ModelTypeSet(),
670                                                ModelTypeSet(BOOKMARKS)));
671
672   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
673   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
674
675   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
676   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
677   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
678   EXPECT_TRUE(configurer_.activated_types().Empty());
679
680   GetController(BOOKMARKS)->FinishStart(
681       DataTypeController::UNRECOVERABLE_ERROR);
682   EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
683   EXPECT_TRUE(configurer_.activated_types().Empty());
684 }
685
686 // Set up a DTM with two controllers.  Then:
687 //
688 //   1) Configure with both controllers.
689 //   2) Finish the download for step 1.
690 //   3) Finish starting the first controller successfully.
691 //   4) Finish starting the second controller with an unrecoverable error.
692 //
693 // The failure from step 4 should cause the DTM to stop.
694 TEST_F(SyncDataTypeManagerImplTest, SecondControllerFails) {
695   AddController(BOOKMARKS);
696   AddController(PREFERENCES);
697
698   SetConfigureStartExpectation();
699   SetConfigureDoneExpectation(DataTypeManager::UNRECOVERABLE_ERROR,
700                               BuildStatusTable(ModelTypeSet(),
701                                                ModelTypeSet(),
702                                                ModelTypeSet(),
703                                                ModelTypeSet(PREFERENCES)));
704
705   // Step 1.
706   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
707   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
708
709   // Step 2.
710   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
711   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS, PREFERENCES), ModelTypeSet());
712   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
713
714   // Step 3.
715   GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
716   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
717
718   // Step 4.
719   GetController(PREFERENCES)->FinishStart(
720       DataTypeController::UNRECOVERABLE_ERROR);
721   EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
722 }
723
724 // Set up a DTM with two controllers.  Then:
725 //
726 //   1) Configure with both controllers.
727 //   2) Finish the download for step 1.
728 //   3) Finish starting the first controller successfully.
729 //   4) Finish starting the second controller with an association failure.
730 //   5) Finish the purge/reconfigure without the failed type.
731 //   6) Stop the DTM.
732 //
733 // The association failure from step 3 should be ignored.
734 //
735 // TODO(akalin): Check that the data type that failed association is
736 // recorded in the CONFIGURE_DONE notification.
737 TEST_F(SyncDataTypeManagerImplTest, OneControllerFailsAssociation) {
738   AddController(BOOKMARKS);
739   AddController(PREFERENCES);
740
741   SetConfigureStartExpectation();
742   SetConfigureDoneExpectation(DataTypeManager::OK,
743                               BuildStatusTable(ModelTypeSet(),
744                                                ModelTypeSet(PREFERENCES),
745                                                ModelTypeSet(),
746                                                ModelTypeSet()));
747
748   // Step 1.
749   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
750   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
751
752   // Step 2.
753   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
754   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS, PREFERENCES), ModelTypeSet());
755   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
756
757   // Step 3.
758   GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
759   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
760
761   // Step 4.
762   GetController(PREFERENCES)->FinishStart(
763       DataTypeController::ASSOCIATION_FAILED);
764   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
765
766   // Step 5.
767   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
768   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
769   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
770   EXPECT_EQ(1U, configurer_.activated_types().Size());
771
772   // Step 6.
773   dtm_->Stop();
774   EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
775   EXPECT_TRUE(configurer_.activated_types().Empty());
776 }
777
778 // Set up a DTM with two controllers.  Then:
779 //
780 //   1) Configure with first controller.
781 //   2) Configure with both controllers.
782 //   3) Finish the download for step 1.
783 //   4) Finish the download for step 2.
784 //   5) Finish starting both controllers.
785 //   6) Stop the DTM.
786 TEST_F(SyncDataTypeManagerImplTest, ConfigureWhileDownloadPending) {
787   AddController(BOOKMARKS);
788   AddController(PREFERENCES);
789
790   SetConfigureStartExpectation();
791   SetConfigureDoneExpectation(DataTypeManager::OK, DataTypeStatusTable());
792
793   // Step 1.
794   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
795   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
796
797   // Step 2.
798   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
799   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
800
801   // Step 3.
802   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
803   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
804
805   // Step 4.
806   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
807   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS, PREFERENCES), ModelTypeSet());
808   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
809
810   // Step 5.
811   GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
812   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
813   GetController(PREFERENCES)->FinishStart(DataTypeController::OK);
814   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
815
816   // Step 6.
817   dtm_->Stop();
818   EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
819 }
820
821 // Set up a DTM with two controllers.  Then:
822 //
823 //   1) Configure with first controller.
824 //   2) Configure with both controllers.
825 //   3) Finish the download for step 1 with a failed data type.
826 //   4) Finish the download for step 2 successfully.
827 //   5) Finish starting both controllers.
828 //   6) Stop the DTM.
829 //
830 // The failure from step 3 should be ignored since there's a
831 // reconfigure pending from step 2.
832 TEST_F(SyncDataTypeManagerImplTest, ConfigureWhileDownloadPendingWithFailure) {
833   AddController(BOOKMARKS);
834   AddController(PREFERENCES);
835
836   SetConfigureStartExpectation();
837   SetConfigureDoneExpectation(DataTypeManager::OK, DataTypeStatusTable());
838
839   // Step 1.
840   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
841   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
842   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
843
844   // Step 2.
845   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
846   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
847
848   // Step 3.
849   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
850   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
851   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
852
853   // Step 4.
854   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS, PREFERENCES), ModelTypeSet());
855   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
856
857   // Step 5.
858   GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
859   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
860   GetController(PREFERENCES)->FinishStart(DataTypeController::OK);
861   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
862
863   // Step 6.
864   dtm_->Stop();
865   EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
866 }
867
868 // Tests a Purge then Configure.  This is similar to the sequence of
869 // operations that would be invoked by the BackendMigrator.
870 TEST_F(SyncDataTypeManagerImplTest, MigrateAll) {
871   AddController(BOOKMARKS);
872   dtm_->set_priority_types(AddHighPriorityTypesTo(ModelTypeSet(BOOKMARKS)));
873
874   SetConfigureStartExpectation();
875   SetConfigureDoneExpectation(DataTypeManager::OK, DataTypeStatusTable());
876
877   // Initial setup.
878   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
879   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
880   GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
881
882   // We've now configured bookmarks and (implicitly) the control types.
883   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
884   observer_.ResetExpectations();
885
886   // Pretend we were told to migrate all types.
887   ModelTypeSet to_migrate;
888   to_migrate.Put(BOOKMARKS);
889   to_migrate.PutAll(syncer::ControlTypes());
890
891   SetConfigureStartExpectation();
892   SetConfigureDoneExpectation(DataTypeManager::OK, DataTypeStatusTable());
893   dtm_->PurgeForMigration(to_migrate,
894                           syncer::CONFIGURE_REASON_MIGRATION);
895   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
896
897   // The DTM will call ConfigureDataTypes(), even though it is unnecessary.
898   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
899   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
900   observer_.ResetExpectations();
901
902   // Re-enable the migrated types.
903   SetConfigureStartExpectation();
904   SetConfigureDoneExpectation(DataTypeManager::OK, DataTypeStatusTable());
905   Configure(dtm_.get(), to_migrate);
906   FinishDownload(*dtm_, to_migrate, ModelTypeSet());
907   GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
908   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
909 }
910
911 // Test receipt of a Configure request while a purge is in flight.
912 TEST_F(SyncDataTypeManagerImplTest, ConfigureDuringPurge) {
913   AddController(BOOKMARKS);
914   AddController(PREFERENCES);
915
916   // Initial configure.
917   SetConfigureStartExpectation();
918   SetConfigureDoneExpectation(DataTypeManager::OK, DataTypeStatusTable());
919   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
920   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
921   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
922   GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
923   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
924   observer_.ResetExpectations();
925
926   // Purge the Nigori type.
927   SetConfigureStartExpectation();
928   dtm_->PurgeForMigration(ModelTypeSet(NIGORI),
929                           syncer::CONFIGURE_REASON_MIGRATION);
930   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
931   observer_.ResetExpectations();
932
933   // Before the backend configuration completes, ask for a different
934   // set of types.  This request asks for
935   // - BOOKMARKS: which is redundant because it was already enabled,
936   // - PREFERENCES: which is new and will need to be downloaded, and
937   // - NIGORI: (added implicitly because it is a control type) which
938   //   the DTM is part-way through purging.
939   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
940   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
941
942   // Invoke the callback we've been waiting for since we asked to purge NIGORI.
943   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
944   observer_.ResetExpectations();
945
946   SetConfigureDoneExpectation(DataTypeManager::OK, DataTypeStatusTable());
947   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
948
949   // Now invoke the callback for the second configure request.
950   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
951   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS, PREFERENCES), ModelTypeSet());
952   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
953
954   // Start the preferences controller.  We don't need to start controller for
955   // the NIGORI because it has none.  We don't need to start the controller for
956   // the BOOKMARKS because it was never stopped.
957   GetController(PREFERENCES)->FinishStart(DataTypeController::OK);
958   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
959 }
960
961 TEST_F(SyncDataTypeManagerImplTest, PrioritizedConfiguration) {
962   AddController(BOOKMARKS);
963   AddController(PREFERENCES);
964
965   dtm_->set_priority_types(
966       AddHighPriorityTypesTo(ModelTypeSet(PREFERENCES)));
967
968   // Initial configure.
969   SetConfigureStartExpectation();
970   SetConfigureDoneExpectation(DataTypeManager::OK, DataTypeStatusTable());
971
972   // Initially only PREFERENCES is configured.
973   configurer_.set_expected_configure_types(
974       AddHighPriorityTypesTo(ModelTypeSet(PREFERENCES)));
975   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
976   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
977
978   // BOOKMARKS is configured after download of PREFERENCES finishes.
979   configurer_.set_expected_configure_types(ModelTypeSet(BOOKMARKS));
980   FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
981   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
982
983   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
984   GetController(PREFERENCES)->FinishStart(DataTypeController::OK);
985   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
986
987   GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
988   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
989 }
990
991 TEST_F(SyncDataTypeManagerImplTest, PrioritizedConfigurationReconfigure) {
992   AddController(BOOKMARKS);
993   AddController(PREFERENCES);
994   AddController(APPS);
995
996   dtm_->set_priority_types(
997       AddHighPriorityTypesTo(ModelTypeSet(PREFERENCES)));
998
999   // Initial configure.
1000   SetConfigureStartExpectation();
1001   SetConfigureDoneExpectation(DataTypeManager::OK, DataTypeStatusTable());
1002
1003   // Reconfigure while associating PREFERENCES and downloading BOOKMARKS.
1004   configurer_.set_expected_configure_types(
1005       AddHighPriorityTypesTo(ModelTypeSet(PREFERENCES)));
1006   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
1007   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
1008
1009   configurer_.set_expected_configure_types(ModelTypeSet(BOOKMARKS));
1010   FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
1011   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
1012
1013   // Enable syncing for APPS.
1014   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES, APPS));
1015   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
1016
1017   // Reconfiguration starts after downloading and association of previous
1018   // types finish.
1019   configurer_.set_expected_configure_types(
1020       AddHighPriorityTypesTo(ModelTypeSet(PREFERENCES)));
1021   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
1022   GetController(PREFERENCES)->FinishStart(DataTypeController::OK);
1023   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
1024
1025   configurer_.set_expected_configure_types(ModelTypeSet(BOOKMARKS, APPS));
1026   FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
1027   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
1028
1029   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS, APPS), ModelTypeSet());
1030   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
1031
1032   // Skip calling FinishStart() for PREFENCES because it's already started in
1033   // first configuration.
1034   GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
1035   GetController(APPS)->FinishStart(DataTypeController::OK);
1036   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
1037 }
1038
1039 TEST_F(SyncDataTypeManagerImplTest, PrioritizedConfigurationStop) {
1040   AddController(BOOKMARKS);
1041   AddController(PREFERENCES);
1042
1043   dtm_->set_priority_types(
1044       AddHighPriorityTypesTo(ModelTypeSet(PREFERENCES)));
1045
1046   // Initial configure.
1047   SetConfigureStartExpectation();
1048   SetConfigureDoneExpectation(DataTypeManager::ABORTED, DataTypeStatusTable());
1049
1050   // Initially only PREFERENCES is configured.
1051   configurer_.set_expected_configure_types(
1052       AddHighPriorityTypesTo(ModelTypeSet(PREFERENCES)));
1053   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
1054   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
1055
1056   // BOOKMARKS is configured after download of PREFERENCES finishes.
1057   configurer_.set_expected_configure_types(ModelTypeSet(BOOKMARKS));
1058   FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
1059   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
1060
1061   // PREFERENCES controller is associating while BOOKMARKS is downloading.
1062   EXPECT_EQ(DataTypeController::ASSOCIATING,
1063             GetController(PREFERENCES)->state());
1064   EXPECT_EQ(DataTypeController::MODEL_LOADED,
1065             GetController(BOOKMARKS)->state());
1066
1067   dtm_->Stop();
1068   EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
1069   EXPECT_EQ(DataTypeController::NOT_RUNNING,
1070             GetController(PREFERENCES)->state());
1071   EXPECT_EQ(DataTypeController::NOT_RUNNING, GetController(BOOKMARKS)->state());
1072 }
1073
1074 TEST_F(SyncDataTypeManagerImplTest, PrioritizedConfigurationDownloadError) {
1075   AddController(BOOKMARKS);
1076   AddController(PREFERENCES);
1077
1078   dtm_->set_priority_types(
1079       AddHighPriorityTypesTo(ModelTypeSet(PREFERENCES)));
1080
1081   // Initial configure.
1082   SetConfigureStartExpectation();
1083   SetConfigureDoneExpectation(DataTypeManager::UNRECOVERABLE_ERROR,
1084                               BuildStatusTable(ModelTypeSet(),
1085                                                ModelTypeSet(),
1086                                                ModelTypeSet(),
1087                                                ModelTypeSet(BOOKMARKS)));
1088
1089   // Initially only PREFERENCES is configured.
1090   configurer_.set_expected_configure_types(
1091       AddHighPriorityTypesTo(ModelTypeSet(PREFERENCES)));
1092   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
1093   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
1094
1095   // BOOKMARKS is configured after download of PREFERENCES finishes.
1096   configurer_.set_expected_configure_types(ModelTypeSet(BOOKMARKS));
1097   FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
1098   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
1099
1100   // PREFERENCES controller is associating while BOOKMARKS is downloading.
1101   EXPECT_EQ(DataTypeController::ASSOCIATING,
1102             GetController(PREFERENCES)->state());
1103   EXPECT_EQ(DataTypeController::MODEL_LOADED,
1104             GetController(BOOKMARKS)->state());
1105
1106   // Make BOOKMARKS download fail.
1107   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet(BOOKMARKS));
1108   EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
1109   EXPECT_EQ(DataTypeController::NOT_RUNNING,
1110             GetController(PREFERENCES)->state());
1111   EXPECT_EQ(DataTypeController::NOT_RUNNING, GetController(BOOKMARKS)->state());
1112 }
1113
1114 TEST_F(SyncDataTypeManagerImplTest, HighPriorityAssociationFailure) {
1115   AddController(PREFERENCES);   // Will fail.
1116   AddController(BOOKMARKS);     // Will succeed.
1117
1118   dtm_->set_priority_types(
1119       AddHighPriorityTypesTo(ModelTypeSet(PREFERENCES)));
1120
1121   // Initial configure.
1122   SetConfigureStartExpectation();
1123   SetConfigureDoneExpectation(DataTypeManager::OK,
1124                               BuildStatusTable(ModelTypeSet(),
1125                                                ModelTypeSet(PREFERENCES),
1126                                                ModelTypeSet(),
1127                                                ModelTypeSet()));
1128
1129   // Initially only PREFERENCES is configured.
1130   configurer_.set_expected_configure_types(
1131       AddHighPriorityTypesTo(ModelTypeSet(PREFERENCES)));
1132   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
1133   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
1134
1135   // BOOKMARKS is configured after download of PREFERENCES finishes.
1136   configurer_.set_expected_configure_types(ModelTypeSet(BOOKMARKS));
1137   FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
1138   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
1139
1140   // PREFERENCES controller is associating while BOOKMARKS is downloading.
1141   EXPECT_EQ(DataTypeController::ASSOCIATING,
1142             GetController(PREFERENCES)->state());
1143   EXPECT_EQ(DataTypeController::MODEL_LOADED,
1144             GetController(BOOKMARKS)->state());
1145
1146   // Make PREFERENCES association fail.
1147   GetController(PREFERENCES)->FinishStart(
1148       DataTypeController::ASSOCIATION_FAILED);
1149   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
1150
1151   // Reconfigure without PREFERENCES after the BOOKMARKS download completes,
1152   // then reconfigure with BOOKMARKS.
1153   configurer_.set_expected_configure_types(syncer::ControlTypes());
1154   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
1155   configurer_.set_expected_configure_types(ModelTypeSet(BOOKMARKS));
1156   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
1157
1158   // Reconfigure with BOOKMARKS.
1159   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
1160   EXPECT_EQ(DataTypeController::ASSOCIATING,
1161             GetController(BOOKMARKS)->state());
1162   GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
1163
1164   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
1165   EXPECT_EQ(DataTypeController::NOT_RUNNING,
1166             GetController(PREFERENCES)->state());
1167   EXPECT_EQ(DataTypeController::RUNNING, GetController(BOOKMARKS)->state());
1168 }
1169
1170 TEST_F(SyncDataTypeManagerImplTest, LowPriorityAssociationFailure) {
1171   AddController(PREFERENCES);  // Will succeed.
1172   AddController(BOOKMARKS);    // Will fail.
1173
1174   dtm_->set_priority_types(
1175       AddHighPriorityTypesTo(ModelTypeSet(PREFERENCES)));
1176
1177   // Initial configure.
1178   SetConfigureStartExpectation();
1179   SetConfigureDoneExpectation(DataTypeManager::OK,
1180                               BuildStatusTable(ModelTypeSet(),
1181                                                ModelTypeSet(BOOKMARKS),
1182                                                ModelTypeSet(),
1183                                                ModelTypeSet()));
1184
1185   // Initially only PREFERENCES is configured.
1186   configurer_.set_expected_configure_types(
1187       AddHighPriorityTypesTo(ModelTypeSet(PREFERENCES)));
1188   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
1189   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
1190
1191   // BOOKMARKS is configured after download of PREFERENCES finishes.
1192   configurer_.set_expected_configure_types(ModelTypeSet(BOOKMARKS));
1193   FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
1194   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
1195
1196   // PREFERENCES controller is associating while BOOKMARKS is downloading.
1197   EXPECT_EQ(DataTypeController::ASSOCIATING,
1198             GetController(PREFERENCES)->state());
1199   EXPECT_EQ(DataTypeController::MODEL_LOADED,
1200             GetController(BOOKMARKS)->state());
1201
1202   // BOOKMARKS finishes downloading and PREFERENCES finishes associating.
1203   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
1204   GetController(PREFERENCES)->FinishStart(DataTypeController::OK);
1205   EXPECT_EQ(DataTypeController::RUNNING, GetController(PREFERENCES)->state());
1206
1207   // Make BOOKMARKS association fail, which triggers reconfigure with only
1208   // PREFERENCES.
1209   configurer_.set_expected_configure_types(
1210       AddHighPriorityTypesTo(ModelTypeSet(PREFERENCES)));
1211   GetController(BOOKMARKS)->FinishStart(DataTypeController::ASSOCIATION_FAILED);
1212   EXPECT_EQ(DataTypeController::NOT_RUNNING,
1213             GetController(BOOKMARKS)->state());
1214   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
1215
1216   // Finish configuration with only PREFERENCES.
1217   configurer_.set_expected_configure_types(ModelTypeSet());
1218   FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
1219   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
1220   EXPECT_EQ(DataTypeController::RUNNING, GetController(PREFERENCES)->state());
1221   EXPECT_EQ(DataTypeController::NOT_RUNNING,
1222             GetController(BOOKMARKS)->state());
1223 }
1224
1225 TEST_F(SyncDataTypeManagerImplTest, FilterDesiredTypes) {
1226   AddController(BOOKMARKS);
1227
1228   ModelTypeSet types(BOOKMARKS, APPS);
1229   dtm_->set_priority_types(AddHighPriorityTypesTo(types));
1230
1231   SetConfigureStartExpectation();
1232   SetConfigureDoneExpectation(DataTypeManager::OK, DataTypeStatusTable());
1233
1234   ModelTypeSet expected_types = syncer::ControlTypes();
1235   expected_types.Put(BOOKMARKS);
1236   // APPS is filtered out because there's no controller for it.
1237   configurer_.set_expected_configure_types(expected_types);
1238   Configure(dtm_.get(), types);
1239   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
1240   GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
1241
1242   dtm_->Stop();
1243   EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
1244 }
1245
1246 TEST_F(SyncDataTypeManagerImplTest, ConfigureForBackupRollback) {
1247   AddController(BOOKMARKS);
1248
1249   SetConfigureStartExpectation();
1250
1251   ModelTypeSet expected_types = syncer::ControlTypes();
1252   expected_types.Put(BOOKMARKS);
1253   configurer_.set_expected_configure_types(expected_types);
1254   dtm_->set_priority_types(expected_types);
1255
1256   dtm_->Configure(ModelTypeSet(BOOKMARKS),
1257                   syncer::CONFIGURE_REASON_BACKUP_ROLLBACK);
1258 }
1259
1260 TEST_F(SyncDataTypeManagerImplTest, ReenableAfterDataTypeError) {
1261   AddController(PREFERENCES);  // Will succeed.
1262   AddController(BOOKMARKS);    // Will be disabled due to datatype error.
1263
1264   SetConfigureStartExpectation();
1265   SetConfigureDoneExpectation(DataTypeManager::OK,
1266                               BuildStatusTable(ModelTypeSet(),
1267                                                ModelTypeSet(BOOKMARKS),
1268                                                ModelTypeSet(),
1269                                                ModelTypeSet()));
1270
1271   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
1272   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
1273   FinishDownload(*dtm_, ModelTypeSet(PREFERENCES, BOOKMARKS), ModelTypeSet());
1274   GetController(PREFERENCES)->FinishStart(DataTypeController::OK);
1275   GetController(BOOKMARKS)
1276       ->FinishStart(DataTypeController::ASSOCIATION_FAILED);
1277   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());  // Reconfig for error.
1278   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());  // Reconfig for error.
1279   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
1280   EXPECT_EQ(DataTypeController::RUNNING, GetController(PREFERENCES)->state());
1281   EXPECT_EQ(DataTypeController::NOT_RUNNING, GetController(BOOKMARKS)->state());
1282
1283   observer_.ResetExpectations();
1284
1285   // Re-enable bookmarks.
1286   SetConfigureDoneExpectation(DataTypeManager::OK, DataTypeStatusTable());
1287   dtm_->ReenableType(syncer::BOOKMARKS);
1288
1289   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
1290   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
1291   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
1292   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
1293   GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
1294   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
1295   EXPECT_EQ(DataTypeController::RUNNING, GetController(PREFERENCES)->state());
1296   EXPECT_EQ(DataTypeController::RUNNING, GetController(BOOKMARKS)->state());
1297
1298   // Should do nothing.
1299   dtm_->ReenableType(syncer::BOOKMARKS);
1300 }
1301
1302 TEST_F(SyncDataTypeManagerImplTest, UnreadyType) {
1303   AddController(BOOKMARKS);
1304   GetController(BOOKMARKS)->SetReadyForStart(false);
1305
1306   // Bookmarks is never started due to being unready.
1307   SetConfigureStartExpectation();
1308   SetConfigureDoneExpectation(DataTypeManager::OK,
1309                               BuildStatusTable(ModelTypeSet(),
1310                                                ModelTypeSet(),
1311                                                ModelTypeSet(BOOKMARKS),
1312                                                ModelTypeSet()));
1313   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
1314   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
1315   EXPECT_EQ(DataTypeController::NOT_RUNNING, GetController(BOOKMARKS)->state());
1316   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
1317   EXPECT_EQ(0U, configurer_.activated_types().Size());
1318   observer_.ResetExpectations();
1319
1320   // Bookmarks should start normally now.
1321   GetController(BOOKMARKS)->SetReadyForStart(true);
1322   SetConfigureDoneExpectation(DataTypeManager::OK, DataTypeStatusTable());
1323   dtm_->ReenableType(BOOKMARKS);
1324   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
1325
1326   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
1327   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
1328   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
1329
1330   GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
1331   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
1332   EXPECT_EQ(1U, configurer_.activated_types().Size());
1333
1334   // Should do nothing.
1335   observer_.ResetExpectations();
1336   dtm_->ReenableType(BOOKMARKS);
1337
1338   dtm_->Stop();
1339   EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
1340   EXPECT_TRUE(configurer_.activated_types().Empty());
1341 }
1342
1343 TEST_F(SyncDataTypeManagerImplTest, ModelLoadError) {
1344   AddController(BOOKMARKS);
1345   GetController(BOOKMARKS)->SetModelLoadError(syncer::SyncError(
1346         FROM_HERE, SyncError::DATATYPE_ERROR, "load error", BOOKMARKS));
1347
1348   // Bookmarks is never started due to hitting a model load error.
1349   SetConfigureStartExpectation();
1350   SetConfigureDoneExpectation(DataTypeManager::OK,
1351                               BuildStatusTable(ModelTypeSet(),
1352                                                ModelTypeSet(BOOKMARKS),
1353                                                ModelTypeSet(),
1354                                                ModelTypeSet()));
1355   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
1356   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
1357   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
1358   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
1359   EXPECT_EQ(DataTypeController::NOT_RUNNING, GetController(BOOKMARKS)->state());
1360
1361   EXPECT_EQ(0U, configurer_.activated_types().Size());
1362 }
1363
1364
1365 TEST_F(SyncDataTypeManagerImplTest, ErrorBeforeAssociation) {
1366   AddController(BOOKMARKS);
1367
1368   // Bookmarks is never started due to hitting a datatype error while the DTM
1369   // is still downloading types.
1370   SetConfigureStartExpectation();
1371   SetConfigureDoneExpectation(DataTypeManager::OK,
1372                               BuildStatusTable(ModelTypeSet(),
1373                                                ModelTypeSet(BOOKMARKS),
1374                                                ModelTypeSet(),
1375                                                ModelTypeSet()));
1376   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
1377   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
1378   GetController(BOOKMARKS)->OnSingleDataTypeUnrecoverableError(
1379       syncer::SyncError(FROM_HERE,
1380                         SyncError::DATATYPE_ERROR,
1381                         "bookmarks error",
1382                         BOOKMARKS));
1383   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
1384   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());  // Reconfig for error.
1385   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
1386   EXPECT_EQ(DataTypeController::NOT_RUNNING, GetController(BOOKMARKS)->state());
1387
1388   EXPECT_EQ(0U, configurer_.activated_types().Size());
1389 }
1390
1391 TEST_F(SyncDataTypeManagerImplTest, AssociationNeverCompletes) {
1392   AddController(BOOKMARKS);
1393
1394   // Bookmarks times out during association and so it's never started.
1395   SetConfigureStartExpectation();
1396   SetConfigureDoneExpectation(DataTypeManager::OK,
1397                               BuildStatusTable(ModelTypeSet(),
1398                                                ModelTypeSet(BOOKMARKS),
1399                                                ModelTypeSet(),
1400                                                ModelTypeSet()));
1401   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
1402
1403   GetController(BOOKMARKS)->SetDelayModelLoad();
1404   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
1405   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
1406
1407   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
1408
1409   // Simulate timeout by firing the timer.
1410   dtm_->GetModelAssociationManagerForTesting()
1411       ->GetTimerForTesting()
1412       ->user_task()
1413       .Run();
1414   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
1415   EXPECT_EQ(DataTypeController::NOT_RUNNING, GetController(BOOKMARKS)->state());
1416
1417   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
1418
1419   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
1420   EXPECT_EQ(0U, configurer_.activated_types().Size());
1421 }
1422
1423 }  // namespace sync_driver