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/basictypes.h"
6 #include "base/compiler_specific.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/run_loop.h"
9 #include "base/values.h"
10 #include "chrome/browser/invalidation/invalidation_service_factory.h"
11 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
12 #include "chrome/browser/signin/signin_manager.h"
13 #include "chrome/browser/signin/signin_manager_factory.h"
14 #include "chrome/browser/sync/fake_oauth2_token_service.h"
15 #include "chrome/browser/sync/glue/data_type_manager_impl.h"
16 #include "chrome/browser/sync/glue/sync_backend_host_mock.h"
17 #include "chrome/browser/sync/profile_sync_components_factory_mock.h"
18 #include "chrome/common/pref_names.h"
19 #include "chrome/test/base/testing_pref_service_syncable.h"
20 #include "chrome/test/base/testing_profile.h"
21 #include "content/public/test/test_browser_thread_bundle.h"
22 #include "google_apis/gaia/gaia_constants.h"
23 #include "testing/gmock/include/gmock/gmock.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25
26 namespace browser_sync {
27
28 namespace {
29
ACTION(ReturnNewDataTypeManager)30 ACTION(ReturnNewDataTypeManager) {
31 return new browser_sync::DataTypeManagerImpl(arg0,
32 arg1,
33 arg2,
34 arg3,
35 arg4,
36 arg5);
37 }
38
39 using testing::_;
40 using testing::StrictMock;
41
42 class TestProfileSyncServiceObserver : public ProfileSyncServiceObserver {
43 public:
TestProfileSyncServiceObserver(ProfileSyncService * service)44 explicit TestProfileSyncServiceObserver(ProfileSyncService* service)
45 : service_(service), first_setup_in_progress_(false) {}
OnStateChanged()46 virtual void OnStateChanged() OVERRIDE {
47 first_setup_in_progress_ = service_->FirstSetupInProgress();
48 }
first_setup_in_progress() const49 bool first_setup_in_progress() const { return first_setup_in_progress_; }
50 private:
51 ProfileSyncService* service_;
52 bool first_setup_in_progress_;
53 };
54
55 // A variant of the SyncBackendHostMock that won't automatically
56 // call back when asked to initialized. Allows us to test things
57 // that could happen while backend init is in progress.
58 class SyncBackendHostNoReturn : public SyncBackendHostMock {
Initialize(SyncFrontend * frontend,scoped_ptr<base::Thread> sync_thread,const syncer::WeakHandle<syncer::JsEventHandler> & event_handler,const GURL & service_url,const syncer::SyncCredentials & credentials,bool delete_sync_data_folder,scoped_ptr<syncer::SyncManagerFactory> sync_manager_factory,scoped_ptr<syncer::UnrecoverableErrorHandler> unrecoverable_error_handler,syncer::ReportUnrecoverableErrorFunction report_unrecoverable_error_function,syncer::NetworkResources * network_resources)59 virtual void Initialize(
60 SyncFrontend* frontend,
61 scoped_ptr<base::Thread> sync_thread,
62 const syncer::WeakHandle<syncer::JsEventHandler>& event_handler,
63 const GURL& service_url,
64 const syncer::SyncCredentials& credentials,
65 bool delete_sync_data_folder,
66 scoped_ptr<syncer::SyncManagerFactory> sync_manager_factory,
67 scoped_ptr<syncer::UnrecoverableErrorHandler> unrecoverable_error_handler,
68 syncer::ReportUnrecoverableErrorFunction
69 report_unrecoverable_error_function,
70 syncer::NetworkResources* network_resources) OVERRIDE {}
71 };
72
ACTION(ReturnNewSyncBackendHostMock)73 ACTION(ReturnNewSyncBackendHostMock) {
74 return new browser_sync::SyncBackendHostMock();
75 }
76
ACTION(ReturnNewSyncBackendHostNoReturn)77 ACTION(ReturnNewSyncBackendHostNoReturn) {
78 return new browser_sync::SyncBackendHostNoReturn();
79 }
80
81 // A test harness that uses a real ProfileSyncService and in most cases a
82 // MockSyncBackendHost.
83 //
84 // This is useful if we want to test the ProfileSyncService and don't care about
85 // testing the SyncBackendHost.
86 class ProfileSyncServiceTest : public ::testing::Test {
87 protected:
ProfileSyncServiceTest()88 ProfileSyncServiceTest()
89 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {}
~ProfileSyncServiceTest()90 virtual ~ProfileSyncServiceTest() {}
91
SetUp()92 virtual void SetUp() OVERRIDE {
93 TestingProfile::Builder builder;
94
95 builder.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(),
96 FakeOAuth2TokenService::BuildTokenService);
97 invalidation::InvalidationServiceFactory::GetInstance()->
98 SetBuildOnlyFakeInvalidatorsForTest(true);
99
100 profile_ = builder.Build().Pass();
101 }
102
TearDown()103 virtual void TearDown() OVERRIDE {
104 // Kill the service before the profile.
105 if (service_)
106 service_->Shutdown();
107
108 service_.reset();
109 profile_.reset();
110 }
111
IssueTestTokens()112 void IssueTestTokens() {
113 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_.get())
114 ->UpdateCredentials("test", "oauth2_login_token");
115 }
116
CreateService(ProfileSyncService::StartBehavior behavior)117 void CreateService(ProfileSyncService::StartBehavior behavior) {
118 SigninManagerBase* signin =
119 SigninManagerFactory::GetForProfile(profile_.get());
120 signin->SetAuthenticatedUsername("test");
121 ProfileOAuth2TokenService* oauth2_token_service =
122 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_.get());
123 components_factory_ = new StrictMock<ProfileSyncComponentsFactoryMock>();
124 service_.reset(new ProfileSyncService(
125 components_factory_,
126 profile_.get(),
127 signin,
128 oauth2_token_service,
129 behavior));
130 }
131
ShutdownAndDeleteService()132 void ShutdownAndDeleteService() {
133 if (service_)
134 service_->Shutdown();
135 service_.reset();
136 }
137
Initialize()138 void Initialize() {
139 service_->Initialize();
140 }
141
ExpectDataTypeManagerCreation()142 void ExpectDataTypeManagerCreation() {
143 EXPECT_CALL(*components_factory_, CreateDataTypeManager(_, _, _, _, _, _)).
144 WillOnce(ReturnNewDataTypeManager());
145 }
146
ExpectSyncBackendHostCreation()147 void ExpectSyncBackendHostCreation() {
148 EXPECT_CALL(*components_factory_, CreateSyncBackendHost(_, _, _)).
149 WillOnce(ReturnNewSyncBackendHostMock());
150 }
151
PrepareDelayedInitSyncBackendHost()152 void PrepareDelayedInitSyncBackendHost() {
153 EXPECT_CALL(*components_factory_, CreateSyncBackendHost(_, _, _)).
154 WillOnce(ReturnNewSyncBackendHostNoReturn());
155 }
156
profile()157 TestingProfile* profile() {
158 return profile_.get();
159 }
160
service()161 ProfileSyncService* service() {
162 return service_.get();
163 }
164
components_factory()165 ProfileSyncComponentsFactoryMock* components_factory() {
166 return components_factory_;
167 }
168
169 private:
170 scoped_ptr<TestingProfile> profile_;
171 scoped_ptr<ProfileSyncService> service_;
172
173 // Pointer to the components factory. Not owned. May be null.
174 ProfileSyncComponentsFactoryMock* components_factory_;
175
176 content::TestBrowserThreadBundle thread_bundle_;
177 };
178
179 // Verify that the server URLs are sane.
TEST_F(ProfileSyncServiceTest,InitialState)180 TEST_F(ProfileSyncServiceTest, InitialState) {
181 CreateService(ProfileSyncService::AUTO_START);
182 Initialize();
183 const std::string& url = service()->sync_service_url().spec();
184 EXPECT_TRUE(url == ProfileSyncService::kSyncServerUrl ||
185 url == ProfileSyncService::kDevServerUrl);
186 }
187
188 // Verify a successful initialization.
TEST_F(ProfileSyncServiceTest,SuccessfulInitialization)189 TEST_F(ProfileSyncServiceTest, SuccessfulInitialization) {
190 profile()->GetTestingPrefService()->SetManagedPref(
191 prefs::kSyncManaged,
192 Value::CreateBooleanValue(false));
193 IssueTestTokens();
194 CreateService(ProfileSyncService::AUTO_START);
195 ExpectDataTypeManagerCreation();
196 ExpectSyncBackendHostCreation();
197 Initialize();
198 EXPECT_FALSE(service()->IsManaged());
199 EXPECT_TRUE(service()->sync_initialized());
200 }
201
202
203 // Verify that the SetSetupInProgress function call updates state
204 // and notifies observers.
TEST_F(ProfileSyncServiceTest,SetupInProgress)205 TEST_F(ProfileSyncServiceTest, SetupInProgress) {
206 CreateService(ProfileSyncService::MANUAL_START);
207 Initialize();
208
209 TestProfileSyncServiceObserver observer(service());
210 service()->AddObserver(&observer);
211
212 service()->SetSetupInProgress(true);
213 EXPECT_TRUE(observer.first_setup_in_progress());
214 service()->SetSetupInProgress(false);
215 EXPECT_FALSE(observer.first_setup_in_progress());
216
217 service()->RemoveObserver(&observer);
218 }
219
220 // Verify that disable by enterprise policy works.
TEST_F(ProfileSyncServiceTest,DisabledByPolicyBeforeInit)221 TEST_F(ProfileSyncServiceTest, DisabledByPolicyBeforeInit) {
222 profile()->GetTestingPrefService()->SetManagedPref(
223 prefs::kSyncManaged,
224 Value::CreateBooleanValue(true));
225 IssueTestTokens();
226 CreateService(ProfileSyncService::AUTO_START);
227 Initialize();
228 EXPECT_TRUE(service()->IsManaged());
229 EXPECT_FALSE(service()->sync_initialized());
230 }
231
232 // Verify that disable by enterprise policy works even after the backend has
233 // been initialized.
TEST_F(ProfileSyncServiceTest,DisabledByPolicyAfterInit)234 TEST_F(ProfileSyncServiceTest, DisabledByPolicyAfterInit) {
235 IssueTestTokens();
236 CreateService(ProfileSyncService::AUTO_START);
237 ExpectDataTypeManagerCreation();
238 ExpectSyncBackendHostCreation();
239 Initialize();
240
241 EXPECT_FALSE(service()->IsManaged());
242 EXPECT_TRUE(service()->sync_initialized());
243
244 profile()->GetTestingPrefService()->SetManagedPref(
245 prefs::kSyncManaged,
246 Value::CreateBooleanValue(true));
247
248 EXPECT_TRUE(service()->IsManaged());
249 EXPECT_FALSE(service()->sync_initialized());
250 }
251
252 // Exercies the ProfileSyncService's code paths related to getting shut down
253 // before the backend initialize call returns.
TEST_F(ProfileSyncServiceTest,AbortedByShutdown)254 TEST_F(ProfileSyncServiceTest, AbortedByShutdown) {
255 CreateService(ProfileSyncService::AUTO_START);
256 PrepareDelayedInitSyncBackendHost();
257
258 IssueTestTokens();
259 Initialize();
260 EXPECT_FALSE(service()->sync_initialized());
261
262 ShutdownAndDeleteService();
263 }
264
265 // Test StopAndSuppress() before we've initialized the backend.
TEST_F(ProfileSyncServiceTest,EarlyStopAndSuppress)266 TEST_F(ProfileSyncServiceTest, EarlyStopAndSuppress) {
267 CreateService(ProfileSyncService::AUTO_START);
268 IssueTestTokens();
269
270 service()->StopAndSuppress();
271 EXPECT_TRUE(profile()->GetPrefs()->GetBoolean(prefs::kSyncSuppressStart));
272
273 // Because of supression, this should fail.
274 Initialize();
275 EXPECT_FALSE(service()->sync_initialized());
276
277 // Remove suppression. This should be enough to allow init to happen.
278 ExpectDataTypeManagerCreation();
279 ExpectSyncBackendHostCreation();
280 service()->UnsuppressAndStart();
281 EXPECT_TRUE(service()->sync_initialized());
282 EXPECT_FALSE(
283 profile()->GetPrefs()->GetBoolean(prefs::kSyncSuppressStart));
284 }
285
286 // Test StopAndSuppress() after we've initialized the backend.
TEST_F(ProfileSyncServiceTest,DisableAndEnableSyncTemporarily)287 TEST_F(ProfileSyncServiceTest, DisableAndEnableSyncTemporarily) {
288 CreateService(ProfileSyncService::AUTO_START);
289 IssueTestTokens();
290 ExpectDataTypeManagerCreation();
291 ExpectSyncBackendHostCreation();
292 Initialize();
293
294 EXPECT_TRUE(service()->sync_initialized());
295 EXPECT_FALSE(profile()->GetPrefs()->GetBoolean(prefs::kSyncSuppressStart));
296
297 testing::Mock::VerifyAndClearExpectations(components_factory());
298
299 service()->StopAndSuppress();
300 EXPECT_FALSE(service()->sync_initialized());
301 EXPECT_TRUE(profile()->GetPrefs()->GetBoolean(prefs::kSyncSuppressStart));
302
303 ExpectDataTypeManagerCreation();
304 ExpectSyncBackendHostCreation();
305
306 service()->UnsuppressAndStart();
307 EXPECT_TRUE(service()->sync_initialized());
308 EXPECT_FALSE(
309 profile()->GetPrefs()->GetBoolean(prefs::kSyncSuppressStart));
310 }
311
312 // Certain ProfileSyncService tests don't apply to Chrome OS, for example
313 // things that deal with concepts like "signing out" and policy.
314 #if !defined (OS_CHROMEOS)
315
TEST_F(ProfileSyncServiceTest,EnableSyncAndSignOut)316 TEST_F(ProfileSyncServiceTest, EnableSyncAndSignOut) {
317 CreateService(ProfileSyncService::AUTO_START);
318 ExpectDataTypeManagerCreation();
319 ExpectSyncBackendHostCreation();
320 IssueTestTokens();
321 Initialize();
322
323 EXPECT_TRUE(service()->sync_initialized());
324 EXPECT_FALSE(profile()->GetPrefs()->GetBoolean(prefs::kSyncSuppressStart));
325
326 SigninManagerFactory::GetForProfile(profile())->SignOut();
327 EXPECT_FALSE(service()->sync_initialized());
328 }
329
330 #endif // !defined(OS_CHROMEOS)
331
TEST_F(ProfileSyncServiceTest,GetSyncTokenStatus)332 TEST_F(ProfileSyncServiceTest, GetSyncTokenStatus) {
333 CreateService(ProfileSyncService::AUTO_START);
334 IssueTestTokens();
335 ExpectDataTypeManagerCreation();
336 ExpectSyncBackendHostCreation();
337 Initialize();
338
339 // Initial status.
340 ProfileSyncService::SyncTokenStatus token_status =
341 service()->GetSyncTokenStatus();
342 EXPECT_EQ(syncer::CONNECTION_NOT_ATTEMPTED, token_status.connection_status);
343 EXPECT_TRUE(token_status.connection_status_update_time.is_null());
344 EXPECT_TRUE(token_status.token_request_time.is_null());
345 EXPECT_TRUE(token_status.token_receive_time.is_null());
346
347 // Simulate an auth error.
348 service()->OnConnectionStatusChange(syncer::CONNECTION_AUTH_ERROR);
349
350 // The token request will take the form of a posted task. Run it.
351 base::RunLoop loop;
352 loop.RunUntilIdle();
353
354 token_status = service()->GetSyncTokenStatus();
355 EXPECT_EQ(syncer::CONNECTION_AUTH_ERROR, token_status.connection_status);
356 EXPECT_FALSE(token_status.connection_status_update_time.is_null());
357 EXPECT_FALSE(token_status.token_request_time.is_null());
358 EXPECT_FALSE(token_status.token_receive_time.is_null());
359 EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
360 token_status.last_get_token_error);
361 EXPECT_TRUE(token_status.next_token_request_time.is_null());
362
363 // Simulate successful connection.
364 service()->OnConnectionStatusChange(syncer::CONNECTION_OK);
365 token_status = service()->GetSyncTokenStatus();
366 EXPECT_EQ(syncer::CONNECTION_OK, token_status.connection_status);
367 }
368
369 } // namespace
370 } // namespace browser_sync
371