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 "base/bind.h" 6 #include "base/bind_helpers.h" 7 #include "base/callback.h" 8 #include "base/memory/scoped_ptr.h" 9 #include "base/run_loop.h" 10 #include "base/tracked_objects.h" 11 #include "chrome/browser/chrome_notification_types.h" 12 #include "chrome/browser/search_engines/template_url_service_factory.h" 13 #include "chrome/browser/search_engines/template_url_service_test_util.h" 14 #include "chrome/browser/sync/glue/data_type_controller_mock.h" 15 #include "chrome/browser/sync/glue/fake_generic_change_processor.h" 16 #include "chrome/browser/sync/glue/search_engine_data_type_controller.h" 17 #include "chrome/browser/sync/profile_sync_components_factory_mock.h" 18 #include "chrome/browser/sync/profile_sync_service_mock.h" 19 #include "chrome/test/base/profile_mock.h" 20 #include "content/public/browser/notification_service.h" 21 #include "sync/api/fake_syncable_service.h" 22 #include "testing/gtest/include/gtest/gtest.h" 23 24 using testing::_; 25 using testing::DoAll; 26 using testing::InvokeWithoutArgs; 27 using testing::Return; 28 using testing::SetArgumentPointee; 29 30 namespace browser_sync { 31 namespace { 32 33 ACTION(MakeSharedChangeProcessor) { 34 return new SharedChangeProcessor(); 35 } 36 37 ACTION_P(ReturnAndRelease, change_processor) { 38 return change_processor->release(); 39 } 40 41 class SyncSearchEngineDataTypeControllerTest : public testing::Test { 42 public: 43 SyncSearchEngineDataTypeControllerTest() 44 : change_processor_(new FakeGenericChangeProcessor()) {} 45 46 virtual void SetUp() { 47 test_util_.SetUp(); 48 profile_sync_factory_.reset(new ProfileSyncComponentsFactoryMock()); 49 // Feed the DTC test_util_'s profile so it is reused later. 50 // This allows us to control the associated TemplateURLService. 51 search_engine_dtc_ = 52 new SearchEngineDataTypeController(profile_sync_factory_.get(), 53 test_util_.profile(), 54 &service_); 55 } 56 57 virtual void TearDown() { 58 // Must be done before we pump the loop. 59 syncable_service_.StopSyncing(syncer::SEARCH_ENGINES); 60 search_engine_dtc_ = NULL; 61 test_util_.TearDown(); 62 } 63 64 protected: 65 // Pre-emptively get the TURL Service and make sure it is loaded. 66 void PreloadTemplateURLService() { 67 test_util_.VerifyLoad(); 68 } 69 70 void SetStartExpectations() { 71 // Ownership gets passed to caller of CreateGenericChangeProcessor. 72 EXPECT_CALL(model_load_callback_, Run(_, _)); 73 EXPECT_CALL(*profile_sync_factory_, 74 GetSyncableServiceForType(syncer::SEARCH_ENGINES)). 75 WillOnce(Return(syncable_service_.AsWeakPtr())); 76 EXPECT_CALL(*profile_sync_factory_, CreateSharedChangeProcessor()). 77 WillOnce(MakeSharedChangeProcessor()); 78 EXPECT_CALL(*profile_sync_factory_, 79 CreateGenericChangeProcessor(_, _, _, _)). 80 WillOnce(ReturnAndRelease(&change_processor_)); 81 } 82 83 void SetActivateExpectations() { 84 EXPECT_CALL(service_, ActivateDataType(syncer::SEARCH_ENGINES, _, _)); 85 } 86 87 void SetStopExpectations() { 88 EXPECT_CALL(service_, DeactivateDataType(syncer::SEARCH_ENGINES)); 89 } 90 91 void Start() { 92 search_engine_dtc_->LoadModels( 93 base::Bind(&ModelLoadCallbackMock::Run, 94 base::Unretained(&model_load_callback_))); 95 search_engine_dtc_->StartAssociating( 96 base::Bind(&StartCallbackMock::Run, 97 base::Unretained(&start_callback_))); 98 } 99 100 // This also manages a BrowserThread and MessageLoop for us. Note that this 101 // must be declared here as the destruction order of the BrowserThread 102 // matters - we could leak if this is declared below. 103 TemplateURLServiceTestUtil test_util_; 104 scoped_refptr<SearchEngineDataTypeController> search_engine_dtc_; 105 scoped_ptr<ProfileSyncComponentsFactoryMock> profile_sync_factory_; 106 ProfileSyncServiceMock service_; 107 scoped_ptr<FakeGenericChangeProcessor> change_processor_; 108 syncer::FakeSyncableService syncable_service_; 109 StartCallbackMock start_callback_; 110 ModelLoadCallbackMock model_load_callback_; 111 }; 112 113 TEST_F(SyncSearchEngineDataTypeControllerTest, StartURLServiceReady) { 114 SetStartExpectations(); 115 // We want to start ready. 116 PreloadTemplateURLService(); 117 SetActivateExpectations(); 118 EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _, _)); 119 120 EXPECT_EQ(DataTypeController::NOT_RUNNING, search_engine_dtc_->state()); 121 EXPECT_FALSE(syncable_service_.syncing()); 122 Start(); 123 EXPECT_EQ(DataTypeController::RUNNING, search_engine_dtc_->state()); 124 EXPECT_TRUE(syncable_service_.syncing()); 125 } 126 127 TEST_F(SyncSearchEngineDataTypeControllerTest, StartURLServiceNotReady) { 128 EXPECT_CALL(*profile_sync_factory_, CreateSharedChangeProcessor()). 129 WillOnce(MakeSharedChangeProcessor()); 130 131 EXPECT_CALL(model_load_callback_, Run(_, _)); 132 EXPECT_FALSE(syncable_service_.syncing()); 133 search_engine_dtc_->LoadModels( 134 base::Bind(&ModelLoadCallbackMock::Run, 135 base::Unretained(&model_load_callback_))); 136 EXPECT_EQ(DataTypeController::MODEL_STARTING, search_engine_dtc_->state()); 137 EXPECT_FALSE(syncable_service_.syncing()); 138 139 // Send the notification that the TemplateURLService has started. 140 content::NotificationService::current()->Notify( 141 chrome::NOTIFICATION_TEMPLATE_URL_SERVICE_LOADED, 142 content::Source<TemplateURLService>(test_util_.model()), 143 content::NotificationService::NoDetails()); 144 EXPECT_EQ(DataTypeController::MODEL_LOADED, search_engine_dtc_->state()); 145 146 // Wait until WebDB is loaded before we shut it down. 147 base::RunLoop().RunUntilIdle(); 148 } 149 150 TEST_F(SyncSearchEngineDataTypeControllerTest, StartFirstRun) { 151 SetStartExpectations(); 152 PreloadTemplateURLService(); 153 SetActivateExpectations(); 154 change_processor_->set_sync_model_has_user_created_nodes(false); 155 EXPECT_CALL(start_callback_, Run(DataTypeController::OK_FIRST_RUN, _, _)); 156 157 Start(); 158 EXPECT_TRUE(syncable_service_.syncing()); 159 } 160 161 TEST_F(SyncSearchEngineDataTypeControllerTest, StartAssociationFailed) { 162 SetStartExpectations(); 163 PreloadTemplateURLService(); 164 SetStopExpectations(); 165 EXPECT_CALL(start_callback_, 166 Run(DataTypeController::ASSOCIATION_FAILED, _, _)); 167 syncable_service_.set_merge_data_and_start_syncing_error( 168 syncer::SyncError(FROM_HERE, 169 syncer::SyncError::DATATYPE_ERROR, 170 "Error", 171 syncer::SEARCH_ENGINES)); 172 173 Start(); 174 EXPECT_EQ(DataTypeController::DISABLED, search_engine_dtc_->state()); 175 EXPECT_FALSE(syncable_service_.syncing()); 176 search_engine_dtc_->Stop(); 177 EXPECT_EQ(DataTypeController::NOT_RUNNING, search_engine_dtc_->state()); 178 EXPECT_FALSE(syncable_service_.syncing()); 179 } 180 181 TEST_F(SyncSearchEngineDataTypeControllerTest, 182 StartAssociationTriggersUnrecoverableError) { 183 SetStartExpectations(); 184 PreloadTemplateURLService(); 185 EXPECT_CALL(start_callback_, 186 Run(DataTypeController::UNRECOVERABLE_ERROR, _, _)); 187 // Set up association to fail with an unrecoverable error. 188 change_processor_->set_sync_model_has_user_created_nodes_success(false); 189 190 Start(); 191 EXPECT_EQ(DataTypeController::NOT_RUNNING, search_engine_dtc_->state()); 192 EXPECT_FALSE(syncable_service_.syncing()); 193 } 194 195 TEST_F(SyncSearchEngineDataTypeControllerTest, Stop) { 196 SetStartExpectations(); 197 PreloadTemplateURLService(); 198 SetActivateExpectations(); 199 SetStopExpectations(); 200 EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _, _)); 201 202 EXPECT_EQ(DataTypeController::NOT_RUNNING, search_engine_dtc_->state()); 203 EXPECT_FALSE(syncable_service_.syncing()); 204 Start(); 205 EXPECT_EQ(DataTypeController::RUNNING, search_engine_dtc_->state()); 206 EXPECT_TRUE(syncable_service_.syncing()); 207 search_engine_dtc_->Stop(); 208 EXPECT_EQ(DataTypeController::NOT_RUNNING, search_engine_dtc_->state()); 209 EXPECT_FALSE(syncable_service_.syncing()); 210 } 211 212 TEST_F(SyncSearchEngineDataTypeControllerTest, 213 OnSingleDatatypeUnrecoverableError) { 214 SetStartExpectations(); 215 PreloadTemplateURLService(); 216 SetActivateExpectations(); 217 EXPECT_CALL(service_, DisableBrokenDatatype(_, _, _)). 218 WillOnce(InvokeWithoutArgs(search_engine_dtc_.get(), 219 &SearchEngineDataTypeController::Stop)); 220 SetStopExpectations(); 221 222 EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _, _)); 223 Start(); 224 // This should cause search_engine_dtc_->Stop() to be called. 225 search_engine_dtc_->OnSingleDatatypeUnrecoverableError(FROM_HERE, "Test"); 226 base::RunLoop().RunUntilIdle(); 227 EXPECT_EQ(DataTypeController::NOT_RUNNING, search_engine_dtc_->state()); 228 EXPECT_FALSE(syncable_service_.syncing()); 229 } 230 231 } // namespace 232 } // namespace browser_sync 233