profile_sync_service_unittest.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
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/command_line.h"
7#include "base/compiler_specific.h"
8#include "base/memory/scoped_ptr.h"
9#include "base/run_loop.h"
10#include "base/strings/utf_string_conversions.h"
11#include "base/values.h"
12#include "chrome/browser/invalidation/fake_invalidation_service.h"
13#include "chrome/browser/invalidation/invalidation_service_factory.h"
14#include "chrome/browser/signin/fake_profile_oauth2_token_service.h"
15#include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h"
16#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
17#include "chrome/browser/signin/signin_manager_factory.h"
18#include "chrome/browser/sync/glue/sync_backend_host_mock.h"
19#include "chrome/browser/sync/managed_user_signin_manager_wrapper.h"
20#include "chrome/browser/sync/profile_sync_components_factory_mock.h"
21#include "chrome/common/chrome_switches.h"
22#include "chrome/common/pref_names.h"
23#include "chrome/test/base/testing_browser_process.h"
24#include "chrome/test/base/testing_pref_service_syncable.h"
25#include "chrome/test/base/testing_profile.h"
26#include "chrome/test/base/testing_profile_manager.h"
27#include "components/signin/core/browser/signin_manager.h"
28#include "components/sync_driver/data_type_manager_impl.h"
29#include "components/sync_driver/pref_names.h"
30#include "content/public/test/test_browser_thread_bundle.h"
31#include "google_apis/gaia/gaia_constants.h"
32#include "testing/gmock/include/gmock/gmock.h"
33#include "testing/gtest/include/gtest/gtest.h"
34
35namespace browser_sync {
36
37namespace {
38
39ACTION(ReturnNewDataTypeManager) {
40  return new browser_sync::DataTypeManagerImpl(base::Closure(),
41                                               arg0,
42                                               arg1,
43                                               arg2,
44                                               arg3,
45                                               arg4,
46                                               arg5);
47}
48
49using testing::StrictMock;
50using testing::_;
51
52class TestProfileSyncServiceObserver : public ProfileSyncServiceObserver {
53 public:
54  explicit TestProfileSyncServiceObserver(ProfileSyncService* service)
55      : service_(service), first_setup_in_progress_(false) {}
56  virtual void OnStateChanged() OVERRIDE {
57    first_setup_in_progress_ = service_->FirstSetupInProgress();
58  }
59  bool first_setup_in_progress() const { return first_setup_in_progress_; }
60 private:
61  ProfileSyncService* service_;
62  bool first_setup_in_progress_;
63};
64
65// A variant of the SyncBackendHostMock that won't automatically
66// call back when asked to initialized.  Allows us to test things
67// that could happen while backend init is in progress.
68class SyncBackendHostNoReturn : public SyncBackendHostMock {
69  virtual void Initialize(
70      SyncFrontend* frontend,
71      scoped_ptr<base::Thread> sync_thread,
72      const syncer::WeakHandle<syncer::JsEventHandler>& event_handler,
73      const GURL& service_url,
74      const syncer::SyncCredentials& credentials,
75      bool delete_sync_data_folder,
76      scoped_ptr<syncer::SyncManagerFactory> sync_manager_factory,
77      scoped_ptr<syncer::UnrecoverableErrorHandler> unrecoverable_error_handler,
78      syncer::ReportUnrecoverableErrorFunction
79          report_unrecoverable_error_function,
80      syncer::NetworkResources* network_resources) OVERRIDE {}
81};
82
83ACTION(ReturnNewSyncBackendHostMock) {
84  return new browser_sync::SyncBackendHostMock();
85}
86
87ACTION(ReturnNewSyncBackendHostNoReturn) {
88  return new browser_sync::SyncBackendHostNoReturn();
89}
90
91// A test harness that uses a real ProfileSyncService and in most cases a
92// MockSyncBackendHost.
93//
94// This is useful if we want to test the ProfileSyncService and don't care about
95// testing the SyncBackendHost.
96class ProfileSyncServiceTest : public ::testing::Test {
97 protected:
98  ProfileSyncServiceTest()
99      : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
100        profile_manager_(TestingBrowserProcess::GetGlobal()) {}
101  virtual ~ProfileSyncServiceTest() {}
102
103  virtual void SetUp() OVERRIDE {
104    CommandLine::ForCurrentProcess()->AppendSwitchASCII(
105        switches::kSyncDeferredStartupTimeoutSeconds, "0");
106
107#if defined(OS_WIN) || defined(OS_MACOSX) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
108    CommandLine::ForCurrentProcess()->AppendSwitch(
109          switches::kSyncEnableBackupRollback);
110#endif
111
112    CHECK(profile_manager_.SetUp());
113
114    TestingProfile::TestingFactories testing_facotries;
115    testing_facotries.push_back(
116            std::make_pair(ProfileOAuth2TokenServiceFactory::GetInstance(),
117                           BuildAutoIssuingFakeProfileOAuth2TokenService));
118    testing_facotries.push_back(
119            std::make_pair(
120                invalidation::InvalidationServiceFactory::GetInstance(),
121                invalidation::FakeInvalidationService::Build));
122
123    profile_ = profile_manager_.CreateTestingProfile(
124        "sync-service-test", scoped_ptr<PrefServiceSyncable>(),
125        base::UTF8ToUTF16("sync-service-test"), 0, std::string(),
126        testing_facotries);
127  }
128
129  virtual void TearDown() OVERRIDE {
130    // Kill the service before the profile.
131    if (service_)
132      service_->Shutdown();
133
134    service_.reset();
135  }
136
137  void IssueTestTokens() {
138    ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)
139        ->UpdateCredentials("test", "oauth2_login_token");
140  }
141
142  void CreateService(ProfileSyncServiceStartBehavior behavior) {
143    SigninManagerBase* signin =
144        SigninManagerFactory::GetForProfile(profile_);
145    signin->SetAuthenticatedUsername("test");
146    ProfileOAuth2TokenService* oauth2_token_service =
147        ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
148    components_factory_ = new StrictMock<ProfileSyncComponentsFactoryMock>();
149    service_.reset(new ProfileSyncService(
150        components_factory_,
151        profile_,
152        new ManagedUserSigninManagerWrapper(profile_, signin),
153        oauth2_token_service,
154        behavior));
155  }
156
157#if defined(OS_WIN) || defined(OS_MACOSX) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
158  void CreateServiceWithoutSignIn() {
159    CreateService(browser_sync::MANUAL_START);
160    SigninManagerFactory::GetForProfile(profile())->SignOut();
161    service()->SetBackupStartDelayForTest(
162        base::TimeDelta::FromMilliseconds(100));
163  }
164#endif
165
166  void ShutdownAndDeleteService() {
167    if (service_)
168      service_->Shutdown();
169    service_.reset();
170  }
171
172  void Initialize() {
173    service_->Initialize();
174  }
175
176  void ExpectDataTypeManagerCreation(int times) {
177    EXPECT_CALL(*components_factory_, CreateDataTypeManager(_, _, _, _, _, _))
178        .Times(times)
179        .WillRepeatedly(ReturnNewDataTypeManager());
180  }
181
182  void ExpectSyncBackendHostCreation(int times) {
183    EXPECT_CALL(*components_factory_, CreateSyncBackendHost(_, _, _, _, _))
184        .Times(times)
185        .WillRepeatedly(ReturnNewSyncBackendHostMock());
186  }
187
188  void PrepareDelayedInitSyncBackendHost() {
189    EXPECT_CALL(*components_factory_, CreateSyncBackendHost(_, _, _, _, _)).
190        WillOnce(ReturnNewSyncBackendHostNoReturn());
191  }
192
193  TestingProfile* profile() {
194    return profile_;
195  }
196
197  ProfileSyncService* service() {
198    return service_.get();
199  }
200
201  ProfileSyncComponentsFactoryMock* components_factory() {
202    return components_factory_;
203  }
204
205 private:
206  content::TestBrowserThreadBundle thread_bundle_;
207  TestingProfileManager profile_manager_;
208  TestingProfile* profile_;
209  scoped_ptr<ProfileSyncService> service_;
210
211  // Pointer to the components factory.  Not owned.  May be null.
212  ProfileSyncComponentsFactoryMock* components_factory_;
213};
214
215// Verify that the server URLs are sane.
216TEST_F(ProfileSyncServiceTest, InitialState) {
217  CreateService(browser_sync::AUTO_START);
218  Initialize();
219  const std::string& url = service()->sync_service_url().spec();
220  EXPECT_TRUE(url == ProfileSyncService::kSyncServerUrl ||
221              url == ProfileSyncService::kDevServerUrl);
222}
223
224// Verify a successful initialization.
225TEST_F(ProfileSyncServiceTest, SuccessfulInitialization) {
226  profile()->GetTestingPrefService()->SetManagedPref(
227      sync_driver::prefs::kSyncManaged, base::Value::CreateBooleanValue(false));
228  IssueTestTokens();
229  CreateService(browser_sync::AUTO_START);
230  ExpectDataTypeManagerCreation(1);
231  ExpectSyncBackendHostCreation(1);
232  Initialize();
233  EXPECT_FALSE(service()->IsManaged());
234  EXPECT_TRUE(service()->sync_initialized());
235  EXPECT_EQ(ProfileSyncService::SYNC, service()->backend_mode());
236}
237
238
239// Verify that the SetSetupInProgress function call updates state
240// and notifies observers.
241TEST_F(ProfileSyncServiceTest, SetupInProgress) {
242  CreateService(browser_sync::AUTO_START);
243  Initialize();
244
245  TestProfileSyncServiceObserver observer(service());
246  service()->AddObserver(&observer);
247
248  service()->SetSetupInProgress(true);
249  EXPECT_TRUE(observer.first_setup_in_progress());
250  service()->SetSetupInProgress(false);
251  EXPECT_FALSE(observer.first_setup_in_progress());
252
253  service()->RemoveObserver(&observer);
254}
255
256// Verify that disable by enterprise policy works.
257TEST_F(ProfileSyncServiceTest, DisabledByPolicyBeforeInit) {
258  profile()->GetTestingPrefService()->SetManagedPref(
259      sync_driver::prefs::kSyncManaged, base::Value::CreateBooleanValue(true));
260  IssueTestTokens();
261  CreateService(browser_sync::AUTO_START);
262  Initialize();
263  EXPECT_TRUE(service()->IsManaged());
264  EXPECT_FALSE(service()->sync_initialized());
265}
266
267// Verify that disable by enterprise policy works even after the backend has
268// been initialized.
269TEST_F(ProfileSyncServiceTest, DisabledByPolicyAfterInit) {
270  IssueTestTokens();
271  CreateService(browser_sync::AUTO_START);
272  ExpectDataTypeManagerCreation(1);
273  ExpectSyncBackendHostCreation(1);
274  Initialize();
275
276  EXPECT_FALSE(service()->IsManaged());
277  EXPECT_TRUE(service()->sync_initialized());
278
279  profile()->GetTestingPrefService()->SetManagedPref(
280      sync_driver::prefs::kSyncManaged, base::Value::CreateBooleanValue(true));
281
282  EXPECT_TRUE(service()->IsManaged());
283  EXPECT_FALSE(service()->sync_initialized());
284}
285
286// Exercies the ProfileSyncService's code paths related to getting shut down
287// before the backend initialize call returns.
288TEST_F(ProfileSyncServiceTest, AbortedByShutdown) {
289  CreateService(browser_sync::AUTO_START);
290  PrepareDelayedInitSyncBackendHost();
291
292  IssueTestTokens();
293  Initialize();
294  EXPECT_FALSE(service()->sync_initialized());
295
296  ShutdownAndDeleteService();
297}
298
299// Test StopAndSuppress() before we've initialized the backend.
300TEST_F(ProfileSyncServiceTest, EarlyStopAndSuppress) {
301  CreateService(browser_sync::AUTO_START);
302  IssueTestTokens();
303
304  service()->StopAndSuppress();
305  EXPECT_TRUE(profile()->GetPrefs()->GetBoolean(
306      sync_driver::prefs::kSyncSuppressStart));
307
308  // Because of supression, this should fail.
309  Initialize();
310  EXPECT_FALSE(service()->sync_initialized());
311
312  // Remove suppression.  This should be enough to allow init to happen.
313  ExpectDataTypeManagerCreation(1);
314  ExpectSyncBackendHostCreation(1);
315  service()->UnsuppressAndStart();
316  EXPECT_TRUE(service()->sync_initialized());
317  EXPECT_FALSE(profile()->GetPrefs()->GetBoolean(
318      sync_driver::prefs::kSyncSuppressStart));
319}
320
321// Test StopAndSuppress() after we've initialized the backend.
322TEST_F(ProfileSyncServiceTest, DisableAndEnableSyncTemporarily) {
323  CreateService(browser_sync::AUTO_START);
324  IssueTestTokens();
325  ExpectDataTypeManagerCreation(1);
326  ExpectSyncBackendHostCreation(1);
327  Initialize();
328
329  EXPECT_TRUE(service()->sync_initialized());
330  EXPECT_FALSE(profile()->GetPrefs()->GetBoolean(
331      sync_driver::prefs::kSyncSuppressStart));
332
333  testing::Mock::VerifyAndClearExpectations(components_factory());
334
335  service()->StopAndSuppress();
336  EXPECT_FALSE(service()->sync_initialized());
337  EXPECT_TRUE(profile()->GetPrefs()->GetBoolean(
338      sync_driver::prefs::kSyncSuppressStart));
339
340  ExpectDataTypeManagerCreation(1);
341  ExpectSyncBackendHostCreation(1);
342
343  service()->UnsuppressAndStart();
344  EXPECT_TRUE(service()->sync_initialized());
345  EXPECT_FALSE(profile()->GetPrefs()->GetBoolean(
346      sync_driver::prefs::kSyncSuppressStart));
347}
348
349// Certain ProfileSyncService tests don't apply to Chrome OS, for example
350// things that deal with concepts like "signing out" and policy.
351#if defined(OS_WIN) || defined(OS_MACOSX) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
352TEST_F(ProfileSyncServiceTest, EnableSyncAndSignOutDesktop) {
353  CreateService(browser_sync::AUTO_START);
354  ExpectDataTypeManagerCreation(2);
355  ExpectSyncBackendHostCreation(2);
356  IssueTestTokens();
357  Initialize();
358
359  EXPECT_TRUE(service()->sync_initialized());
360  EXPECT_FALSE(profile()->GetPrefs()->GetBoolean(
361      sync_driver::prefs::kSyncSuppressStart));
362  EXPECT_EQ(ProfileSyncService::SYNC, service()->backend_mode());
363
364  SigninManagerFactory::GetForProfile(profile())->SignOut();
365  EXPECT_TRUE(service()->sync_initialized());
366  EXPECT_EQ(ProfileSyncService::BACKUP, service()->backend_mode());
367}
368#elif !defined (OS_CHROMEOS)
369TEST_F(ProfileSyncServiceTest, EnableSyncAndSignOut) {
370  CreateService(browser_sync::AUTO_START);
371  ExpectDataTypeManagerCreation(1);
372  ExpectSyncBackendHostCreation(1);
373  IssueTestTokens();
374  Initialize();
375
376  EXPECT_TRUE(service()->sync_initialized());
377  EXPECT_FALSE(profile()->GetPrefs()->GetBoolean(
378      sync_driver::prefs::kSyncSuppressStart));
379
380  SigninManagerFactory::GetForProfile(profile())->SignOut();
381  EXPECT_FALSE(service()->sync_initialized());
382}
383#endif  // !defined(OS_CHROMEOS)
384
385TEST_F(ProfileSyncServiceTest, GetSyncTokenStatus) {
386  CreateService(browser_sync::AUTO_START);
387  IssueTestTokens();
388  ExpectDataTypeManagerCreation(1);
389  ExpectSyncBackendHostCreation(1);
390  Initialize();
391
392  // Initial status.
393  ProfileSyncService::SyncTokenStatus token_status =
394      service()->GetSyncTokenStatus();
395  EXPECT_EQ(syncer::CONNECTION_NOT_ATTEMPTED, token_status.connection_status);
396  EXPECT_TRUE(token_status.connection_status_update_time.is_null());
397  EXPECT_TRUE(token_status.token_request_time.is_null());
398  EXPECT_TRUE(token_status.token_receive_time.is_null());
399
400  // Simulate an auth error.
401  service()->OnConnectionStatusChange(syncer::CONNECTION_AUTH_ERROR);
402
403  // The token request will take the form of a posted task.  Run it.
404  base::RunLoop loop;
405  loop.RunUntilIdle();
406
407  token_status = service()->GetSyncTokenStatus();
408  EXPECT_EQ(syncer::CONNECTION_AUTH_ERROR, token_status.connection_status);
409  EXPECT_FALSE(token_status.connection_status_update_time.is_null());
410  EXPECT_FALSE(token_status.token_request_time.is_null());
411  EXPECT_FALSE(token_status.token_receive_time.is_null());
412  EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
413            token_status.last_get_token_error);
414  EXPECT_TRUE(token_status.next_token_request_time.is_null());
415
416  // Simulate successful connection.
417  service()->OnConnectionStatusChange(syncer::CONNECTION_OK);
418  token_status = service()->GetSyncTokenStatus();
419  EXPECT_EQ(syncer::CONNECTION_OK, token_status.connection_status);
420}
421
422#if defined(OS_WIN) || defined(OS_MACOSX) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
423void QuitLoop() {
424  base::MessageLoop::current()->Quit();
425}
426
427TEST_F(ProfileSyncServiceTest, StartBackup) {
428  CreateServiceWithoutSignIn();
429  ExpectDataTypeManagerCreation(1);
430  ExpectSyncBackendHostCreation(1);
431  Initialize();
432  EXPECT_EQ(ProfileSyncService::IDLE, service()->backend_mode());
433  base::MessageLoop::current()->PostDelayedTask(
434      FROM_HERE,  base::Bind(&QuitLoop),
435      base::TimeDelta::FromMilliseconds(100));
436  base::MessageLoop::current()->Run();
437  EXPECT_EQ(ProfileSyncService::BACKUP, service()->backend_mode());
438}
439
440TEST_F(ProfileSyncServiceTest, BackupAfterSyncDisabled) {
441  CreateService(browser_sync::MANUAL_START);
442  service()->SetSyncSetupCompleted();
443  ExpectDataTypeManagerCreation(2);
444  ExpectSyncBackendHostCreation(2);
445  IssueTestTokens();
446  Initialize();
447  base::MessageLoop::current()->PostTask(FROM_HERE,  base::Bind(&QuitLoop));
448  EXPECT_TRUE(service()->sync_initialized());
449  EXPECT_EQ(ProfileSyncService::SYNC, service()->backend_mode());
450
451  syncer::SyncProtocolError client_cmd;
452  client_cmd.action = syncer::DISABLE_SYNC_ON_CLIENT;
453  service()->OnActionableError(client_cmd);
454  EXPECT_EQ(ProfileSyncService::BACKUP, service()->backend_mode());
455}
456
457TEST_F(ProfileSyncServiceTest, RollbackThenBackup) {
458  CreateService(browser_sync::MANUAL_START);
459  service()->SetSyncSetupCompleted();
460  ExpectDataTypeManagerCreation(3);
461  ExpectSyncBackendHostCreation(3);
462  IssueTestTokens();
463  Initialize();
464  base::MessageLoop::current()->PostTask(FROM_HERE,  base::Bind(&QuitLoop));
465  EXPECT_TRUE(service()->sync_initialized());
466  EXPECT_EQ(ProfileSyncService::SYNC, service()->backend_mode());
467
468  syncer::SyncProtocolError client_cmd;
469  client_cmd.action = syncer::DISABLE_SYNC_AND_ROLLBACK;
470  service()->OnActionableError(client_cmd);
471  EXPECT_TRUE(service()->sync_initialized());
472  EXPECT_EQ(ProfileSyncService::ROLLBACK, service()->backend_mode());
473
474  client_cmd.action = syncer::ROLLBACK_DONE;
475  service()->OnActionableError(client_cmd);
476  EXPECT_TRUE(service()->sync_initialized());
477  EXPECT_EQ(ProfileSyncService::BACKUP, service()->backend_mode());
478}
479#endif
480
481}  // namespace
482}  // namespace browser_sync
483