Home | History | Annotate | Download | only in glue
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/sync/glue/non_ui_data_type_controller.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/bind_helpers.h"
      9 #include "base/callback.h"
     10 #include "base/compiler_specific.h"
     11 #include "base/memory/scoped_ptr.h"
     12 #include "base/message_loop/message_loop.h"
     13 #include "base/synchronization/waitable_event.h"
     14 #include "base/test/test_timeouts.h"
     15 #include "base/tracked_objects.h"
     16 #include "chrome/browser/sync/glue/data_type_controller_mock.h"
     17 #include "chrome/browser/sync/glue/non_ui_data_type_controller_mock.h"
     18 #include "chrome/browser/sync/glue/shared_change_processor_mock.h"
     19 #include "chrome/browser/sync/profile_sync_components_factory_mock.h"
     20 #include "chrome/browser/sync/profile_sync_service_mock.h"
     21 #include "chrome/test/base/profile_mock.h"
     22 #include "content/public/test/test_browser_thread.h"
     23 #include "sync/api/fake_syncable_service.h"
     24 #include "sync/internal_api/public/engine/model_safe_worker.h"
     25 #include "testing/gtest/include/gtest/gtest.h"
     26 
     27 namespace browser_sync {
     28 
     29 namespace {
     30 
     31 using base::WaitableEvent;
     32 using content::BrowserThread;
     33 using syncer::AUTOFILL_PROFILE;
     34 using testing::_;
     35 using testing::AtLeast;
     36 using testing::DoAll;
     37 using testing::InvokeWithoutArgs;
     38 using testing::Mock;
     39 using testing::Return;
     40 using testing::SetArgumentPointee;
     41 using testing::StrictMock;
     42 
     43 ACTION_P(WaitOnEvent, event) {
     44   event->Wait();
     45 }
     46 
     47 ACTION_P(SignalEvent, event) {
     48   event->Signal();
     49 }
     50 
     51 ACTION_P(SaveChangeProcessor, scoped_change_processor) {
     52   scoped_change_processor->reset(arg2);
     53 }
     54 
     55 ACTION_P(GetWeakPtrToSyncableService, syncable_service) {
     56   // Have to do this within an Action to ensure it's not evaluated on the wrong
     57   // thread.
     58   return syncable_service->AsWeakPtr();
     59 }
     60 
     61 class NonUIDataTypeControllerFake
     62     : public NonUIDataTypeController {
     63  public:
     64   NonUIDataTypeControllerFake(
     65       ProfileSyncComponentsFactory* profile_sync_factory,
     66       Profile* profile,
     67       ProfileSyncService* sync_service,
     68       NonUIDataTypeControllerMock* mock)
     69       : NonUIDataTypeController(profile_sync_factory,
     70                                          profile,
     71                                          sync_service),
     72         blocked_(false),
     73         mock_(mock) {}
     74 
     75   virtual syncer::ModelType type() const OVERRIDE {
     76     return AUTOFILL_PROFILE;
     77   }
     78   virtual syncer::ModelSafeGroup model_safe_group() const OVERRIDE {
     79     return syncer::GROUP_DB;
     80   }
     81 
     82   // Prevent tasks from being posted on the backend thread until
     83   // UnblockBackendTasks() is called.
     84   void BlockBackendTasks() {
     85     blocked_ = true;
     86   }
     87 
     88   // Post pending tasks on the backend thread and start allowing tasks
     89   // to be posted on the backend thread again.
     90   void UnblockBackendTasks() {
     91     blocked_ = false;
     92     for (std::vector<PendingTask>::const_iterator it = pending_tasks_.begin();
     93          it != pending_tasks_.end(); ++it) {
     94       PostTaskOnBackendThread(it->from_here, it->task);
     95     }
     96     pending_tasks_.clear();
     97   }
     98 
     99  protected:
    100   virtual bool PostTaskOnBackendThread(
    101       const tracked_objects::Location& from_here,
    102       const base::Closure& task) OVERRIDE {
    103     if (blocked_) {
    104       pending_tasks_.push_back(PendingTask(from_here, task));
    105       return true;
    106     } else {
    107       return BrowserThread::PostTask(BrowserThread::DB, from_here, task);
    108     }
    109   }
    110 
    111   // We mock the following methods because their default implementations do
    112   // nothing, but we still want to make sure they're called appropriately.
    113   virtual bool StartModels() OVERRIDE {
    114     return mock_->StartModels();
    115   }
    116   virtual void StopModels() OVERRIDE {
    117     mock_->StopModels();
    118   }
    119   virtual void RecordUnrecoverableError(
    120       const tracked_objects::Location& from_here,
    121       const std::string& message) OVERRIDE {
    122     mock_->RecordUnrecoverableError(from_here, message);
    123   }
    124   virtual void RecordAssociationTime(base::TimeDelta time) OVERRIDE {
    125     mock_->RecordAssociationTime(time);
    126   }
    127   virtual void RecordStartFailure(DataTypeController::StartResult result)
    128       OVERRIDE {
    129     mock_->RecordStartFailure(result);
    130   }
    131 
    132  private:
    133   virtual ~NonUIDataTypeControllerFake() {}
    134 
    135   DISALLOW_COPY_AND_ASSIGN(NonUIDataTypeControllerFake);
    136 
    137   struct PendingTask {
    138     PendingTask(const tracked_objects::Location& from_here,
    139                 const base::Closure& task)
    140         : from_here(from_here), task(task) {}
    141 
    142     tracked_objects::Location from_here;
    143     base::Closure task;
    144   };
    145 
    146   bool blocked_;
    147   std::vector<PendingTask> pending_tasks_;
    148   NonUIDataTypeControllerMock* mock_;
    149 };
    150 
    151 class SyncNonUIDataTypeControllerTest : public testing::Test {
    152  public:
    153   SyncNonUIDataTypeControllerTest()
    154       : ui_thread_(BrowserThread::UI, &message_loop_),
    155         db_thread_(BrowserThread::DB) {}
    156 
    157   virtual void SetUp() OVERRIDE {
    158     EXPECT_CALL(service_, GetUserShare()).WillRepeatedly(
    159         Return((syncer::UserShare*)NULL));
    160     db_thread_.Start();
    161     profile_sync_factory_.reset(
    162         new StrictMock<ProfileSyncComponentsFactoryMock>());
    163     change_processor_ = new SharedChangeProcessorMock();
    164 
    165     // All of these are refcounted, so don't need to be released.
    166     dtc_mock_ = new StrictMock<NonUIDataTypeControllerMock>();
    167     non_ui_dtc_ =
    168         new NonUIDataTypeControllerFake(profile_sync_factory_.get(),
    169                                         &profile_,
    170                                         &service_,
    171                                         dtc_mock_.get());
    172   }
    173 
    174   virtual void TearDown() OVERRIDE {
    175     db_thread_.Stop();
    176   }
    177 
    178   void WaitForDTC() {
    179     WaitableEvent done(true, false);
    180     BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
    181        base::Bind(&SyncNonUIDataTypeControllerTest::SignalDone,
    182                   &done));
    183     done.TimedWait(TestTimeouts::action_timeout());
    184     if (!done.IsSignaled()) {
    185       ADD_FAILURE() << "Timed out waiting for DB thread to finish.";
    186     }
    187     base::MessageLoop::current()->RunUntilIdle();
    188   }
    189 
    190  protected:
    191   void SetStartExpectations() {
    192     EXPECT_CALL(*dtc_mock_.get(), StartModels()).WillOnce(Return(true));
    193     EXPECT_CALL(model_load_callback_, Run(_, _));
    194     EXPECT_CALL(*profile_sync_factory_,
    195                 CreateSharedChangeProcessor()).
    196         WillOnce(Return(change_processor_.get()));
    197   }
    198 
    199   void SetAssociateExpectations() {
    200     EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _))
    201         .WillOnce(GetWeakPtrToSyncableService(&syncable_service_));
    202     EXPECT_CALL(*change_processor_.get(), CryptoReadyIfNecessary())
    203         .WillOnce(Return(true));
    204     EXPECT_CALL(*change_processor_.get(), ActivateDataType(_));
    205     EXPECT_CALL(*change_processor_.get(), SyncModelHasUserCreatedNodes(_))
    206         .WillOnce(DoAll(SetArgumentPointee<0>(true), Return(true)));
    207     EXPECT_CALL(*change_processor_.get(), GetSyncData(_))
    208         .WillOnce(Return(syncer::SyncError()));
    209     EXPECT_CALL(*change_processor_.get(), GetSyncCount()).WillOnce(Return(0));
    210     EXPECT_CALL(*dtc_mock_.get(), RecordAssociationTime(_));
    211   }
    212 
    213   void SetActivateExpectations(DataTypeController::StartResult result) {
    214     EXPECT_CALL(start_callback_, Run(result,_,_));
    215   }
    216 
    217   void SetStopExpectations() {
    218     EXPECT_CALL(*dtc_mock_.get(), StopModels());
    219     EXPECT_CALL(*change_processor_.get(), Disconnect()).WillOnce(Return(true));
    220     EXPECT_CALL(service_, DeactivateDataType(_));
    221   }
    222 
    223   void SetStartFailExpectations(DataTypeController::StartResult result) {
    224     EXPECT_CALL(*dtc_mock_.get(), StopModels()).Times(AtLeast(1));
    225     if (DataTypeController::IsUnrecoverableResult(result))
    226       EXPECT_CALL(*dtc_mock_.get(), RecordUnrecoverableError(_, _));
    227     EXPECT_CALL(*dtc_mock_.get(), RecordStartFailure(result));
    228     EXPECT_CALL(start_callback_, Run(result, _, _));
    229   }
    230 
    231   void Start() {
    232     non_ui_dtc_->LoadModels(
    233         base::Bind(&ModelLoadCallbackMock::Run,
    234                    base::Unretained(&model_load_callback_)));
    235     non_ui_dtc_->StartAssociating(
    236         base::Bind(&StartCallbackMock::Run,
    237                    base::Unretained(&start_callback_)));
    238   }
    239 
    240   static void SignalDone(WaitableEvent* done) {
    241     done->Signal();
    242   }
    243 
    244   base::MessageLoopForUI message_loop_;
    245   content::TestBrowserThread ui_thread_;
    246   content::TestBrowserThread db_thread_;
    247   ProfileMock profile_;
    248   scoped_ptr<ProfileSyncComponentsFactoryMock> profile_sync_factory_;
    249   StrictMock<ProfileSyncServiceMock> service_;
    250   StartCallbackMock start_callback_;
    251   ModelLoadCallbackMock model_load_callback_;
    252   // Must be destroyed after non_ui_dtc_.
    253   syncer::FakeSyncableService syncable_service_;
    254   scoped_refptr<NonUIDataTypeControllerFake> non_ui_dtc_;
    255   scoped_refptr<NonUIDataTypeControllerMock> dtc_mock_;
    256   scoped_refptr<SharedChangeProcessorMock> change_processor_;
    257   scoped_ptr<syncer::SyncChangeProcessor> saved_change_processor_;
    258 };
    259 
    260 TEST_F(SyncNonUIDataTypeControllerTest, StartOk) {
    261   SetStartExpectations();
    262   SetAssociateExpectations();
    263   SetActivateExpectations(DataTypeController::OK);
    264   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
    265   Start();
    266   WaitForDTC();
    267   EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state());
    268 }
    269 
    270 TEST_F(SyncNonUIDataTypeControllerTest, StartFirstRun) {
    271   SetStartExpectations();
    272   EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _))
    273       .WillOnce(GetWeakPtrToSyncableService(&syncable_service_));
    274   EXPECT_CALL(*change_processor_.get(), CryptoReadyIfNecessary())
    275       .WillOnce(Return(true));
    276   EXPECT_CALL(*change_processor_.get(), SyncModelHasUserCreatedNodes(_))
    277       .WillOnce(DoAll(SetArgumentPointee<0>(false), Return(true)));
    278   EXPECT_CALL(*change_processor_.get(), GetSyncData(_))
    279       .WillOnce(Return(syncer::SyncError()));
    280   EXPECT_CALL(*dtc_mock_.get(), RecordAssociationTime(_));
    281   SetActivateExpectations(DataTypeController::OK_FIRST_RUN);
    282   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
    283   Start();
    284   WaitForDTC();
    285   EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state());
    286 }
    287 
    288 // Start the DTC and have StartModels() return false.  Then, stop the
    289 // DTC without finishing model startup.  It should stop cleanly.
    290 TEST_F(SyncNonUIDataTypeControllerTest, AbortDuringStartModels) {
    291   EXPECT_CALL(*profile_sync_factory_,
    292               CreateSharedChangeProcessor()).
    293       WillOnce(Return(change_processor_.get()));
    294   EXPECT_CALL(*dtc_mock_.get(), StartModels()).WillOnce(Return(false));
    295   EXPECT_CALL(*dtc_mock_.get(), StopModels());
    296   EXPECT_CALL(model_load_callback_, Run(_, _));
    297   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
    298   non_ui_dtc_->LoadModels(
    299       base::Bind(&ModelLoadCallbackMock::Run,
    300                  base::Unretained(&model_load_callback_)));
    301   WaitForDTC();
    302   EXPECT_EQ(DataTypeController::MODEL_STARTING, non_ui_dtc_->state());
    303   non_ui_dtc_->Stop();
    304   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
    305 }
    306 
    307 // Start the DTC and have MergeDataAndStartSyncing() return an error.
    308 // The DTC should become disabled, and the DTC should still stop
    309 // cleanly.
    310 TEST_F(SyncNonUIDataTypeControllerTest, StartAssociationFailed) {
    311   SetStartExpectations();
    312   EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _))
    313       .WillOnce(GetWeakPtrToSyncableService(&syncable_service_));
    314   EXPECT_CALL(*change_processor_.get(), CryptoReadyIfNecessary())
    315       .WillOnce(Return(true));
    316   EXPECT_CALL(*change_processor_.get(), SyncModelHasUserCreatedNodes(_))
    317       .WillOnce(DoAll(SetArgumentPointee<0>(true), Return(true)));
    318   EXPECT_CALL(*change_processor_.get(), GetSyncData(_))
    319       .WillOnce(Return(syncer::SyncError()));
    320   EXPECT_CALL(*dtc_mock_.get(), RecordAssociationTime(_));
    321   SetStartFailExpectations(DataTypeController::ASSOCIATION_FAILED);
    322   // Set up association to fail with an association failed error.
    323   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
    324   syncable_service_.set_merge_data_and_start_syncing_error(
    325       syncer::SyncError(FROM_HERE,
    326                         syncer::SyncError::DATATYPE_ERROR,
    327                         "Sync Error",
    328                         non_ui_dtc_->type()));
    329   Start();
    330   WaitForDTC();
    331   EXPECT_EQ(DataTypeController::DISABLED, non_ui_dtc_->state());
    332   non_ui_dtc_->Stop();
    333   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
    334 }
    335 
    336 TEST_F(SyncNonUIDataTypeControllerTest,
    337        StartAssociationTriggersUnrecoverableError) {
    338   SetStartExpectations();
    339   SetStartFailExpectations(DataTypeController::UNRECOVERABLE_ERROR);
    340   // Set up association to fail with an unrecoverable error.
    341   EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _))
    342       .WillOnce(GetWeakPtrToSyncableService(&syncable_service_));
    343   EXPECT_CALL(*change_processor_.get(), CryptoReadyIfNecessary())
    344       .WillRepeatedly(Return(true));
    345   EXPECT_CALL(*change_processor_.get(), SyncModelHasUserCreatedNodes(_))
    346       .WillRepeatedly(DoAll(SetArgumentPointee<0>(false), Return(false)));
    347   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
    348   Start();
    349   WaitForDTC();
    350   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
    351 }
    352 
    353 TEST_F(SyncNonUIDataTypeControllerTest,
    354        StartAssociationCryptoNotReady) {
    355   SetStartExpectations();
    356   SetStartFailExpectations(DataTypeController::NEEDS_CRYPTO);
    357   // Set up association to fail with a NEEDS_CRYPTO error.
    358   EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _))
    359       .WillOnce(GetWeakPtrToSyncableService(&syncable_service_));
    360   EXPECT_CALL(*change_processor_.get(), CryptoReadyIfNecessary())
    361       .WillRepeatedly(Return(false));
    362   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
    363   Start();
    364   WaitForDTC();
    365   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
    366 }
    367 
    368 // Trigger a Stop() call when we check if the model associator has user created
    369 // nodes.
    370 TEST_F(SyncNonUIDataTypeControllerTest, AbortDuringAssociation) {
    371   WaitableEvent wait_for_db_thread_pause(false, false);
    372   WaitableEvent pause_db_thread(false, false);
    373 
    374   SetStartExpectations();
    375   SetStartFailExpectations(DataTypeController::ABORTED);
    376   EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _))
    377       .WillOnce(GetWeakPtrToSyncableService(&syncable_service_));
    378   EXPECT_CALL(*change_processor_.get(), CryptoReadyIfNecessary())
    379       .WillOnce(Return(true));
    380   EXPECT_CALL(*change_processor_.get(), SyncModelHasUserCreatedNodes(_))
    381       .WillOnce(DoAll(SignalEvent(&wait_for_db_thread_pause),
    382                       WaitOnEvent(&pause_db_thread),
    383                       SetArgumentPointee<0>(true),
    384                       Return(true)));
    385   EXPECT_CALL(*change_processor_.get(), GetSyncData(_)).WillOnce(
    386       Return(syncer::SyncError(FROM_HERE,
    387                                syncer::SyncError::DATATYPE_ERROR,
    388                                "Disconnected.",
    389                                AUTOFILL_PROFILE)));
    390   EXPECT_CALL(*change_processor_.get(), Disconnect())
    391       .WillOnce(DoAll(SignalEvent(&pause_db_thread), Return(true)));
    392   EXPECT_CALL(service_, DeactivateDataType(_));
    393   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
    394   Start();
    395   wait_for_db_thread_pause.Wait();
    396   non_ui_dtc_->Stop();
    397   WaitForDTC();
    398   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
    399 }
    400 
    401 // Start the DTC while the backend tasks are blocked. Then stop the DTC before
    402 // the backend tasks get a chance to run. The DTC should have no interaction
    403 // with the profile sync factory or profile sync service once stopped.
    404 TEST_F(SyncNonUIDataTypeControllerTest, StartAfterSyncShutdown) {
    405   non_ui_dtc_->BlockBackendTasks();
    406 
    407   SetStartExpectations();
    408   // We don't expect StopSyncing to be called because local_service_ will never
    409   // have been set.
    410   EXPECT_CALL(*change_processor_.get(), Disconnect()).WillOnce(Return(true));
    411   EXPECT_CALL(*dtc_mock_.get(), StopModels());
    412   EXPECT_CALL(service_, DeactivateDataType(_));
    413   EXPECT_CALL(*dtc_mock_.get(),
    414               RecordStartFailure(DataTypeController::ABORTED));
    415   EXPECT_CALL(start_callback_, Run(DataTypeController::ABORTED, _, _));
    416   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
    417   Start();
    418   non_ui_dtc_->Stop();
    419   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
    420   Mock::VerifyAndClearExpectations(&profile_sync_factory_);
    421   Mock::VerifyAndClearExpectations(&service_);
    422   Mock::VerifyAndClearExpectations(change_processor_.get());
    423   Mock::VerifyAndClearExpectations(dtc_mock_.get());
    424 
    425   EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _))
    426       .WillOnce(Return(base::WeakPtr<syncer::SyncableService>()));
    427   non_ui_dtc_->UnblockBackendTasks();
    428   WaitForDTC();
    429 }
    430 
    431 TEST_F(SyncNonUIDataTypeControllerTest, Stop) {
    432   SetStartExpectations();
    433   SetAssociateExpectations();
    434   SetActivateExpectations(DataTypeController::OK);
    435   SetStopExpectations();
    436   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
    437   Start();
    438   WaitForDTC();
    439   EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state());
    440   non_ui_dtc_->Stop();
    441   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
    442 }
    443 
    444 // Start the DTC then block its backend tasks.  While its backend
    445 // tasks are blocked, stop and start it again, then unblock its
    446 // backend tasks.  The (delayed) running of the backend tasks from the
    447 // stop after the restart shouldn't cause any problems.
    448 TEST_F(SyncNonUIDataTypeControllerTest, StopStart) {
    449   SetStartExpectations();
    450   SetAssociateExpectations();
    451   SetActivateExpectations(DataTypeController::OK);
    452   SetStopExpectations();
    453   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
    454   Start();
    455   WaitForDTC();
    456   EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state());
    457 
    458   non_ui_dtc_->BlockBackendTasks();
    459   non_ui_dtc_->Stop();
    460   Mock::VerifyAndClearExpectations(&profile_sync_factory_);
    461   SetStartExpectations();
    462   SetAssociateExpectations();
    463   SetActivateExpectations(DataTypeController::OK);
    464   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
    465   Start();
    466   non_ui_dtc_->UnblockBackendTasks();
    467 
    468   WaitForDTC();
    469   EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state());
    470 }
    471 
    472 TEST_F(SyncNonUIDataTypeControllerTest,
    473        OnSingleDatatypeUnrecoverableError) {
    474   SetStartExpectations();
    475   SetAssociateExpectations();
    476   SetActivateExpectations(DataTypeController::OK);
    477   EXPECT_CALL(*dtc_mock_.get(), RecordUnrecoverableError(_, "Test"));
    478   EXPECT_CALL(service_, DisableBrokenDatatype(_, _, _)).WillOnce(
    479       InvokeWithoutArgs(non_ui_dtc_.get(), &NonUIDataTypeController::Stop));
    480   SetStopExpectations();
    481   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
    482   Start();
    483   WaitForDTC();
    484   EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state());
    485   // This should cause non_ui_dtc_->Stop() to be called.
    486   BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, base::Bind(
    487       &NonUIDataTypeControllerFake::
    488           OnSingleDatatypeUnrecoverableError,
    489       non_ui_dtc_.get(),
    490       FROM_HERE,
    491       std::string("Test")));
    492   WaitForDTC();
    493   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
    494 }
    495 
    496 }  // namespace
    497 
    498 }  // namespace browser_sync
    499