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/ui_data_type_controller.h" 6 7 #include "base/bind.h" 8 #include "base/memory/scoped_ptr.h" 9 #include "base/message_loop/message_loop.h" 10 #include "base/tracked_objects.h" 11 #include "chrome/browser/sync/glue/data_type_controller_mock.h" 12 #include "chrome/browser/sync/glue/fake_generic_change_processor.h" 13 #include "chrome/browser/sync/profile_sync_components_factory_mock.h" 14 #include "chrome/browser/sync/profile_sync_service_mock.h" 15 #include "chrome/test/base/profile_mock.h" 16 #include "content/public/test/test_browser_thread.h" 17 #include "sync/api/fake_syncable_service.h" 18 #include "testing/gtest/include/gtest/gtest.h" 19 20 using content::BrowserThread; 21 using testing::_; 22 using testing::InvokeWithoutArgs; 23 using testing::Return; 24 25 namespace browser_sync { 26 namespace { 27 28 ACTION(MakeSharedChangeProcessor) { 29 return new SharedChangeProcessor(); 30 } 31 32 ACTION_P(ReturnAndRelease, change_processor) { 33 return change_processor->release(); 34 } 35 36 // TODO(zea): Expand this to make the dtc type paramterizable. This will let us 37 // test the basic functionality of all UIDataTypeControllers. We'll need to have 38 // intelligent default values for the methods queried in the dependent services 39 // (e.g. those queried in StartModels). 40 class SyncUIDataTypeControllerTest : public testing::Test { 41 public: 42 SyncUIDataTypeControllerTest() 43 : ui_thread_(BrowserThread::UI, &message_loop_), 44 type_(syncer::PREFERENCES), 45 change_processor_(new FakeGenericChangeProcessor()) {} 46 47 virtual void SetUp() { 48 profile_sync_factory_.reset(new ProfileSyncComponentsFactoryMock()); 49 preference_dtc_ = 50 new UIDataTypeController(type_, 51 profile_sync_factory_.get(), 52 &profile_, 53 &profile_sync_service_); 54 SetStartExpectations(); 55 } 56 57 virtual void TearDown() { 58 // Must be done before we pump the loop. 59 syncable_service_.StopSyncing(type_); 60 preference_dtc_ = NULL; 61 PumpLoop(); 62 } 63 64 protected: 65 void SetStartExpectations() { 66 // Ownership gets passed to caller of CreateGenericChangeProcessor. 67 change_processor_.reset(new FakeGenericChangeProcessor()); 68 EXPECT_CALL(model_load_callback_, Run(_, _)); 69 EXPECT_CALL(*profile_sync_factory_, GetSyncableServiceForType(type_)). 70 WillOnce(Return(syncable_service_.AsWeakPtr())); 71 EXPECT_CALL(*profile_sync_factory_, CreateSharedChangeProcessor()). 72 WillOnce(MakeSharedChangeProcessor()); 73 EXPECT_CALL(*profile_sync_factory_, 74 CreateGenericChangeProcessor(_, _, _, _)). 75 WillOnce(ReturnAndRelease(&change_processor_)); 76 } 77 78 void SetActivateExpectations() { 79 EXPECT_CALL(profile_sync_service_, ActivateDataType(type_, _, _)); 80 } 81 82 void SetStopExpectations() { 83 EXPECT_CALL(profile_sync_service_, DeactivateDataType(type_)); 84 } 85 86 void Start() { 87 preference_dtc_->LoadModels( 88 base::Bind(&ModelLoadCallbackMock::Run, 89 base::Unretained(&model_load_callback_))); 90 preference_dtc_->StartAssociating( 91 base::Bind(&StartCallbackMock::Run, 92 base::Unretained(&start_callback_))); 93 } 94 95 void PumpLoop() { 96 message_loop_.RunUntilIdle(); 97 } 98 99 base::MessageLoopForUI message_loop_; 100 content::TestBrowserThread ui_thread_; 101 ProfileMock profile_; 102 scoped_ptr<ProfileSyncComponentsFactoryMock> profile_sync_factory_; 103 ProfileSyncServiceMock profile_sync_service_; 104 const syncer::ModelType type_; 105 StartCallbackMock start_callback_; 106 ModelLoadCallbackMock model_load_callback_; 107 scoped_refptr<UIDataTypeController> preference_dtc_; 108 scoped_ptr<FakeGenericChangeProcessor> change_processor_; 109 syncer::FakeSyncableService syncable_service_; 110 }; 111 112 // Start the DTC. Verify that the callback is called with OK, the 113 // service has been told to start syncing and that the DTC is now in RUNNING 114 // state. 115 TEST_F(SyncUIDataTypeControllerTest, Start) { 116 SetActivateExpectations(); 117 EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _, _)); 118 119 EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state()); 120 EXPECT_FALSE(syncable_service_.syncing()); 121 Start(); 122 EXPECT_EQ(DataTypeController::RUNNING, preference_dtc_->state()); 123 EXPECT_TRUE(syncable_service_.syncing()); 124 } 125 126 // Start and then stop the DTC. Verify that the service started and stopped 127 // syncing, and that the DTC went from RUNNING to NOT_RUNNING. 128 TEST_F(SyncUIDataTypeControllerTest, StartStop) { 129 SetActivateExpectations(); 130 SetStopExpectations(); 131 EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _, _)); 132 133 EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state()); 134 EXPECT_FALSE(syncable_service_.syncing()); 135 Start(); 136 EXPECT_EQ(DataTypeController::RUNNING, preference_dtc_->state()); 137 EXPECT_TRUE(syncable_service_.syncing()); 138 preference_dtc_->Stop(); 139 EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state()); 140 EXPECT_FALSE(syncable_service_.syncing()); 141 } 142 143 // Start the DTC when no user nodes are created. Verify that the callback 144 // is called with OK_FIRST_RUN. Stop the DTC. 145 TEST_F(SyncUIDataTypeControllerTest, StartStopFirstRun) { 146 SetActivateExpectations(); 147 SetStopExpectations(); 148 EXPECT_CALL(start_callback_, Run(DataTypeController::OK_FIRST_RUN, _, _)); 149 change_processor_->set_sync_model_has_user_created_nodes(false); 150 151 EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state()); 152 EXPECT_FALSE(syncable_service_.syncing()); 153 Start(); 154 EXPECT_EQ(DataTypeController::RUNNING, preference_dtc_->state()); 155 EXPECT_TRUE(syncable_service_.syncing()); 156 preference_dtc_->Stop(); 157 EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state()); 158 EXPECT_FALSE(syncable_service_.syncing()); 159 } 160 161 // Start the DTC, but have the service fail association. Verify the callback 162 // is called with ASSOCIATION_FAILED, the DTC goes to state DISABLED, and the 163 // service is not syncing. Then stop the DTC. 164 TEST_F(SyncUIDataTypeControllerTest, StartAssociationFailed) { 165 SetStopExpectations(); 166 EXPECT_CALL(start_callback_, 167 Run(DataTypeController::ASSOCIATION_FAILED, _, _)); 168 syncable_service_.set_merge_data_and_start_syncing_error( 169 syncer::SyncError(FROM_HERE, 170 syncer::SyncError::DATATYPE_ERROR, 171 "Error", 172 type_)); 173 174 EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state()); 175 EXPECT_FALSE(syncable_service_.syncing()); 176 Start(); 177 EXPECT_EQ(DataTypeController::DISABLED, preference_dtc_->state()); 178 EXPECT_FALSE(syncable_service_.syncing()); 179 preference_dtc_->Stop(); 180 EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state()); 181 EXPECT_FALSE(syncable_service_.syncing()); 182 } 183 184 // Start the DTC but fail to check if there are user created nodes. Verify the 185 // DTC calls the callback with UNRECOVERABLE_ERROR and that it goes into 186 // NOT_RUNNING state. Verify the syncable service is not syncing. 187 TEST_F(SyncUIDataTypeControllerTest, 188 StartAssociationTriggersUnrecoverableError) { 189 EXPECT_CALL(start_callback_, 190 Run(DataTypeController::UNRECOVERABLE_ERROR, _, _)); 191 change_processor_->set_sync_model_has_user_created_nodes_success(false); 192 193 EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state()); 194 EXPECT_FALSE(syncable_service_.syncing()); 195 Start(); 196 EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state()); 197 EXPECT_FALSE(syncable_service_.syncing()); 198 } 199 200 // Start the DTC, but then trigger an unrecoverable error. Verify the syncer 201 // gets stopped and the DTC is in NOT_RUNNING state. 202 TEST_F(SyncUIDataTypeControllerTest, OnSingleDatatypeUnrecoverableError) { 203 SetActivateExpectations(); 204 EXPECT_CALL(profile_sync_service_, DisableBrokenDatatype(_,_,_)). 205 WillOnce(InvokeWithoutArgs(preference_dtc_.get(), 206 &UIDataTypeController::Stop)); 207 SetStopExpectations(); 208 EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _, _)); 209 210 EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state()); 211 EXPECT_FALSE(syncable_service_.syncing()); 212 Start(); 213 EXPECT_TRUE(syncable_service_.syncing()); 214 preference_dtc_->OnSingleDatatypeUnrecoverableError(FROM_HERE, "Test"); 215 PumpLoop(); 216 EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state()); 217 EXPECT_FALSE(syncable_service_.syncing()); 218 } 219 220 } // namespace 221 } // namespace browser_sync 222